Revision: 19110
Author:   [email protected]
Date:     Wed Feb  5 15:52:31 2014 UTC
Log:      inline api getters in crankshaft

[email protected]

BUG=

Review URL: https://codereview.chromium.org/146023004
http://code.google.com/p/v8/source/detail?r=19110

Modified:
 /branches/bleeding_edge/src/hydrogen.cc
 /branches/bleeding_edge/src/hydrogen.h
 /branches/bleeding_edge/test/cctest/test-api.cc

=======================================
--- /branches/bleeding_edge/src/hydrogen.cc     Wed Feb  5 15:44:20 2014 UTC
+++ /branches/bleeding_edge/src/hydrogen.cc     Wed Feb  5 15:52:31 2014 UTC
@@ -5361,7 +5361,8 @@
   if (info->has_holder()) return false;

   if (lookup_.IsPropertyCallbacks()) {
-    return accessor_.is_identical_to(info->accessor_);
+    return accessor_.is_identical_to(info->accessor_) &&
+        api_holder_.is_identical_to(info->api_holder_);
   }

   if (lookup_.IsConstant()) {
@@ -5407,9 +5408,20 @@
         : Handle<AccessorPair>::cast(callback)->setter();
     if (!raw_accessor->IsJSFunction()) return false;
     Handle<JSFunction> accessor = handle(JSFunction::cast(raw_accessor));
-    CallOptimization call_optimization(accessor);
- // TODO(dcarney): temporary hack unless crankshaft can handle api calls.
-    if (call_optimization.is_simple_api_call()) return false;
+    if (accessor->shared()->IsApiFunction()) {
+      CallOptimization call_optimization(accessor);
+      if (!call_optimization.is_simple_api_call()) return false;
+      CallOptimization::HolderLookup holder_lookup;
+      api_holder_ = call_optimization.LookupHolderOfExpectedType(
+          map, &holder_lookup);
+      switch (holder_lookup) {
+        case CallOptimization::kHolderNotFound:
+          return false;
+        case CallOptimization::kHolderIsReceiver:
+        case CallOptimization::kHolderFound:
+          break;
+      }
+    }
     accessor_ = accessor;
   } else if (lookup_.IsConstant()) {
     constant_ = handle(lookup_.GetConstantFromMap(*map), isolate());
@@ -5572,7 +5584,7 @@
       return New<HCallFunction>(function, argument_count, WRAP_AND_CALL);
     } else if (FLAG_inline_accessors && can_inline_accessor) {
       bool success = info->IsLoad()
-          ? TryInlineGetter(info->accessor(), ast_id, return_id)
+ ? TryInlineGetter(info->accessor(), info->map(), ast_id, return_id)
           : TryInlineSetter(info->accessor(), ast_id, return_id, value);
       if (success) return NULL;
     }
