Revision: 18946
Author:   [email protected]
Date:     Thu Jan 30 13:18:41 2014 UTC
Log:      crankshaft support for api method calls

[email protected]

BUG=

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

Modified:
 /branches/bleeding_edge/src/arm/code-stubs-arm.cc
 /branches/bleeding_edge/src/arm/macro-assembler-arm.cc
 /branches/bleeding_edge/src/arm/macro-assembler-arm.h
 /branches/bleeding_edge/src/arm/simulator-arm.cc
 /branches/bleeding_edge/src/arm/stub-cache-arm.cc
 /branches/bleeding_edge/src/hydrogen.cc
 /branches/bleeding_edge/src/hydrogen.h
 /branches/bleeding_edge/src/ia32/code-stubs-ia32.cc
 /branches/bleeding_edge/src/ia32/stub-cache-ia32.cc
 /branches/bleeding_edge/src/isolate.h
 /branches/bleeding_edge/src/stub-cache.cc
 /branches/bleeding_edge/src/stub-cache.h
 /branches/bleeding_edge/src/x64/code-stubs-x64.cc
 /branches/bleeding_edge/src/x64/stub-cache-x64.cc
 /branches/bleeding_edge/test/cctest/test-api.cc

=======================================
--- /branches/bleeding_edge/src/arm/code-stubs-arm.cc Thu Jan 30 12:15:51 2014 UTC +++ /branches/bleeding_edge/src/arm/code-stubs-arm.cc Thu Jan 30 13:18:41 2014 UTC
@@ -453,6 +453,27 @@
     descriptor->param_representations_ = representations;
     descriptor->platform_specific_descriptor_ = &default_descriptor;
   }
+  {
+    CallInterfaceDescriptor* descriptor =
+        isolate->call_descriptor(Isolate::ApiFunctionCall);
+    static Register registers[] = { r0,  // callee
+                                    r4,  // call_data
+                                    r2,  // holder
+                                    r1,  // api_function_address
+                                    cp,  // context
+    };
+    static Representation representations[] = {
+        Representation::Tagged(),    // callee
+        Representation::Tagged(),    // call_data
+        Representation::Tagged(),    // holder
+        Representation::External(),  // api_function_address
+        Representation::Tagged(),    // context
+    };
+    descriptor->register_param_count_ = 5;
+    descriptor->register_params_ = registers;
+    descriptor->param_representations_ = representations;
+    descriptor->platform_specific_descriptor_ = &default_descriptor;
+  }
 }


@@ -5379,8 +5400,7 @@
   //  -- r0                  : callee
   //  -- r4                  : call_data
   //  -- r2                  : holder
-  //  -- r3                  : api_function_address
-  //  -- r1                  : thunk_arg
+  //  -- r1                  : api_function_address
   //  -- cp                  : context
   //  --
   //  -- sp[0]               : last argument
@@ -5392,8 +5412,7 @@
   Register callee = r0;
   Register call_data = r4;
   Register holder = r2;
-  Register api_function_address = r3;
-  Register thunk_arg = r1;
+  Register api_function_address = r1;
   Register context = cp;

   int argc = ArgumentBits::decode(bit_field_);
@@ -5449,7 +5468,7 @@
   FrameScope frame_scope(masm, StackFrame::MANUAL);
   __ EnterExitFrame(false, kApiStackSpace);

- ASSERT(!thunk_arg.is(r0) && !api_function_address.is(r0) && !scratch.is(r0));
+  ASSERT(!api_function_address.is(r0) && !scratch.is(r0));
   // r0 = FunctionCallbackInfo&
   // Arguments is after the return address.
   __ add(r0, sp, Operand(1 * kPointerSize));
@@ -5480,7 +5499,6 @@

   __ CallApiFunctionAndReturn(api_function_address,
                               thunk_ref,
-                              thunk_arg,
                               kStackUnwindSpace,
                               return_value_operand,
                               restore_context ?
@@ -5493,12 +5511,10 @@
   //  -- sp[0]                  : name
   //  -- sp[4 - kArgsLength*4]  : PropertyCallbackArguments object
   //  -- ...
-  //  -- r3                    : api_function_address
-  //  -- r2                    : thunk_last_arg
+  //  -- r2                     : api_function_address
   // -----------------------------------

-  Register api_function_address = r3;
-  Register thunk_last_arg = r2;
+  Register api_function_address = r2;

   __ mov(r0, sp);  // r0 = Handle<Name>
   __ add(r1, r0, Operand(1 * kPointerSize));  // r1 = PCA
@@ -5522,7 +5538,6 @@
       masm->isolate());
   __ CallApiFunctionAndReturn(api_function_address,
                               thunk_ref,
-                              thunk_last_arg,
                               kStackUnwindSpace,
                               MemOperand(fp, 6 * kPointerSize),
                               NULL);
=======================================
--- /branches/bleeding_edge/src/arm/macro-assembler-arm.cc Tue Jan 28 11:53:11 2014 UTC +++ /branches/bleeding_edge/src/arm/macro-assembler-arm.cc Thu Jan 30 13:18:41 2014 UTC
@@ -2300,7 +2300,6 @@
 void MacroAssembler::CallApiFunctionAndReturn(
     Register function_address,
     ExternalReference thunk_ref,
-    Register thunk_last_arg,
     int stack_space,
     MemOperand return_value_operand,
     MemOperand* context_restore_operand) {
@@ -2314,8 +2313,7 @@
       ExternalReference::handle_scope_level_address(isolate()),
       next_address);

-  ASSERT(function_address.is(r3));
-  ASSERT(thunk_last_arg.is(r1) || thunk_last_arg.is(r2));
+  ASSERT(function_address.is(r1) || function_address.is(r2));

   Label profiler_disabled;
   Label end_profiler_check;
=======================================
--- /branches/bleeding_edge/src/arm/macro-assembler-arm.h Mon Jan 27 09:57:54 2014 UTC +++ /branches/bleeding_edge/src/arm/macro-assembler-arm.h Thu Jan 30 13:18:41 2014 UTC
@@ -1136,7 +1136,6 @@
   // the additional space allocated for the fast call).
   void CallApiFunctionAndReturn(Register function_address,
                                 ExternalReference thunk_ref,
-                                Register thunk_last_arg,
                                 int stack_space,
                                 MemOperand return_value_operand,
                                 MemOperand* context_restore_operand);
=======================================
--- /branches/bleeding_edge/src/arm/simulator-arm.cc Tue Jan 14 09:57:05 2014 UTC +++ /branches/bleeding_edge/src/arm/simulator-arm.cc Thu Jan 30 13:18:41 2014 UTC
@@ -845,6 +845,12 @@
         addr_of_swi - OFFSET_OF(Redirection, swi_instruction_);
     return reinterpret_cast<Redirection*>(addr_of_redirection);
   }
+
+  static void* ReverseRedirection(int32_t reg) {
+    Redirection* redirection = FromSwiInstruction(
+        reinterpret_cast<Instruction*>(reinterpret_cast<void*>(reg)));
+    return redirection->external_function();
+  }

  private:
   void* external_function_;
@@ -1689,12 +1695,12 @@
 // This signature supports direct call in to API function native callback
 // (refer to InvocationCallback in v8.h).
 typedef void (*SimulatorRuntimeDirectApiCall)(int32_t arg0);
-typedef void (*SimulatorRuntimeProfilingApiCall)(int32_t arg0, int32_t arg1);
+typedef void (*SimulatorRuntimeProfilingApiCall)(int32_t arg0, void* arg1);

 // This signature supports direct call to accessor getter callback.
typedef void (*SimulatorRuntimeDirectGetterCall)(int32_t arg0, int32_t arg1);
 typedef void (*SimulatorRuntimeProfilingGetterCall)(
-    int32_t arg0, int32_t arg1, int32_t arg2);
+    int32_t arg0, int32_t arg1, void* arg2);

// Software interrupt instructions are used by the simulator to call into the
 // C-based V8 runtime.
@@ -1833,7 +1839,7 @@
         CHECK(stack_aligned);
         SimulatorRuntimeProfilingApiCall target =
             reinterpret_cast<SimulatorRuntimeProfilingApiCall>(external);
-        target(arg0, arg1);
+        target(arg0, Redirection::ReverseRedirection(arg1));
       } else if (
           redirection->type() == ExternalReference::DIRECT_GETTER_CALL) {
         if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
@@ -1862,7 +1868,7 @@
         SimulatorRuntimeProfilingGetterCall target =
             reinterpret_cast<SimulatorRuntimeProfilingGetterCall>(
                 external);
-        target(arg0, arg1, arg2);
+        target(arg0, arg1, Redirection::ReverseRedirection(arg2));
       } else {
         // builtin call.
         ASSERT(redirection->type() == ExternalReference::BUILTIN_CALL);
=======================================
--- /branches/bleeding_edge/src/arm/stub-cache-arm.cc Thu Jan 30 12:15:51 2014 UTC +++ /branches/bleeding_edge/src/arm/stub-cache-arm.cc Thu Jan 30 13:18:41 2014 UTC
@@ -788,8 +788,7 @@
   Register callee = r0;
   Register call_data = r4;
   Register holder = r2;
-  Register api_function_address = r3;
-  Register thunk_arg = r1;
+  Register api_function_address = r1;

   // Put holder in place.
   __ Move(holder, holder_in);
@@ -822,53 +821,11 @@
                                             type,
                                             masm->isolate());
   __ mov(api_function_address, Operand(ref));
-  __ mov(thunk_arg, Operand(reinterpret_cast<int32_t>(function_address)));

   // Jump to stub.
   CallApiFunctionStub stub(restore_context, call_data_undefined, argc);
   __ TailCallStub(&stub);
 }
-
-
-// Generates call to API function.
-static void GenerateFastApiCall(MacroAssembler* masm,
-                                const CallOptimization& optimization,
-                                int argc,
-                                Handle<Map> map_to_holder,
- CallOptimization::HolderLookup holder_lookup) {
-  Counters* counters = masm->isolate()->counters();
-  __ IncrementCounter(counters->call_const_fast_api(), 1, r0, r1);
-
-  // Move holder to a register
-  Register holder_reg = r2;
-  switch (holder_lookup) {
-    case CallOptimization::kHolderIsReceiver:
-      {
-        ASSERT(map_to_holder.is_null());
-        __ ldr(holder_reg, MemOperand(sp, argc * kPointerSize));
-      }
-      break;
-    case CallOptimization::kHolderIsPrototypeOfMap:
-      {
- Handle<JSObject> holder(JSObject::cast(map_to_holder->prototype()));
-        if (!masm->isolate()->heap()->InNewSpace(*holder)) {
-          __ Move(holder_reg, holder);
-        } else {
-          __ Move(holder_reg, map_to_holder);
-          __ ldr(holder_reg,
-                 FieldMemOperand(holder_reg, Map::kPrototypeOffset));
-        }
-      }
-     break;
-    case CallOptimization::kHolderNotFound:
-      UNREACHABLE();
-  }
-  GenerateFastApiCallBody(masm,
-                          optimization,
-                          argc,
-                          holder_reg,
-                          false);
-}


 // Generate call to api function.
@@ -975,36 +932,9 @@
           name, miss_label);
     }

-    Handle<Map> lookup_map;
-    CallOptimization::HolderLookup holder_lookup =
-        CallOptimization::kHolderNotFound;
-    if (optimization.is_simple_api_call() &&
-        !lookup->holder()->IsGlobalObject()) {
-      lookup_map = optimization.LookupHolderOfExpectedType(
-          object, object, interceptor_holder, &holder_lookup);
-      if (holder_lookup == CallOptimization::kHolderNotFound) {
-        lookup_map =
-            optimization.LookupHolderOfExpectedType(
-                object,
-                interceptor_holder,
-                Handle<JSObject>(lookup->holder()),
-                &holder_lookup);
-      }
-    }
-
-    // Invoke function.
-    if (holder_lookup != CallOptimization::kHolderNotFound) {
-      int argc = arguments_.immediate();
-      GenerateFastApiCall(masm,
-                          optimization,
-                          argc,
-                          lookup_map,
-                          holder_lookup);
-    } else {
-      Handle<JSFunction> function = optimization.constant_function();
-      __ Move(r0, receiver);
-      stub_compiler_->GenerateJumpFunction(object, function);
-    }
+    Handle<JSFunction> function = optimization.constant_function();
+    __ Move(r0, receiver);
+    stub_compiler_->GenerateJumpFunction(object, function);

     // Invoke a regular function.
     __ bind(&regular_invoke);