@@ -7394,8 +7406,10 @@


 bool HOptimizedGraphBuilder::TryInlineGetter(Handle<JSFunction> getter,
+                                             Handle<Map> receiver_map,
                                              BailoutId ast_id,
                                              BailoutId return_id) {
+  if (TryInlineApiGetter(getter, receiver_map, ast_id)) return true;
   return TryInline(getter,
                    0,
                    NULL,
@@ -7678,54 +7692,102 @@

 bool HOptimizedGraphBuilder::TryInlineApiFunctionCall(Call* expr,
                                                       HValue* receiver) {
-  return TryInlineApiCall(
-      expr, receiver, Handle<Map>::null(), true);
+  Handle<JSFunction> function = expr->target();
+  int argc = expr->arguments()->length();
+  SmallMapList receiver_maps;
+  return TryInlineApiCall(function,
+                          receiver,
+                          &receiver_maps,
+                          argc,
+                          expr->id(),
+                          kCallApiFunction);
 }


-bool HOptimizedGraphBuilder::TryInlineApiMethodCall(Call* expr,
-                                                    HValue* receiver,
- Handle<Map> receiver_map) {
-  return TryInlineApiCall(expr, receiver, receiver_map, false);
+bool HOptimizedGraphBuilder::TryInlineApiMethodCall(
+    Call* expr,
+    HValue* receiver,
+    SmallMapList* receiver_maps) {
+  Handle<JSFunction> function = expr->target();
+  int argc = expr->arguments()->length();
+  return TryInlineApiCall(function,
+                          receiver,
+                          receiver_maps,
+                          argc,
+                          expr->id(),
+                          kCallApiMethod);
 }

-bool HOptimizedGraphBuilder::TryInlineApiCall(Call* expr,
-                                              HValue* receiver,
-                                              Handle<Map> receiver_map,
-                                              bool is_function_call) {
-  if (!expr->IsMonomorphic()) return false;
-  CallOptimization optimization(expr->target());
+
+bool HOptimizedGraphBuilder::TryInlineApiGetter(Handle<JSFunction> function,
+                                                Handle<Map> receiver_map,
+                                                BailoutId ast_id) {
+  SmallMapList receiver_maps(1, zone());
+  receiver_maps.Add(receiver_map, zone());
+  return TryInlineApiCall(function,
+                          NULL,  // Receiver is on expression stack.
+                          &receiver_maps,
+                          0,
+                          ast_id,
+                          kCallApiGetter);
+}
+
+
+bool HOptimizedGraphBuilder::TryInlineApiCall(Handle<JSFunction> function,
+                                               HValue* receiver,
+                                               SmallMapList* receiver_maps,
+                                               int argc,
+                                               BailoutId ast_id,
+                                               ApiCallType call_type) {
+  CallOptimization optimization(function);
   if (!optimization.is_simple_api_call()) return false;
   Handle<Map> holder_map;
-  if (is_function_call) {
+  if (call_type == kCallApiFunction) {
     // Cannot embed a direct reference to the global proxy map
     // as it maybe dropped on deserialization.
     CHECK(!Serializer::enabled());
-    receiver_map = Handle<Map>(
- expr->target()->context()->global_object()->global_receiver()->map());
+    ASSERT_EQ(0, receiver_maps->length());
+    receiver_maps->Add(handle(
+        function->context()->global_object()->global_receiver()->map()),
+        zone());
   }
   CallOptimization::HolderLookup holder_lookup =
       CallOptimization::kHolderNotFound;
   Handle<JSObject> api_holder = optimization.LookupHolderOfExpectedType(
-      receiver_map, &holder_lookup);
+      receiver_maps->first(), &holder_lookup);
   if (holder_lookup == CallOptimization::kHolderNotFound) return false;

   if (FLAG_trace_inlining) {
     PrintF("Inlining api function ");
-    expr->target()->ShortPrint();
+    function->ShortPrint();
     PrintF("\n");
   }

-  const int argc = expr->arguments()->length();
-  // Includes receiver.
-  PushArgumentsFromEnvironment(argc + 1);
-
-  // Need to ensure the chain between receiver and api_holder is intact
-  AddCheckMap(receiver, receiver_map);
-  if (holder_lookup == CallOptimization::kHolderFound) {
-    AddCheckPrototypeMaps(api_holder, receiver_map);
-  } else {
-    ASSERT_EQ(holder_lookup, CallOptimization::kHolderIsReceiver);
+  bool drop_extra = false;
+  switch (call_type) {
+    case kCallApiFunction:
+    case kCallApiMethod:
+      // Need to check that none of the receiver maps could have changed.
+      Add<HCheckMaps>(receiver, receiver_maps);
+ // Need to ensure the chain between receiver and api_holder is intact.
+      if (holder_lookup == CallOptimization::kHolderFound) {
+        AddCheckPrototypeMaps(api_holder, receiver_maps->first());
+      } else {
+        ASSERT_EQ(holder_lookup, CallOptimization::kHolderIsReceiver);
+      }
+      // Includes receiver.
+      PushArgumentsFromEnvironment(argc + 1);
+      // Drop function after call.
+      drop_extra = true;
+      break;
+    case kCallApiGetter:
+      // Receiver and prototype chain cannot have changed.
+      ASSERT_EQ(0, argc);
+      ASSERT_EQ(NULL, receiver);
+      // Receiver is on expression stack.
+      receiver = Pop();
+      Add<HPushArgument>(receiver);
+      break;
   }

   HValue* holder = NULL;
@@ -7751,8 +7813,7 @@
   HValue* api_function_address = Add<HConstant>(ExternalReference(ref));

   HValue* op_vals[] = {
-    // callee
-    Add<HConstant>(expr->target()),
+    Add<HConstant>(function),
     call_data,
     holder,
     api_function_address,
@@ -7773,8 +7834,8 @@
       code_value, argc + 1, descriptor,
       Vector<HValue*>(op_vals, descriptor->environment_length()));

-  Drop(1);  // Drop function.
-  ast_context()->ReturnInstruction(call, expr->id());
+  if (drop_extra) Drop(1);  // Drop function.
+  ast_context()->ReturnInstruction(call, ast_id);
   return true;
 }

@@ -7923,7 +7984,7 @@
         }
         return;
       }
-      if (TryInlineApiMethodCall(expr, receiver, map)) return;
+      if (TryInlineApiMethodCall(expr, receiver, types)) return;

       // Wrap the receiver if necessary.
       if (NeedsWrappingFor(ToType(types->first()), known_function)) {
=======================================
--- /branches/bleeding_edge/src/hydrogen.h      Wed Feb  5 15:44:20 2014 UTC
+++ /branches/bleeding_edge/src/hydrogen.h      Wed Feb  5 15:52:31 2014 UTC
@@ -2218,6 +2218,7 @@
   bool TryInlineCall(Call* expr);
   bool TryInlineConstruct(CallNew* expr, HValue* implicit_return_value);
   bool TryInlineGetter(Handle<JSFunction> getter,
+                       Handle<Map> receiver_map,
                        BailoutId ast_id,
                        BailoutId return_id);
   bool TryInlineSetter(Handle<JSFunction> setter,
@@ -2231,14 +2232,24 @@
                                   HValue* receiver,
                                   Handle<Map> receiver_map);
   bool TryInlineBuiltinFunctionCall(Call* expr);
+  enum ApiCallType {
+    kCallApiFunction,
+    kCallApiMethod,
+    kCallApiGetter
+  };
   bool TryInlineApiMethodCall(Call* expr,
                               HValue* receiver,
-                              Handle<Map> receiver_map);
+                              SmallMapList* receiver_types);
   bool TryInlineApiFunctionCall(Call* expr, HValue* receiver);
-  bool TryInlineApiCall(Call* expr,
-                        HValue* receiver,
-                        Handle<Map> receiver_map,
-                        bool is_function_call);
+  bool TryInlineApiGetter(Handle<JSFunction> function,
+                          Handle<Map> receiver_map,
+                          BailoutId ast_id);
+  bool TryInlineApiCall(Handle<JSFunction> function,
+                         HValue* receiver,
+                         SmallMapList* receiver_maps,
+                         int argc,
+                         BailoutId ast_id,
+                         ApiCallType call_type);

   // If --trace-inlining, print a line of the inlining trace.  Inlining
   // succeeded if the reason string is NULL and failed if there is a
@@ -2374,6 +2385,7 @@
     Handle<String> name_;
     Handle<JSObject> holder_;
     Handle<JSFunction> accessor_;
+    Handle<JSObject> api_holder_;
     Handle<Object> constant_;
     Handle<Map> transition_;
     HObjectAccess access_;
=======================================
--- /branches/bleeding_edge/test/cctest/test-api.cc Wed Feb 5 09:29:04 2014 UTC +++ /branches/bleeding_edge/test/cctest/test-api.cc Wed Feb 5 15:52:31 2014 UTC
@@ -21915,6 +21915,25 @@
     CHECK(holder == info.Holder());
     count++;
   }
+
+  // TODO(dcarney): move this to v8.h
+  static void SetAccessorProperty(Local<Object> object,
+                                  Local<String> name,
+                                  Local<Function> getter,
+ Local<Function> setter = Local<Function>()) {
+    i::Isolate* isolate = CcTest::i_isolate();
+    v8::AccessControl settings = v8::DEFAULT;
+    v8::PropertyAttribute attribute = v8::None;
+    i::Handle<i::Object> getter_i = v8::Utils::OpenHandle(*getter);
+    i::Handle<i::Object> setter_i = v8::Utils::OpenHandle(*setter, true);
+    if (setter_i.is_null()) setter_i = isolate->factory()->null_value();
+    i::JSObject::DefineAccessor(v8::Utils::OpenHandle(*object),
+                                v8::Utils::OpenHandle(*name),
+                                getter_i,
+                                setter_i,
+                                static_cast<PropertyAttributes>(attribute),
+                                settings);
+  }

   public:
     void Run(bool use_signature, bool global) {
@@ -21952,9 +21971,12 @@
       Local<FunctionTemplate> function_template = FunctionTemplate::New(
           isolate, OptimizationCallback, data, signature);
       Local<Function> function = function_template->GetFunction();
-      Local<Object>::Cast(
-          inner_global->GetPrototype())->Set(v8_str("global_f"), function);
+      Local<Object> global_holder = Local<Object>::Cast(
+          inner_global->GetPrototype());
+      global_holder->Set(v8_str("g_f"), function);
+      SetAccessorProperty(global_holder, v8_str("g_p1"), function);
       function_holder->Set(v8_str("f"), function);
+      SetAccessorProperty(function_holder, v8_str("p1"), function);
       // Initialize expected values.
       callee = function;
       count = 0;
@@ -21980,33 +22002,40 @@
       if (!use_signature) holder = receiver;
       // build wrap_function
       int key = (use_signature ? 1 : 0) + 2 * (global ? 1 : 0);
-      i::ScopedVector<char> wrap_function(100);
+      i::ScopedVector<char> wrap_function(200);
       if (global) {
         i::OS::SNPrintF(
             wrap_function,
-           "function wrap_%d() { var f = global_f; return f(); }\n",
-            key);
+            "function wrap_f_%d() { var f = g_f; return f(); }\n"
+            "function wrap_p1_%d() { return this.g_p1; }\n",
+            key, key);
       } else {
         i::OS::SNPrintF(
             wrap_function,
-            "function wrap_%d() { return receiver_subclass.f(); }\n",
-            key);
+            "function wrap_f_%d() { return receiver_subclass.f(); }\n"
+            "function wrap_p1_%d() { return receiver_subclass.p1; }\n",
+            key, key);
       }
       // build source string
       i::ScopedVector<char> source(500);
       i::OS::SNPrintF(
           source,
-          "%s\n"  // wrap_function
-          "function wrap2() { wrap_%d(); }\n"
-          "wrap2();\n"
-          "wrap2();\n"
-          "%%OptimizeFunctionOnNextCall(wrap_%d);\n"
-          "wrap2();\n",
-          wrap_function.start(), key, key);
+          "%s\n"  // wrap functions
+          "function wrap_f() { wrap_f_%d(); }\n"
+          "function wrap_p1() { wrap_p1_%d(); }\n"
+          "wrap_f();\n"
+          "wrap_f();\n"
+          "%%OptimizeFunctionOnNextCall(wrap_f_%d);\n"
+          "wrap_f();\n"
+          "wrap_p1();\n"
+          "wrap_p1();\n"
+          "%%OptimizeFunctionOnNextCall(wrap_p1_%d);\n"
+          "wrap_p1();\n",
+          wrap_function.start(), key, key, key, key);
       v8::TryCatch try_catch;
       CompileRun(source.start());
       ASSERT(!try_catch.HasCaught());
-      CHECK_EQ(3, count);
+      CHECK_EQ(6, count);
     }
 };

--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
--- You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.

Reply via email to