@@ -1324,15 +1254,13 @@
   __ push(name());

   // Abi for CallApiGetter
-  Register getter_address_reg = r3;
-  Register thunk_last_arg = r2;
+  Register getter_address_reg = r2;

   Address getter_address = v8::ToCData<Address>(callback->getter());
   ApiFunction fun(getter_address);
   ExternalReference::Type type = ExternalReference::DIRECT_GETTER_CALL;
   ExternalReference ref = ExternalReference(&fun, type, isolate());
   __ mov(getter_address_reg, Operand(ref));
- __ mov(thunk_last_arg, Operand(reinterpret_cast<int32_t>(getter_address)));

   CallApiGetterStub stub;
   __ TailCallStub(&stub);
@@ -1500,57 +1428,6 @@
 }


-Handle<Code> CallStubCompiler::CompileFastApiCall(
-    const CallOptimization& optimization,
-    Handle<Object> object,
-    Handle<JSObject> holder,
-    Handle<Cell> cell,
-    Handle<JSFunction> function,
-    Handle<String> name) {
-  Counters* counters = isolate()->counters();
-
-  ASSERT(optimization.is_simple_api_call());
-  // Bail out if object is a global object as we don't want to
-  // repatch it to global receiver.
-  if (object->IsGlobalObject()) return Handle<Code>::null();
-  if (!cell.is_null()) return Handle<Code>::null();
-  if (!object->IsJSObject()) return Handle<Code>::null();
-  Handle<JSObject> receiver = Handle<JSObject>::cast(object);
-  CallOptimization::HolderLookup holder_lookup =
-      CallOptimization::kHolderNotFound;
-  Handle<Map> lookup_map = optimization.LookupHolderOfExpectedType(
-      receiver, receiver, holder, &holder_lookup);
-  if (holder_lookup == CallOptimization::kHolderNotFound) {
-    return Handle<Code>::null();
-  }
-
-  Label miss;
-  GenerateNameCheck(name, &miss);
-
-  // Get the receiver from the stack.
-  const int argc = arguments().immediate();
-  __ ldr(r1, MemOperand(sp, argc * kPointerSize));
-
-  // Check that the receiver isn't a smi.
-  __ JumpIfSmi(r1, &miss);
-
-  __ IncrementCounter(counters->call_const(), 1, r0, r3);
-
- // Check that the maps haven't changed and find a Holder as a side effect.
-  CheckPrototypes(
-      IC::CurrentTypeOf(object, isolate()),
-      r1, holder, r0, r3, r4, name, &miss);
-
-  GenerateFastApiCall(
-      masm(), optimization, argc, lookup_map, holder_lookup);
-
-  HandlerFrontendFooter(&miss);
-
-  // Return the generated code.
-  return GetCode(function);
-}
-
-
 void StubCompiler::GenerateBooleanCheck(Register object, Label* miss) {
   Label success;
   // Check that the object is a boolean.
@@ -1712,14 +1589,6 @@
     Handle<PropertyCell> cell,
     Handle<JSFunction> function,
     Handle<Name> name) {
-  if (HasCustomCallGenerator(function)) {
-    Handle<Code> code = CompileCustomCall(
-        object, holder, cell, function, Handle<String>::cast(name),
-        Code::NORMAL);
-    // A null handle means bail out to the regular compiler code below.
-    if (!code.is_null()) return code;
-  }
-
   Label miss;
   HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss);
// Potentially loads a closure that matches the shared function info of the
=======================================
--- /branches/bleeding_edge/src/hydrogen.cc     Thu Jan 30 12:52:49 2014 UTC
+++ /branches/bleeding_edge/src/hydrogen.cc     Thu Jan 30 13:18:41 2014 UTC
@@ -7950,6 +7950,118 @@
   }
   return false;
 }
+
+
+bool HOptimizedGraphBuilder::TryInlineApiFunctionCall(Call* expr,
+                                                      HValue* receiver,
+                                                      bool drop_extra) {
+  return TryInlineApiCall(
+      expr, receiver, Handle<Map>::null(), drop_extra, true);
+}
+
+
+bool HOptimizedGraphBuilder::TryInlineApiMethodCall(Call* expr,
+                                                    HValue* receiver,
+ Handle<Map> receiver_map) {
+  return TryInlineApiCall(expr, receiver, receiver_map, false, false);
+}
+
+bool HOptimizedGraphBuilder::TryInlineApiCall(Call* expr,
+                                              HValue* receiver,
+                                              Handle<Map> receiver_map,
+                                              bool drop_extra,
+                                              bool is_function_call) {
+  if (!expr->IsMonomorphic() || expr->check_type() != RECEIVER_MAP_CHECK) {
+    return false;
+  }
+  CallOptimization optimization(expr->target());
+  if (!optimization.is_simple_api_call()) return false;
+  Handle<Map> holder_map;
+  if (is_function_call) {
+    // 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());
+  }
+  CallOptimization::HolderLookup holder_lookup =
+      CallOptimization::kHolderNotFound;
+  Handle<JSObject> api_holder = optimization.LookupHolderOfExpectedType(
+      receiver_map, &holder_lookup);
+  if (holder_lookup == CallOptimization::kHolderNotFound) return false;
+
+  if (FLAG_trace_inlining) {
+    PrintF("Inlining api function ");
+    expr->target()->ShortPrint();
+    PrintF("\n");
+  }
+
+  // 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);
+  }
+
+  // TODO(verwaest): remove.
+  if (!is_function_call) {
+    AddCheckConstantFunction(expr->holder(), receiver, receiver_map);
+  }
+
+  HValue* holder = NULL;
+  switch (holder_lookup) {
+    case CallOptimization::kHolderFound:
+      holder = Add<HConstant>(api_holder);
+      break;
+    case CallOptimization::kHolderIsReceiver:
+ holder = environment()->ExpressionStackAt(expr->arguments()->length());
+      break;
+    case CallOptimization::kHolderNotFound:
+      UNREACHABLE();
+      break;
+  }
+  Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
+  Handle<Object> call_data_obj(api_call_info->data(), isolate());
+  bool call_data_is_undefined = call_data_obj->IsUndefined();
+  HValue* call_data = Add<HConstant>(call_data_obj);
+  ApiFunction fun(v8::ToCData<Address>(api_call_info->callback()));
+  ExternalReference ref = ExternalReference(&fun,
+ ExternalReference::DIRECT_API_CALL,
+                                            isolate());
+  HValue* api_function_address = Add<HConstant>(ExternalReference(ref));
+
+  HValue* op_vals[] = {
+    // callee
+    Add<HConstant>(expr->target()),
+    call_data,
+    holder,
+    api_function_address,
+    context()
+  };
+
+  const int argc = expr->arguments()->length();
+  // Includes receiver.
+  PushArgumentsFromEnvironment(argc + 1);
+
+  CallInterfaceDescriptor* descriptor =
+      isolate()->call_descriptor(Isolate::ApiFunctionCall);
+
+  CallApiFunctionStub stub(true, call_data_is_undefined, argc);
+  Handle<Code> code = stub.GetCode(isolate());
+  HConstant* code_value = Add<HConstant>(code);
+
+  ASSERT((sizeof(op_vals) / kPointerSize) ==
+         descriptor->environment_length());
+
+  HInstruction* call = New<HCallWithDescriptor>(
+      code_value, argc + 1, descriptor,
+      Vector<HValue*>(op_vals, descriptor->environment_length()));
+
+  if (drop_extra) Drop(1);  // Drop function.
+  ast_context()->ReturnInstruction(call, expr->id());
+  return true;
+}


 bool HOptimizedGraphBuilder::TryCallApply(Call* expr) {
@@ -8040,16 +8152,12 @@
Handle<JSFunction> target) {
   SharedFunctionInfo* shared = target->shared();
   if (shared->is_classic_mode() && !shared->native()) {
-    HValue* context = Add<HLoadNamedField>(
-        function, static_cast<HValue*>(NULL),
-        HObjectAccess::ForJSObjectOffset(JSFunction::kContextOffset));
-    HValue* global_object = Add<HLoadNamedField>(
-        context, static_cast<HValue*>(NULL),
-        HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX));
-    return Add<HLoadNamedField>(
-        global_object, static_cast<HValue*>(NULL),
-        HObjectAccess::ForJSObjectOffset(
-            GlobalObject::kGlobalReceiverOffset));
+    // Cannot embed a direct reference to the global proxy
+    // as is it dropped on deserialization.
+    CHECK(!Serializer::enabled());
+    Handle<JSObject> global_receiver(
+        target->context()->global_object()->global_receiver());
+    return Add<HConstant>(global_receiver);
   }
   return graph()->GetConstantUndefined();
 }
@@ -8122,12 +8230,9 @@
         }
         return;
       }
+      if (TryInlineApiMethodCall(expr, receiver, map)) return;

-      if (CallStubCompiler::HasCustomCallGenerator(expr->target()) ||
-          expr->check_type() != RECEIVER_MAP_CHECK) {
-        // When the target has a custom call IC generator, use the IC,
-        // because it is likely to generate better code.  Also use the IC
-        // when a primitive receiver check is required.
+      if (expr->check_type() != RECEIVER_MAP_CHECK) {
         call = NewCallNamed(name, argument_count);
         PushArgumentsFromEnvironment(argument_count);
       } else {
@@ -8193,28 +8298,15 @@
           }
           return;
         }
+        if (TryInlineApiFunctionCall(expr, receiver, false)) return;
         if (TryInlineCall(expr)) return;

         if (expr->target().is_identical_to(current_info()->closure())) {
           graph()->MarkRecursive();
         }

-        if (CallStubCompiler::HasCustomCallGenerator(expr->target())) {
- // We're about to install a contextual IC, which expects the global
-          // object as receiver rather than the global proxy.
-          HValue* global_object = Add<HLoadNamedField>(
-              context(), static_cast<HValue*>(NULL),
-              HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX));
-          const int receiver_index = argument_count - 1;
- environment()->SetExpressionStackAt(receiver_index, global_object);
-          // When the target has a custom call IC generator, use the IC,
-          // because it is likely to generate better code.
-          call = NewCallNamed(var->name(), argument_count);
-          PushArgumentsFromEnvironment(argument_count);
-        } else {
-          call = BuildCallConstantFunction(expr->target(), argument_count);
-          PushArgumentsFromEnvironment(argument_count);
-        }
+        call = BuildCallConstantFunction(expr->target(), argument_count);
+        PushArgumentsFromEnvironment(argument_count);
       } else {
         HValue* receiver = Add<HLoadNamedField>(
             context(), static_cast<HValue*>(NULL),
@@ -8247,6 +8339,7 @@
         }
         return;
       }
+      if (TryInlineApiFunctionCall(expr, receiver, true)) return;

       if (TryInlineCall(expr, true)) {   // Drop function from environment.
         return;
=======================================
--- /branches/bleeding_edge/src/hydrogen.h      Thu Jan 30 11:30:38 2014 UTC
+++ /branches/bleeding_edge/src/hydrogen.h      Thu Jan 30 13:18:41 2014 UTC
@@ -2227,6 +2227,14 @@
                                   Handle<Map> receiver_map,
                                   CheckType check_type);
   bool TryInlineBuiltinFunctionCall(Call* expr, bool drop_extra);
+  bool TryInlineApiMethodCall(
+      Call* expr, HValue* receiver, Handle<Map> receiver_map);
+ bool TryInlineApiFunctionCall(Call* expr, HValue* receiver, bool drop_extra);
+  bool TryInlineApiCall(Call* expr,
+                        HValue* receiver,
+                        Handle<Map> receiver_map,
+                        bool drop_extra,
+                        bool is_function_call);

   // If --trace-inlining, print a line of the inlining trace.  Inlining
   // succeeded if the reason string is NULL and failed if there is a
=======================================
--- /branches/bleeding_edge/src/ia32/code-stubs-ia32.cc Thu Jan 30 12:15:51 2014 UTC +++ /branches/bleeding_edge/src/ia32/code-stubs-ia32.cc Thu Jan 30 13:18:41 2014 UTC
@@ -446,6 +446,26 @@
     descriptor->register_params_ = registers;
     descriptor->param_representations_ = representations;
   }
+  {
+    CallInterfaceDescriptor* descriptor =
+        isolate->call_descriptor(Isolate::ApiFunctionCall);
+    static Register registers[] = { eax,  // callee
+                                    ebx,  // call_data
+                                    ecx,  // holder
+                                    edx,  // api_function_address
+                                    esi,  // context
+    };
+    static Representation representations[] = {
+        Representation::Tagged(),    // callee
+        Representation::Tagged(),    // call_data
+        Representation::Tagged(),    // holder
+        Representation::External(),  // api_function_address
+        Representation::Tagged(),    // context
+    };
+    descriptor->register_param_count_ = 5;
+    descriptor->register_params_ = registers;
+    descriptor->param_representations_ = representations;
+  }
 }


=======================================
--- /branches/bleeding_edge/src/ia32/stub-cache-ia32.cc Thu Jan 30 12:15:51 2014 UTC +++ /branches/bleeding_edge/src/ia32/stub-cache-ia32.cc Thu Jan 30 13:18:41 2014 UTC
@@ -460,46 +460,6 @@
   CallApiFunctionStub stub(restore_context, call_data_undefined, argc);
   __ TailCallStub(&stub);
 }
-
-
-// Generates call to API function.
-static void GenerateFastApiCall(MacroAssembler* masm,
-                                const CallOptimization& optimization,
-                                int argc,
-                                Handle<Map> map_to_holder,
- CallOptimization::HolderLookup holder_lookup) {
-  Counters* counters = masm->isolate()->counters();
-  __ IncrementCounter(counters->call_const_fast_api(), 1);
-
-  // Move holder to a register
-  Register holder_reg = ecx;
-  switch (holder_lookup) {
-    case CallOptimization::kHolderIsReceiver:
-      {
-        ASSERT(map_to_holder.is_null());
-        __ mov(holder_reg, Operand(esp, (argc + 1)* kPointerSize));
-      }
-      break;
-    case CallOptimization::kHolderIsPrototypeOfMap:
-      {
- Handle<JSObject> holder(JSObject::cast(map_to_holder->prototype()));
-        if (!masm->isolate()->heap()->InNewSpace(*holder)) {
-          __ mov(holder_reg, holder);
-        } else {
-          __ mov(holder_reg, map_to_holder);
- __ mov(holder_reg, FieldOperand(holder_reg, Map::kPrototypeOffset));
-        }
-      }
-     break;
-    case CallOptimization::kHolderNotFound:
-      UNREACHABLE();
-  }
-  GenerateFastApiCallBody(masm,
-                          optimization,
-                          argc,
-                          holder_reg,
-                          false);
-}


 // Generate call to api function.
@@ -612,35 +572,8 @@
           name, miss_label);
     }

-    Handle<Map> lookup_map;
-    CallOptimization::HolderLookup holder_lookup =
-        CallOptimization::kHolderNotFound;
-    if (optimization.is_simple_api_call() &&
-        !lookup->holder()->IsGlobalObject()) {
-      lookup_map = optimization.LookupHolderOfExpectedType(
-          object, object, interceptor_holder, &holder_lookup);
-      if (holder_lookup == CallOptimization::kHolderNotFound) {
-        lookup_map =
-            optimization.LookupHolderOfExpectedType(
-                object,
-                interceptor_holder,
-                Handle<JSObject>(lookup->holder()),
-                &holder_lookup);
-      }
-    }
-
-    // Invoke function.
-    if (holder_lookup != CallOptimization::kHolderNotFound) {
-      int argc = arguments_.immediate();
-      GenerateFastApiCall(masm,
-                          optimization,
-                          argc,
-                          lookup_map,
-                          holder_lookup);
-    } else {
-      Handle<JSFunction> fun = optimization.constant_function();
-      stub_compiler_->GenerateJumpFunction(object, fun);
-    }
+    Handle<JSFunction> fun = optimization.constant_function();
+    stub_compiler_->GenerateJumpFunction(object, fun);

     // Invoke a regular function.
     __ bind(&regular_invoke);
@@ -1509,54 +1442,6 @@
   return GetCode(Code::FAST, name);
 }

-
-Handle<Code> CallStubCompiler::CompileFastApiCall(
-    const CallOptimization& optimization,
-    Handle<Object> object,
-    Handle<JSObject> holder,
-    Handle<Cell> cell,
-    Handle<JSFunction> function,
-    Handle<String> name) {
-  ASSERT(optimization.is_simple_api_call());
-  // Bail out if object is a global object as we don't want to
-  // repatch it to global receiver.
-  if (object->IsGlobalObject()) return Handle<Code>::null();
-  if (!cell.is_null()) return Handle<Code>::null();
-  if (!object->IsJSObject()) return Handle<Code>::null();
-  Handle<JSObject> receiver = Handle<JSObject>::cast(object);
-  CallOptimization::HolderLookup holder_lookup =
-      CallOptimization::kHolderNotFound;
-  Handle<Map> lookup_map = optimization.LookupHolderOfExpectedType(
-      receiver, receiver, holder, &holder_lookup);
-  if (holder_lookup == CallOptimization::kHolderNotFound) {
-    return Handle<Code>::null();
-  }
-
-  Label miss;
-  GenerateNameCheck(name, &miss);
-
-  // Get the receiver from the stack.
-  const int argc = arguments().immediate();
-  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
-
-  // Check that the receiver isn't a smi.
-  __ JumpIfSmi(edx, &miss);
-
-  Counters* counters = isolate()->counters();
-  __ IncrementCounter(counters->call_const(), 1);
-
- // Check that the maps haven't changed and find a Holder as a side effect.
-  CheckPrototypes(IC::CurrentTypeOf(object, isolate()), edx, holder,
-                  ebx, eax, edi, name, &miss);
-
- GenerateFastApiCall(masm(), optimization, argc, lookup_map, holder_lookup);
-
-  HandlerFrontendFooter(&miss);
-
-  // Return the generated code.
-  return GetCode(function);
-}
-

 void StubCompiler::GenerateBooleanCheck(Register object, Label* miss) {
   Label success;
@@ -1712,14 +1597,6 @@
     Handle<PropertyCell> cell,
     Handle<JSFunction> function,
     Handle<Name> name) {
-  if (HasCustomCallGenerator(function)) {
-    Handle<Code> code = CompileCustomCall(
-        object, holder, cell, function, Handle<String>::cast(name),
-        Code::NORMAL);
-    // A null handle means bail out to the regular compiler code below.
-    if (!code.is_null()) return code;
-  }
-
   Label miss;
   HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss);
// Potentially loads a closure that matches the shared function info of the
=======================================
--- /branches/bleeding_edge/src/isolate.h       Thu Jan 30 10:33:53 2014 UTC
+++ /branches/bleeding_edge/src/isolate.h       Thu Jan 30 13:18:41 2014 UTC
@@ -1082,6 +1082,7 @@
     NamedCall,
     CallHandler,
     ArgumentAdaptorCall,
+    ApiFunctionCall,
     NUMBER_OF_CALL_DESCRIPTORS
   };

=======================================
--- /branches/bleeding_edge/src/stub-cache.cc   Fri Jan 24 11:47:53 2014 UTC
+++ /branches/bleeding_edge/src/stub-cache.cc   Thu Jan 30 13:18:41 2014 UTC
@@ -1288,15 +1288,6 @@
     Handle<Name> name,
     CheckType check,
     Handle<JSFunction> function) {
-  if (HasCustomCallGenerator(function)) {
-    Handle<Code> code = CompileCustomCall(object, holder,
-                                          Handle<Cell>::null(),
- function, Handle<String>::cast(name),
-                                          Code::FAST);
-    // A null handle means bail out to the regular compiler code below.
-    if (!code.is_null()) return code;
-  }
-
   Label miss;
   HandlerFrontendHeader(object, holder, name, check, &miss);
   GenerateJumpFunction(object, function);
@@ -1875,31 +1866,6 @@
       kind_(kind),
       cache_holder_(cache_holder) {
 }
-
-
-bool CallStubCompiler::HasCustomCallGenerator(Handle<JSFunction> function) {
-  CallOptimization optimization(function);
-  return optimization.is_simple_api_call();
-}
-
-
-Handle<Code> CallStubCompiler::CompileCustomCall(
-    Handle<Object> object,
-    Handle<JSObject> holder,
-    Handle<Cell> cell,
-    Handle<JSFunction> function,
-    Handle<String> fname,
-    Code::StubType type) {
-  ASSERT(HasCustomCallGenerator(function));
-  CallOptimization optimization(function);
-  ASSERT(optimization.is_simple_api_call());
-  return CompileFastApiCall(optimization,
-                            object,
-                            holder,
-                            cell,
-                            function,
-                            fname);
-}


 Handle<Code> CallStubCompiler::GetCode(Code::StubType type,
@@ -1937,44 +1903,32 @@
 }


-Handle<Map> CallOptimization::LookupHolderOfExpectedType(
-    Handle<JSObject> receiver,
-    Handle<JSObject> object,
-    Handle<JSObject> holder,
+Handle<JSObject> CallOptimization::LookupHolderOfExpectedType(
+    Handle<Map> object_map,
     HolderLookup* holder_lookup) const {
   ASSERT(is_simple_api_call());
   ASSERT_EQ(kHolderNotFound, *holder_lookup);
-  *holder_lookup = kHolderIsReceiver;
-  Handle<Map> map_to_holder;
-  if (expected_receiver_type_.is_null()) {
-    // no expected type, load from receiver.
-    return map_to_holder;
+  if (!object_map->IsJSObjectMap()) {
+    *holder_lookup = kHolderNotFound;
+    return Handle<JSObject>::null();
   }
-  // walk down the prototype chain to the object
-  while (!receiver.is_identical_to(object)) {
-    *holder_lookup = kHolderIsPrototypeOfMap;
-    map_to_holder = Handle<Map>(receiver->map());
- receiver = Handle<JSObject>(JSObject::cast(map_to_holder->prototype()));
+  if (expected_receiver_type_.is_null() ||
+      expected_receiver_type_->IsTemplateFor(*object_map)) {
+    *holder_lookup = kHolderIsReceiver;
+    return Handle<JSObject>::null();
   }
-  // start looking for the holder
-  while (!object.is_identical_to(holder)) {
-    Handle<Map> object_map(object->map());
+  while (true) {
+    if (!object_map->prototype()->IsJSObject()) break;
+    Handle<JSObject> prototype(JSObject::cast(object_map->prototype()));
+    if (!prototype->map()->is_hidden_prototype()) break;
+    object_map = handle(prototype->map());
     if (expected_receiver_type_->IsTemplateFor(*object_map)) {
-      return map_to_holder;
+      *holder_lookup = kHolderFound;
+      return prototype;
     }
-    if (!object_map->is_hidden_prototype()) {
-      *holder_lookup = kHolderNotFound;
-      return Handle<Map>::null();
-    }
-    *holder_lookup = kHolderIsPrototypeOfMap;
-    map_to_holder = object_map;
-    object = Handle<JSObject>(JSObject::cast(object_map->prototype()));
-  }
-  if (expected_receiver_type_->IsTemplateFor(holder->map())) {
-    return map_to_holder;
   }
   *holder_lookup = kHolderNotFound;
-  return Handle<Map>::null();
+  return Handle<JSObject>::null();
 }


=======================================
--- /branches/bleeding_edge/src/stub-cache.h    Fri Jan 24 11:47:53 2014 UTC
+++ /branches/bleeding_edge/src/stub-cache.h    Thu Jan 30 13:18:41 2014 UTC
@@ -921,26 +921,7 @@
                                  Handle<JSFunction> function,
                                  Handle<Name> name);

-  static bool HasCustomCallGenerator(Handle<JSFunction> function);
-
  private:
-  // Compiles a custom call constant/global IC.  For constant calls cell is
-  // NULL.  Returns an empty handle if there is no custom call code for the
-  // given function.
-  Handle<Code> CompileCustomCall(Handle<Object> object,
-                                 Handle<JSObject> holder,
-                                 Handle<Cell> cell,
-                                 Handle<JSFunction> function,
-                                 Handle<String> name,
-                                 Code::StubType type);
-
-  Handle<Code> CompileFastApiCall(const CallOptimization& optimization,
-                                  Handle<Object> object,
-                                  Handle<JSObject> holder,
-                                  Handle<Cell> cell,
-                                  Handle<JSFunction> function,
-                                  Handle<String> name);
-
   Handle<Code> GetCode(Code::StubType type, Handle<Name> name);
   Handle<Code> GetCode(Handle<JSFunction> function);

@@ -998,16 +979,11 @@
   enum HolderLookup {
     kHolderNotFound,
     kHolderIsReceiver,
-    kHolderIsPrototypeOfMap
+    kHolderFound
   };
-  // Returns a map whose prototype has the expected type in the
-  // prototype chain between the two arguments
-  // null will be returned if the first argument has that property
-  // lookup will be set accordingly
-  Handle<Map> LookupHolderOfExpectedType(Handle<JSObject> receiver,
-                                         Handle<JSObject> object,
-                                         Handle<JSObject> holder,
- HolderLookup* holder_lookup) const;
+  Handle<JSObject> LookupHolderOfExpectedType(
+      Handle<Map> receiver_map,
+      HolderLookup* holder_lookup) const;

   bool IsCompatibleReceiver(Object* receiver) {
     ASSERT(is_simple_api_call());
=======================================
--- /branches/bleeding_edge/src/x64/code-stubs-x64.cc Thu Jan 30 12:15:51 2014 UTC +++ /branches/bleeding_edge/src/x64/code-stubs-x64.cc Thu Jan 30 13:18:41 2014 UTC
@@ -443,6 +443,26 @@
     descriptor->register_params_ = registers;
     descriptor->param_representations_ = representations;
   }
+  {
+    CallInterfaceDescriptor* descriptor =
+        isolate->call_descriptor(Isolate::ApiFunctionCall);
+    static Register registers[] = { rax,  // callee
+                                    rbx,  // call_data
+                                    rcx,  // holder
+                                    rdx,  // api_function_address
+                                    rsi,  // context
+    };
+    static Representation representations[] = {
+        Representation::Tagged(),    // callee
+        Representation::Tagged(),    // call_data
+        Representation::Tagged(),    // holder
+        Representation::External(),  // api_function_address
+        Representation::Tagged(),    // context
+    };
+    descriptor->register_param_count_ = 5;
+    descriptor->register_params_ = registers;
+    descriptor->param_representations_ = representations;
+  }
 }


=======================================
--- /branches/bleeding_edge/src/x64/stub-cache-x64.cc Thu Jan 30 12:15:51 2014 UTC +++ /branches/bleeding_edge/src/x64/stub-cache-x64.cc Thu Jan 30 13:18:41 2014 UTC
@@ -435,47 +435,6 @@
   CallApiFunctionStub stub(restore_context, call_data_undefined, argc);
   __ TailCallStub(&stub);
 }
-
-
-// Generates call to API function.
-static void GenerateFastApiCall(MacroAssembler* masm,
-                                const CallOptimization& optimization,
-                                int argc,
-                                Handle<Map> map_to_holder,
- CallOptimization::HolderLookup holder_lookup) {
-  Counters* counters = masm->isolate()->counters();
-  __ IncrementCounter(counters->call_const_fast_api(), 1);
-
-  // Move holder to a register
-  Register holder_reg = rax;
-  switch (holder_lookup) {
-    case CallOptimization::kHolderIsReceiver:
-      {
-        ASSERT(map_to_holder.is_null());
-        StackArgumentsAccessor args(rsp, argc);
-        __ movp(holder_reg, args.GetReceiverOperand());
-      }
-      break;
-    case CallOptimization::kHolderIsPrototypeOfMap:
-      {
- Handle<JSObject> holder(JSObject::cast(map_to_holder->prototype()));
-        if (!masm->isolate()->heap()->InNewSpace(*holder)) {
-          __ Move(holder_reg, holder);
-        } else {
-          __ Move(holder_reg, map_to_holder);
- __ movp(holder_reg, FieldOperand(holder_reg, Map::kPrototypeOffset));
-        }
-      }
-     break;
-    case CallOptimization::kHolderNotFound:
-      UNREACHABLE();
-  }
-  GenerateFastApiCallBody(masm,
-                          optimization,
-                          argc,
-                          holder_reg,
-                          false);
-}


 // Generate call to api function.
@@ -585,35 +544,8 @@
           name, miss_label);
     }

-    Handle<Map> lookup_map;
-    CallOptimization::HolderLookup holder_lookup =
-        CallOptimization::kHolderNotFound;
-    if (optimization.is_simple_api_call() &&
-        !lookup->holder()->IsGlobalObject()) {
-      lookup_map = optimization.LookupHolderOfExpectedType(
-          object, object, interceptor_holder, &holder_lookup);
-      if (holder_lookup == CallOptimization::kHolderNotFound) {
-        lookup_map =
-            optimization.LookupHolderOfExpectedType(
-                object,
-                interceptor_holder,
-                Handle<JSObject>(lookup->holder()),
-                &holder_lookup);
-      }
-    }
-
-    // Invoke function.
-    if (holder_lookup != CallOptimization::kHolderNotFound) {
-      int argc = arguments_.immediate();
-      GenerateFastApiCall(masm,
-                          optimization,
-                          argc,
-                          lookup_map,
-                          holder_lookup);
-    } else {
-      Handle<JSFunction> fun = optimization.constant_function();
-      stub_compiler_->GenerateJumpFunction(object, fun);
-    }
+    Handle<JSFunction> fun = optimization.constant_function();
+    stub_compiler_->GenerateJumpFunction(object, fun);

     // Invoke a regular function.
     __ bind(&regular_invoke);
@@ -1399,54 +1331,6 @@
   // Return the generated code.
   return GetCode(Code::FAST, name);
 }
-
-
-Handle<Code> CallStubCompiler::CompileFastApiCall(
-    const CallOptimization& optimization,
-    Handle<Object> object,
-    Handle<JSObject> holder,
-    Handle<Cell> cell,
-    Handle<JSFunction> function,
-    Handle<String> name) {
-  ASSERT(optimization.is_simple_api_call());
-  // Bail out if object is a global object as we don't want to
-  // repatch it to global receiver.
-  if (object->IsGlobalObject()) return Handle<Code>::null();
-  if (!cell.is_null()) return Handle<Code>::null();
-  if (!object->IsJSObject()) return Handle<Code>::null();
-  Handle<JSObject> receiver = Handle<JSObject>::cast(object);
-  CallOptimization::HolderLookup holder_lookup =
-      CallOptimization::kHolderNotFound;
-  Handle<Map> lookup_map = optimization.LookupHolderOfExpectedType(
-      receiver, receiver, holder, &holder_lookup);
-  if (holder_lookup == CallOptimization::kHolderNotFound) {
-    return Handle<Code>::null();
-  }
-
-  Label miss;
-  GenerateNameCheck(name, &miss);
-
-  const int argc = arguments().immediate();
-  StackArgumentsAccessor args(rsp, argc);
-  __ movp(rdx, args.GetReceiverOperand());
-
-  // Check that the receiver isn't a smi.
-  __ JumpIfSmi(rdx, &miss);
-
-  Counters* counters = isolate()->counters();
-  __ IncrementCounter(counters->call_const(), 1);
-
- // Check that the maps haven't changed and find a Holder as a side effect.
-  CheckPrototypes(IC::CurrentTypeOf(object, isolate()), rdx, holder,
-                  rbx, rax, rdi, name, &miss);
-
- GenerateFastApiCall(masm(), optimization, argc, lookup_map, holder_lookup);
-
-  HandlerFrontendFooter(&miss);
-
-  // Return the generated code.
-  return GetCode(function);
-}


 void StubCompiler::GenerateBooleanCheck(Register object, Label* miss) {
@@ -1599,14 +1483,6 @@
     Handle<PropertyCell> cell,
     Handle<JSFunction> function,
     Handle<Name> name) {
-  if (HasCustomCallGenerator(function)) {
-    Handle<Code> code = CompileCustomCall(
-        object, holder, cell, function, Handle<String>::cast(name),
-        Code::NORMAL);
-    // A null handle means bail out to the regular compiler code below.
-    if (!code.is_null()) return code;
-  }
-
   Label miss;
   HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss);
// Potentially loads a closure that matches the shared function info of the
=======================================
--- /branches/bleeding_edge/test/cctest/test-api.cc Thu Jan 30 10:53:20 2014 UTC +++ /branches/bleeding_edge/test/cctest/test-api.cc Thu Jan 30 13:18:41 2014 UTC
@@ -21845,3 +21845,132 @@
       "  new C1();"
       "}");
 }
+
+
+class ApiCallOptimizationChecker {
+ private:
+  static Local<Object> data;
+  static Local<Object> receiver;
+  static Local<Object> holder;
+  static Local<Object> callee;
+  static int count;
+
+  static void OptimizationCallback(
+      const v8::FunctionCallbackInfo<v8::Value>& info) {
+    CHECK(callee == info.Callee());
+    CHECK(data == info.Data());
+    CHECK(receiver == info.This());
+    CHECK(holder == info.Holder());
+    count++;
+  }
+
+  public:
+    void Run(bool use_signature, bool global) {
+      v8::Isolate* isolate = CcTest::isolate();
+      v8::HandleScope scope(isolate);
+      // Build a template for signature checks.
+      Local<v8::ObjectTemplate> signature_template;
+      Local<v8::Signature> signature;
+      {
+        Local<v8::FunctionTemplate> parent_template =
+          FunctionTemplate::New(isolate);
+        parent_template->SetHiddenPrototype(true);
+        Local<v8::FunctionTemplate> function_template
+            = FunctionTemplate::New(isolate);
+        function_template->Inherit(parent_template);
+        if (use_signature) {
+          signature = v8::Signature::New(isolate, parent_template);
+        }
+        signature_template = function_template->InstanceTemplate();
+      }
+      // Global object must pass checks.
+      Local<v8::Context> context =
+          v8::Context::New(isolate, NULL, signature_template);
+      v8::Context::Scope context_scope(context);
+      // Install regular object that can pass signature checks.
+      Local<Object> function_receiver = signature_template->NewInstance();
+ context->Global()->Set(v8_str("function_receiver"), function_receiver);
+      // Get the holder objects.
+      Local<Object> inner_global =
+          Local<Object>::Cast(context->Global()->GetPrototype());
+      Local<Object> function_holder =
+          Local<Object>::Cast(function_receiver->GetPrototype());
+      // Install function on hidden prototype object.
+      data = Object::New(isolate);
+      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);
+      function_holder->Set(v8_str("f"), function);
+      // Initialize expected values.
+      callee = function;
+      count = 0;
+      if (global) {
+        receiver = context->Global();
+        holder = inner_global;
+      } else {
+        holder = function_receiver;
+ // If not using a signature, add something else to the prototype chain
+        // to test the case that holder != receiver
+        if (!use_signature) {
+          receiver = Local<Object>::Cast(CompileRun(
+              "var receiver_subclass = {};\n"
+              "receiver_subclass.__proto__ = function_receiver;\n"
+              "receiver_subclass"));
+        } else {
+          receiver = Local<Object>::Cast(CompileRun(
+            "var receiver_subclass = function_receiver;\n"
+            "receiver_subclass"));
+        }
+      }
+      // With no signature, the holder is not set.
+      if (!use_signature) holder = receiver;
+      // build wrap_function
+      int key = (use_signature ? 1 : 0) + 2 * (global ? 1 : 0);
+      i::ScopedVector<char> wrap_function(100);
+      if (global) {
+        i::OS::SNPrintF(
+            wrap_function,
+           "function wrap_%d() { var f = global_f; return f(); }\n",
+            key);
+      } else {
+        i::OS::SNPrintF(
+            wrap_function,
+            "function wrap_%d() { return receiver_subclass.f(); }\n",
+            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);
+      v8::TryCatch try_catch;
+      CompileRun(source.start());
+      ASSERT(!try_catch.HasCaught());
+      CHECK_EQ(3, count);
+    }
+};
+
+
+Local<Object> ApiCallOptimizationChecker::data;
+Local<Object> ApiCallOptimizationChecker::receiver;
+Local<Object> ApiCallOptimizationChecker::holder;
+Local<Object> ApiCallOptimizationChecker::callee;
+int ApiCallOptimizationChecker::count = 0;
+
+
+TEST(TestFunctionCallOptimization) {
+  i::FLAG_allow_natives_syntax = true;
+  ApiCallOptimizationChecker checker;
+  checker.Run(true, true);
+  checker.Run(false, true);
+  checker.Run(true, false);
+  checker.Run(false, false);
+}

--
--
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