Optimized calling of C++ builtins (and HandleApiCall
authorvitalyr@chromium.org <vitalyr@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 15 Jan 2010 12:25:24 +0000 (12:25 +0000)
committervitalyr@chromium.org <vitalyr@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 15 Jan 2010 12:25:24 +0000 (12:25 +0000)
in particular).

  * Called function is passed on the stack instead of
    using a static variable.

  * Builtins that don't need the called function don't
    get it.

  * Made is_construct statically known to HandleApiCall
    by setting custom construct stub for API functions.

Review URL: http://codereview.chromium.org/536065

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3613 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/arm/builtins-arm.cc
src/assembler.cc
src/assembler.h
src/builtins.cc
src/builtins.h
src/factory.cc
src/ia32/builtins-ia32.cc
src/serialize.cc
src/x64/builtins-x64.cc
test/cctest/test-api.cc
test/cctest/test-serialize.cc

index 5389a3c5f53085823cca4554f4077e13fc5773d0..ae7dae3b0833a13f5f1497d12b79686807fee04e 100644 (file)
@@ -38,15 +38,32 @@ namespace internal {
 #define __ ACCESS_MASM(masm)
 
 
-void Builtins::Generate_Adaptor(MacroAssembler* masm, CFunctionId id) {
-  // TODO(428): Don't pass the function in a static variable.
-  __ mov(ip, Operand(ExternalReference::builtin_passed_function()));
-  __ str(r1, MemOperand(ip, 0));
-
-  // The actual argument count has already been loaded into register
-  // r0, but JumpToRuntime expects r0 to contain the number of
-  // arguments including the receiver.
-  __ add(r0, r0, Operand(1));
+void Builtins::Generate_Adaptor(MacroAssembler* masm,
+                                CFunctionId id,
+                                BuiltinExtraArguments extra_args) {
+  // ----------- S t a t e -------------
+  //  -- r0                 : number of arguments excluding receiver
+  //  -- r1                 : called function (only guaranteed when
+  //                          extra_args requires it)
+  //  -- cp                 : context
+  //  -- sp[0]              : last argument
+  //  -- ...
+  //  -- sp[4 * (argc - 1)] : first argument (argc == r0)
+  //  -- sp[4 * argc]       : receiver
+  // -----------------------------------
+
+  // Insert extra arguments.
+  int num_extra_args = 0;
+  if (extra_args == NEEDS_CALLED_FUNCTION) {
+    num_extra_args = 1;
+    __ push(r1);
+  } else {
+    ASSERT(extra_args == NO_EXTRA_ARGUMENTS);
+  }
+
+  // JumpToRuntime expects r0 to contain the number of arguments
+  // including the receiver and the extra arguments.
+  __ add(r0, r0, Operand(num_extra_args + 1));
   __ JumpToRuntime(ExternalReference(id));
 }
 
@@ -491,7 +508,8 @@ void Builtins::Generate_JSConstructCall(MacroAssembler* masm) {
 }
 
 
-void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
+static void Generate_JSConstructStubHelper(MacroAssembler* masm,
+                                           bool is_api_function) {
   // Enter a construct frame.
   __ EnterConstructFrame();
 
@@ -727,8 +745,17 @@ void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
   // Call the function.
   // r0: number of arguments
   // r1: constructor function
-  ParameterCount actual(r0);
-  __ InvokeFunction(r1, actual, CALL_FUNCTION);
+  if (is_api_function) {
+    __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
+    Handle<Code> code = Handle<Code>(
+        Builtins::builtin(Builtins::HandleApiCallConstruct));
+    ParameterCount expected(0);
+    __ InvokeCode(code, expected, expected,
+                  RelocInfo::CODE_TARGET, CALL_FUNCTION);
+  } else {
+    ParameterCount actual(r0);
+    __ InvokeFunction(r1, actual, CALL_FUNCTION);
+  }
 
   // Pop the function from the stack.
   // sp[0]: constructor function
@@ -783,6 +810,16 @@ void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
 }
 
 
+void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
+  Generate_JSConstructStubHelper(masm, false);
+}
+
+
+void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) {
+  Generate_JSConstructStubHelper(masm, true);
+}
+
+
 static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
                                              bool is_construct) {
   // Called from Generate_JS_Entry
index a736fb13f3ca9d301b5e499bd6c3aefcfcfe8aba..195073a0961bc14ac8d4df03e7e6cc243a4c887c 100644 (file)
@@ -563,11 +563,6 @@ ExternalReference ExternalReference::perform_gc_function() {
 }
 
 
-ExternalReference ExternalReference::builtin_passed_function() {
-  return ExternalReference(&Builtins::builtin_passed_function);
-}
-
-
 ExternalReference ExternalReference::random_positive_smi_function() {
   return ExternalReference(Redirect(FUNCTION_ADDR(V8::RandomPositiveSmi)));
 }
index e5efe89b6728630d792eb3f57286c8d762f73d6a..b3077a0c93f6d3664b484894bbb513564b2bd39b 100644 (file)
@@ -398,7 +398,6 @@ class ExternalReference BASE_EMBEDDED {
   // ExternalReferenceTable in serialize.cc manually.
 
   static ExternalReference perform_gc_function();
-  static ExternalReference builtin_passed_function();
   static ExternalReference random_positive_smi_function();
 
   // Static data in the keyed lookup cache.
index aa680d76b42b3f9acfa5712b7e4d142001dd76d2..f86e27a0c2cbc5dd536530134fe1235f1a2263de 100644 (file)
 namespace v8 {
 namespace internal {
 
+namespace {
+
+// Arguments object passed to C++ builtins.
+template <BuiltinExtraArguments extra_args>
+class BuiltinArguments : public Arguments {
+ public:
+  Object*& operator[] (int index) {
+    ASSERT(index < length());
+    return Arguments::operator[](index);
+  }
+
+  template <class S> Handle<S> at(int index) {
+    ASSERT(index < length());
+    return Arguments::at<S>(index);
+  }
+
+  Handle<Object> receiver() {
+    return Arguments::at<Object>(0);
+  }
+
+  Handle<JSFunction> called_function() {
+    STATIC_ASSERT(extra_args == NEEDS_CALLED_FUNCTION);
+    return Arguments::at<JSFunction>(Arguments::length() - 1);
+  }
+
+  // Gets the total number of arguments including the receiver (but
+  // excluding extra arguments).
+  int length() const {
+    STATIC_ASSERT(extra_args == NO_EXTRA_ARGUMENTS);
+    return Arguments::length();
+  }
+
+#ifdef DEBUG
+  void Verify() {
+    // Check we have at least the receiver.
+    ASSERT(Arguments::length() >= 1);
+  }
+#endif
+};
+
+
+// Specialize BuiltinArguments for the called function extra argument.
+
+template <>
+int BuiltinArguments<NEEDS_CALLED_FUNCTION>::length() const {
+  return Arguments::length() - 1;
+}
+
+#ifdef DEBUG
+template <>
+void BuiltinArguments<NEEDS_CALLED_FUNCTION>::Verify() {
+  // Check we have at least the receiver and the called function.
+  ASSERT(Arguments::length() >= 2);
+  // Make sure cast to JSFunction succeeds.
+  called_function();
+}
+#endif
+
+
+#define DEF_ARG_TYPE(name, spec)                      \
+  typedef BuiltinArguments<spec> name##ArgumentsType;
+BUILTIN_LIST_C(DEF_ARG_TYPE)
+#undef DEF_ARG_TYPE
+
+}  // namespace
+
+
 // ----------------------------------------------------------------------------
-// Support macros for defining builtins in C.
+// Support macro for defining builtins in C++.
 // ----------------------------------------------------------------------------
 //
 // A builtin function is defined by writing:
@@ -45,30 +112,26 @@ namespace internal {
 //   BUILTIN(name) {
 //     ...
 //   }
-//   BUILTIN_END
 //
-// In the body of the builtin function, the variable 'receiver' is visible.
-// The arguments can be accessed through the Arguments object args.
-//
-//   args[0]: Receiver (also available as 'receiver')
-//   args[1]: First argument
-//     ...
-//   args[n]: Last argument
-//   args.length(): Number of arguments including the receiver.
-// ----------------------------------------------------------------------------
+// In the body of the builtin function the arguments can be accessed
+// through the BuiltinArguments object args.
 
+#ifdef DEBUG
 
-// TODO(428): We should consider passing whether or not the
-// builtin was invoked as a constructor as part of the
-// arguments. Maybe we also want to pass the called function?
-#define BUILTIN(name)                                                   \
-  static Object* Builtin_##name(Arguments args) {      \
-    Handle<Object> receiver = args.at<Object>(0);
+#define BUILTIN(name)                                           \
+  static Object* Builtin_Impl_##name(name##ArgumentsType args); \
+  static Object* Builtin_##name(name##ArgumentsType args) {     \
+    args.Verify();                                              \
+    return Builtin_Impl_##name(args);                           \
+  }                                                             \
+  static Object* Builtin_Impl_##name(name##ArgumentsType args)
 
+#else  // For release mode.
 
-#define BUILTIN_END                             \
-  return Heap::undefined_value();               \
-}
+#define BUILTIN(name)                                           \
+  static Object* Builtin_##name(name##ArgumentsType args)
+
+#endif
 
 
 static inline bool CalledAsConstructor() {
@@ -126,13 +189,13 @@ Handle<Code> Builtins::GetCode(JavaScript id, bool* resolved) {
 
 BUILTIN(Illegal) {
   UNREACHABLE();
+  return Heap::undefined_value();  // Make compiler happy.
 }
-BUILTIN_END
 
 
 BUILTIN(EmptyFunction) {
+  return Heap::undefined_value();
 }
-BUILTIN_END
 
 
 BUILTIN(ArrayCodeGeneric) {
@@ -140,7 +203,7 @@ BUILTIN(ArrayCodeGeneric) {
 
   JSArray* array;
   if (CalledAsConstructor()) {
-    array = JSArray::cast(*receiver);
+    array = JSArray::cast(*args.receiver());
   } else {
     // Allocate the JS Array
     JSFunction* constructor =
@@ -194,11 +257,10 @@ BUILTIN(ArrayCodeGeneric) {
 
   return array;
 }
-BUILTIN_END
 
 
 BUILTIN(ArrayPush) {
-  JSArray* array = JSArray::cast(*receiver);
+  JSArray* array = JSArray::cast(*args.receiver());
   ASSERT(array->HasFastElements());
 
   // Make sure we have space for the elements.
@@ -233,11 +295,10 @@ BUILTIN(ArrayPush) {
   array->set_length(Smi::FromInt(new_length), SKIP_WRITE_BARRIER);
   return array->length();
 }
-BUILTIN_END
 
 
 BUILTIN(ArrayPop) {
-  JSArray* array = JSArray::cast(*receiver);
+  JSArray* array = JSArray::cast(*args.receiver());
   ASSERT(array->HasFastElements());
   Object* undefined = Heap::undefined_value();
 
@@ -265,7 +326,6 @@ BUILTIN(ArrayPop) {
 
   return top;
 }
-BUILTIN_END
 
 
 // -----------------------------------------------------------------------------
@@ -320,20 +380,20 @@ static inline Object* TypeCheck(int argc,
 }
 
 
-BUILTIN(HandleApiCall) {
-  HandleScope scope;
-  bool is_construct = CalledAsConstructor();
+template <bool is_construct>
+static Object* HandleApiCallHelper(
+    BuiltinArguments<NEEDS_CALLED_FUNCTION> args) {
+  ASSERT(is_construct == CalledAsConstructor());
 
-  // TODO(428): Remove use of static variable, handle API callbacks directly.
-  Handle<JSFunction> function =
-      Handle<JSFunction>(JSFunction::cast(Builtins::builtin_passed_function));
+  HandleScope scope;
+  Handle<JSFunction> function = args.called_function();
 
   if (is_construct) {
     Handle<FunctionTemplateInfo> desc =
         Handle<FunctionTemplateInfo>(
             FunctionTemplateInfo::cast(function->shared()->function_data()));
     bool pending_exception = false;
-    Factory::ConfigureInstance(desc, Handle<JSObject>::cast(receiver),
+    Factory::ConfigureInstance(desc, Handle<JSObject>::cast(args.receiver()),
                                &pending_exception);
     ASSERT(Top::has_pending_exception() == pending_exception);
     if (pending_exception) return Failure::Exception();
@@ -359,15 +419,13 @@ BUILTIN(HandleApiCall) {
     Object* data_obj = call_data->data();
     Object* result;
 
-    v8::Local<v8::Object> self =
-        v8::Utils::ToLocal(Handle<JSObject>::cast(receiver));
     Handle<Object> data_handle(data_obj);
     v8::Local<v8::Value> data = v8::Utils::ToLocal(data_handle);
     ASSERT(raw_holder->IsJSObject());
     v8::Local<v8::Function> callee = v8::Utils::ToLocal(function);
     Handle<JSObject> holder_handle(JSObject::cast(raw_holder));
     v8::Local<v8::Object> holder = v8::Utils::ToLocal(holder_handle);
-    LOG(ApiObjectAccess("call", JSObject::cast(*receiver)));
+    LOG(ApiObjectAccess("call", JSObject::cast(*args.receiver())));
     v8::Arguments new_args = v8::ImplementationUtilities::NewArguments(
         data,
         holder,
@@ -395,16 +453,26 @@ BUILTIN(HandleApiCall) {
     if (!is_construct || result->IsJSObject()) return result;
   }
 
-  return *receiver;
+  return *args.receiver();
+}
+
+
+BUILTIN(HandleApiCall) {
+  return HandleApiCallHelper<false>(args);
+}
+
+
+BUILTIN(HandleApiCallConstruct) {
+  return HandleApiCallHelper<true>(args);
 }
-BUILTIN_END
 
 
 // Helper function to handle calls to non-function objects created through the
 // API. The object can be called as either a constructor (using new) or just as
 // a function (without new).
-static Object* HandleApiCallAsFunctionOrConstructor(bool is_construct_call,
-                                                    Arguments args) {
+static Object* HandleApiCallAsFunctionOrConstructor(
+    bool is_construct_call,
+    BuiltinArguments<NO_EXTRA_ARGUMENTS> args) {
   // Non-functions are never called as constructors. Even if this is an object
   // called as a constructor the delegate call is not a construct call.
   ASSERT(!CalledAsConstructor());
@@ -412,7 +480,7 @@ static Object* HandleApiCallAsFunctionOrConstructor(bool is_construct_call,
   Handle<Object> receiver = args.at<Object>(0);
 
   // Get the object called.
-  JSObject* obj = JSObject::cast(*receiver);
+  JSObject* obj = JSObject::cast(*args.receiver());
 
   // Get the invocation callback from the function descriptor that was
   // used to create the called object.
@@ -432,12 +500,12 @@ static Object* HandleApiCallAsFunctionOrConstructor(bool is_construct_call,
   Object* result;
   { HandleScope scope;
     v8::Local<v8::Object> self =
-        v8::Utils::ToLocal(Handle<JSObject>::cast(receiver));
+        v8::Utils::ToLocal(Handle<JSObject>::cast(args.receiver()));
     Handle<Object> data_handle(data_obj);
     v8::Local<v8::Value> data = v8::Utils::ToLocal(data_handle);
     Handle<JSFunction> callee_handle(constructor);
     v8::Local<v8::Function> callee = v8::Utils::ToLocal(callee_handle);
-    LOG(ApiObjectAccess("call non-function", JSObject::cast(*receiver)));
+    LOG(ApiObjectAccess("call non-function", JSObject::cast(*args.receiver())));
     v8::Arguments new_args = v8::ImplementationUtilities::NewArguments(
         data,
         self,
@@ -471,7 +539,6 @@ static Object* HandleApiCallAsFunctionOrConstructor(bool is_construct_call,
 BUILTIN(HandleApiCallAsFunction) {
   return HandleApiCallAsFunctionOrConstructor(false, args);
 }
-BUILTIN_END
 
 
 // Handle calls to non-function objects created through the API. This delegate
@@ -479,14 +546,6 @@ BUILTIN_END
 BUILTIN(HandleApiCallAsConstructor) {
   return HandleApiCallAsFunctionOrConstructor(true, args);
 }
-BUILTIN_END
-
-
-// TODO(1238487): This is a nasty hack. We need to improve the way we
-// call builtins considerable to get rid of this and the hairy macros
-// in builtins.cc.
-Object* Builtins::builtin_passed_function;
-
 
 
 static void Generate_LoadIC_ArrayLength(MacroAssembler* masm) {
@@ -708,7 +767,7 @@ static void Generate_StubNoRegisters_DebugBreak(MacroAssembler* masm) {
 Object* Builtins::builtins_[builtin_count] = { NULL, };
 const char* Builtins::names_[builtin_count] = { NULL, };
 
-#define DEF_ENUM_C(name) FUNCTION_ADDR(Builtin_##name),
+#define DEF_ENUM_C(name, ignore) FUNCTION_ADDR(Builtin_##name),
   Address Builtins::c_functions_[cfunction_count] = {
     BUILTIN_LIST_C(DEF_ENUM_C)
   };
@@ -739,14 +798,16 @@ void Builtins::Setup(bool create_heap_objects) {
     const char* s_name;  // name is only used for generating log information.
     int name;
     Code::Flags flags;
+    BuiltinExtraArguments extra_args;
   };
 
-#define DEF_FUNCTION_PTR_C(name)         \
-    { FUNCTION_ADDR(Generate_Adaptor),   \
-      FUNCTION_ADDR(Builtin_##name),     \
-      #name,                             \
-      c_##name,                          \
-      Code::ComputeFlags(Code::BUILTIN)  \
+#define DEF_FUNCTION_PTR_C(name, extra_args) \
+    { FUNCTION_ADDR(Generate_Adaptor),            \
+      FUNCTION_ADDR(Builtin_##name),              \
+      #name,                                      \
+      c_##name,                                   \
+      Code::ComputeFlags(Code::BUILTIN),          \
+      extra_args                                  \
     },
 
 #define DEF_FUNCTION_PTR_A(name, kind, state)              \
@@ -754,7 +815,8 @@ void Builtins::Setup(bool create_heap_objects) {
       NULL,                                                \
       #name,                                               \
       name,                                                \
-      Code::ComputeFlags(Code::kind, NOT_IN_LOOP, state)   \
+      Code::ComputeFlags(Code::kind, NOT_IN_LOOP, state),  \
+      NO_EXTRA_ARGUMENTS                                   \
     },
 
   // Define array of pointers to generators and C builtin functions.
@@ -763,7 +825,8 @@ void Builtins::Setup(bool create_heap_objects) {
       BUILTIN_LIST_A(DEF_FUNCTION_PTR_A)
       BUILTIN_LIST_DEBUG_A(DEF_FUNCTION_PTR_A)
       // Terminator:
-      { NULL, NULL, NULL, builtin_count, static_cast<Code::Flags>(0) }
+      { NULL, NULL, NULL, builtin_count, static_cast<Code::Flags>(0),
+        NO_EXTRA_ARGUMENTS }
   };
 
 #undef DEF_FUNCTION_PTR_C
@@ -779,12 +842,12 @@ void Builtins::Setup(bool create_heap_objects) {
     if (create_heap_objects) {
       MacroAssembler masm(buffer, sizeof buffer);
       // Generate the code/adaptor.
-      typedef void (*Generator)(MacroAssembler*, int);
+      typedef void (*Generator)(MacroAssembler*, int, BuiltinExtraArguments);
       Generator g = FUNCTION_CAST<Generator>(functions[i].generator);
       // We pass all arguments to the generator, but it may not use all of
       // them.  This works because the first arguments are on top of the
       // stack.
-      g(&masm, functions[i].name);
+      g(&masm, functions[i].name, functions[i].extra_args);
       // Move the code into the object heap.
       CodeDesc desc;
       masm.GetCode(&desc);
index f0ceab6679835def58c66955f6708bc232285eca..418948f750d04e57edea191d22d82b6e90f09d72 100644 (file)
 namespace v8 {
 namespace internal {
 
-// Define list of builtins implemented in C.
-#define BUILTIN_LIST_C(V)                          \
-  V(Illegal)                                       \
-                                                   \
-  V(EmptyFunction)                                 \
-                                                   \
-  V(ArrayCodeGeneric)                              \
-                                                   \
-  V(ArrayPush)                                     \
-  V(ArrayPop)                                      \
-                                                   \
-  V(HandleApiCall)                                 \
-  V(HandleApiCallAsFunction)                       \
-  V(HandleApiCallAsConstructor)
+// Specifies extra arguments required by a C++ builtin.
+enum BuiltinExtraArguments {
+  NO_EXTRA_ARGUMENTS = 0,
+  NEEDS_CALLED_FUNCTION = 1
+};
+
+
+// Define list of builtins implemented in C++.
+#define BUILTIN_LIST_C(V)                                           \
+  V(Illegal, NO_EXTRA_ARGUMENTS)                                    \
+                                                                    \
+  V(EmptyFunction, NO_EXTRA_ARGUMENTS)                              \
+                                                                    \
+  V(ArrayCodeGeneric, NO_EXTRA_ARGUMENTS)                           \
+                                                                    \
+  V(ArrayPush, NO_EXTRA_ARGUMENTS)                                  \
+  V(ArrayPop, NO_EXTRA_ARGUMENTS)                                   \
+                                                                    \
+  V(HandleApiCall, NEEDS_CALLED_FUNCTION)                           \
+  V(HandleApiCallConstruct, NEEDS_CALLED_FUNCTION)                  \
+  V(HandleApiCallAsFunction, NO_EXTRA_ARGUMENTS)                    \
+  V(HandleApiCallAsConstructor, NO_EXTRA_ARGUMENTS)
 
 
 // Define list of builtins implemented in assembly.
@@ -52,6 +60,7 @@ namespace internal {
   V(ArgumentsAdaptorTrampoline, BUILTIN, UNINITIALIZED)                   \
   V(JSConstructCall,            BUILTIN, UNINITIALIZED)                   \
   V(JSConstructStubGeneric,     BUILTIN, UNINITIALIZED)                   \
+  V(JSConstructStubApi,         BUILTIN, UNINITIALIZED)                   \
   V(JSEntryTrampoline,          BUILTIN, UNINITIALIZED)                   \
   V(JSConstructEntryTrampoline, BUILTIN, UNINITIALIZED)                   \
                                                                           \
@@ -169,7 +178,7 @@ class Builtins : public AllStatic {
   static const char* Lookup(byte* pc);
 
   enum Name {
-#define DEF_ENUM_C(name) name,
+#define DEF_ENUM_C(name, ignore) name,
 #define DEF_ENUM_A(name, kind, state) name,
     BUILTIN_LIST_C(DEF_ENUM_C)
     BUILTIN_LIST_A(DEF_ENUM_A)
@@ -180,7 +189,7 @@ class Builtins : public AllStatic {
   };
 
   enum CFunctionId {
-#define DEF_ENUM_C(name) c_##name,
+#define DEF_ENUM_C(name, ignore) c_##name,
     BUILTIN_LIST_C(DEF_ENUM_C)
 #undef DEF_ENUM_C
     cfunction_count
@@ -212,8 +221,6 @@ class Builtins : public AllStatic {
   static Handle<Code> GetCode(JavaScript id, bool* resolved);
   static int NumberOfJavaScriptBuiltins() { return id_count; }
 
-  static Object* builtin_passed_function;
-
  private:
   // The external C++ functions called from the code.
   static Address c_functions_[cfunction_count];
@@ -226,9 +233,12 @@ class Builtins : public AllStatic {
   static const char* javascript_names_[id_count];
   static int javascript_argc_[id_count];
 
-  static void Generate_Adaptor(MacroAssembler* masm, CFunctionId id);
+  static void Generate_Adaptor(MacroAssembler* masm,
+                               CFunctionId id,
+                               BuiltinExtraArguments extra_args);
   static void Generate_JSConstructCall(MacroAssembler* masm);
   static void Generate_JSConstructStubGeneric(MacroAssembler* masm);
+  static void Generate_JSConstructStubApi(MacroAssembler* masm);
   static void Generate_JSEntryTrampoline(MacroAssembler* masm);
   static void Generate_JSConstructEntryTrampoline(MacroAssembler* masm);
   static void Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm);
index 2a80953eb146ce973f0f894cbb468d476d3ee3d4..a406350c7da7f4c8fb9dfdd25ac66c1892be2d40 100644 (file)
@@ -766,6 +766,8 @@ Handle<JSObject> Factory::NewArgumentsObject(Handle<Object> callee,
 Handle<JSFunction> Factory::CreateApiFunction(
     Handle<FunctionTemplateInfo> obj, ApiInstanceType instance_type) {
   Handle<Code> code = Handle<Code>(Builtins::builtin(Builtins::HandleApiCall));
+  Handle<Code> construct_stub =
+      Handle<Code>(Builtins::builtin(Builtins::JSConstructStubApi));
 
   int internal_field_count = 0;
   if (!obj->instance_template()->IsUndefined()) {
@@ -840,6 +842,7 @@ Handle<JSFunction> Factory::CreateApiFunction(
   }
 
   result->shared()->set_function_data(*obj);
+  result->shared()->set_construct_stub(*construct_stub);
   result->shared()->DontAdaptArguments();
 
   // Recursively copy parent templates' accessors, 'data' may be modified.
index d56c02de19c05460d462dac8e79df250a9ab23b2..2c5b1d1f58831c6c5530172d39bc757cb64cc866 100644 (file)
@@ -36,15 +36,36 @@ namespace internal {
 #define __ ACCESS_MASM(masm)
 
 
-void Builtins::Generate_Adaptor(MacroAssembler* masm, CFunctionId id) {
-  // TODO(428): Don't pass the function in a static variable.
-  ExternalReference passed = ExternalReference::builtin_passed_function();
-  __ mov(Operand::StaticVariable(passed), edi);
-
-  // The actual argument count has already been loaded into register
-  // eax, but JumpToRuntime expects eax to contain the number of
-  // arguments including the receiver.
-  __ inc(eax);
+void Builtins::Generate_Adaptor(MacroAssembler* masm,
+                                CFunctionId id,
+                                BuiltinExtraArguments extra_args) {
+  // ----------- S t a t e -------------
+  //  -- eax                : number of arguments excluding receiver
+  //  -- edi                : called function (only guaranteed when
+  //                          extra_args requires it)
+  //  -- esi                : context
+  //  -- esp[0]             : return address
+  //  -- esp[4]             : last argument
+  //  -- ...
+  //  -- esp[4 * argc]      : first argument (argc == eax)
+  //  -- esp[4 * (argc +1)] : receiver
+  // -----------------------------------
+
+  // Insert extra arguments.
+  int num_extra_args = 0;
+  if (extra_args == NEEDS_CALLED_FUNCTION) {
+    num_extra_args = 1;
+    Register scratch = ebx;
+    __ pop(scratch);  // Save return address.
+    __ push(edi);
+    __ push(scratch);  // Restore return address.
+  } else {
+    ASSERT(extra_args == NO_EXTRA_ARGUMENTS);
+  }
+
+  // JumpToRuntime expects eax to contain the number of arguments
+  // including the receiver and the extra arguments.
+  __ add(Operand(eax), Immediate(num_extra_args + 1));
   __ JumpToRuntime(ExternalReference(id));
 }
 
@@ -81,7 +102,8 @@ void Builtins::Generate_JSConstructCall(MacroAssembler* masm) {
 }
 
 
-void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
+static void Generate_JSConstructStubHelper(MacroAssembler* masm,
+                                           bool is_api_function) {
   // Enter a construct frame.
   __ EnterConstructFrame();
 
@@ -277,8 +299,17 @@ void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
   __ j(greater_equal, &loop);
 
   // Call the function.
-  ParameterCount actual(eax);
-  __ InvokeFunction(edi, actual, CALL_FUNCTION);
+  if (is_api_function) {
+    __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
+    Handle<Code> code = Handle<Code>(
+        Builtins::builtin(Builtins::HandleApiCallConstruct));
+    ParameterCount expected(0);
+    __ InvokeCode(code, expected, expected,
+                  RelocInfo::CODE_TARGET, CALL_FUNCTION);
+  } else {
+    ParameterCount actual(eax);
+    __ InvokeFunction(edi, actual, CALL_FUNCTION);
+  }
 
   // Restore context from the frame.
   __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
@@ -319,6 +350,16 @@ void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
 }
 
 
+void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
+  Generate_JSConstructStubHelper(masm, false);
+}
+
+
+void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) {
+  Generate_JSConstructStubHelper(masm, true);
+}
+
+
 static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
                                              bool is_construct) {
   // Clear the context before we push it when entering the JS frame.
index db46f3acf4d09ece8149726e257867b6542481c6..ef263fd0db7031d84ce922aa5990a1687a1a01ef 100644 (file)
@@ -241,7 +241,7 @@ void ExternalReferenceTable::PopulateTable() {
 
   static const RefTableEntry ref_table[] = {
   // Builtins
-#define DEF_ENTRY_C(name) \
+#define DEF_ENTRY_C(name, ignored) \
   { C_BUILTIN, \
     Builtins::c_##name, \
     "Builtins::" #name },
@@ -249,11 +249,11 @@ void ExternalReferenceTable::PopulateTable() {
   BUILTIN_LIST_C(DEF_ENTRY_C)
 #undef DEF_ENTRY_C
 
-#define DEF_ENTRY_C(name) \
+#define DEF_ENTRY_C(name, ignored) \
   { BUILTIN, \
     Builtins::name, \
     "Builtins::" #name },
-#define DEF_ENTRY_A(name, kind, state) DEF_ENTRY_C(name)
+#define DEF_ENTRY_A(name, kind, state) DEF_ENTRY_C(name, ignored)
 
   BUILTIN_LIST_C(DEF_ENTRY_C)
   BUILTIN_LIST_A(DEF_ENTRY_A)
@@ -396,10 +396,6 @@ void ExternalReferenceTable::PopulateTable() {
       "V8::RandomPositiveSmi");
 
   // Miscellaneous
-  Add(ExternalReference::builtin_passed_function().address(),
-      UNCLASSIFIED,
-      1,
-      "Builtins::builtin_passed_function");
   Add(ExternalReference::the_hole_value_location().address(),
       UNCLASSIFIED,
       2,
index f444d2cf85f5ca2d56dd14e531d7dd0fabfe85c9..0b95bba60806991115769df27881d4372820fb2b 100644 (file)
@@ -34,16 +34,36 @@ namespace internal {
 
 #define __ ACCESS_MASM(masm)
 
-void Builtins::Generate_Adaptor(MacroAssembler* masm, CFunctionId id) {
-  // TODO(428): Don't pass the function in a static variable.
-  ExternalReference passed = ExternalReference::builtin_passed_function();
-  __ movq(kScratchRegister, passed.address(), RelocInfo::EXTERNAL_REFERENCE);
-  __ movq(Operand(kScratchRegister, 0), rdi);
-
-  // The actual argument count has already been loaded into register
-  // rax, but JumpToRuntime expects rax to contain the number of
-  // arguments including the receiver.
-  __ incq(rax);
+
+void Builtins::Generate_Adaptor(MacroAssembler* masm,
+                                CFunctionId id,
+                                BuiltinExtraArguments extra_args) {
+  // ----------- S t a t e -------------
+  //  -- rax                : number of arguments excluding receiver
+  //  -- rdi                : called function (only guaranteed when
+  //                          extra_args requires it)
+  //  -- rsi                : context
+  //  -- rsp[0]             : return address
+  //  -- rsp[8]             : last argument
+  //  -- ...
+  //  -- rsp[8 * argc]      : first argument (argc == rax)
+  //  -- rsp[8 * (argc +1)] : receiver
+  // -----------------------------------
+
+  // Insert extra arguments.
+  int num_extra_args = 0;
+  if (extra_args == NEEDS_CALLED_FUNCTION) {
+    num_extra_args = 1;
+    __ pop(kScratchRegister);  // Save return address.
+    __ push(rdi);
+    __ push(kScratchRegister);  // Restore return address.
+  } else {
+    ASSERT(extra_args == NO_EXTRA_ARGUMENTS);
+  }
+
+  // JumpToRuntime expects rax to contain the number of arguments
+  // including the receiver and the extra arguments.
+  __ addq(rax, Immediate(num_extra_args + 1));
   __ JumpToRuntime(ExternalReference(id), 1);
 }
 
@@ -888,7 +908,8 @@ void Builtins::Generate_JSConstructCall(MacroAssembler* masm) {
 }
 
 
-void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
+static void Generate_JSConstructStubHelper(MacroAssembler* masm,
+                                           bool is_api_function) {
     // Enter a construct frame.
   __ EnterConstructFrame();
 
@@ -1091,8 +1112,17 @@ void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
   __ j(greater_equal, &loop);
 
   // Call the function.
-  ParameterCount actual(rax);
-  __ InvokeFunction(rdi, actual, CALL_FUNCTION);
+  if (is_api_function) {
+    __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
+    Handle<Code> code = Handle<Code>(
+        Builtins::builtin(Builtins::HandleApiCallConstruct));
+    ParameterCount expected(0);
+    __ InvokeCode(code, expected, expected,
+                  RelocInfo::CODE_TARGET, CALL_FUNCTION);
+  } else {
+    ParameterCount actual(rax);
+    __ InvokeFunction(rdi, actual, CALL_FUNCTION);
+  }
 
   // Restore context from the frame.
   __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
@@ -1129,6 +1159,16 @@ void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
 }
 
 
+void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
+  Generate_JSConstructStubHelper(masm, false);
+}
+
+
+void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) {
+  Generate_JSConstructStubHelper(masm, true);
+}
+
+
 static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
                                              bool is_construct) {
   // Expects five C++ function parameters.
index 3db7c37f1cd60bcaf4d5a31894dbdae9d2ba0809..f948cd3194f9a6b649283ee795f02566bdd2dbf6 100644 (file)
@@ -4895,8 +4895,7 @@ THREADED_TEST(CallAsFunction) {
   CHECK_EQ(17, value->Int32Value());
 
   // Check that the call-as-function handler can be called through
-  // new.  Currently, there is no way to check in the call-as-function
-  // handler if it has been called through new or not.
+  // new.
   value = CompileRun("new obj(43)");
   CHECK(!try_catch.HasCaught());
   CHECK_EQ(-43, value->Int32Value());
index d02972b83ab8fc0566d0f572c2715ec3dba8d4bf..9961281418f4131a02af4f8c4e4bd515b0b551a2 100644 (file)
@@ -117,10 +117,6 @@ TEST(ExternalReferenceEncoder) {
       ExternalReference(&Counters::keyed_load_function_prototype);
   CHECK_EQ(make_code(STATS_COUNTER, Counters::k_keyed_load_function_prototype),
            encoder.Encode(keyed_load_function_prototype.address()));
-  ExternalReference passed_function =
-      ExternalReference::builtin_passed_function();
-  CHECK_EQ(make_code(UNCLASSIFIED, 1),
-           encoder.Encode(passed_function.address()));
   ExternalReference the_hole_value_location =
       ExternalReference::the_hole_value_location();
   CHECK_EQ(make_code(UNCLASSIFIED, 2),
@@ -160,8 +156,6 @@ TEST(ExternalReferenceDecoder) {
            decoder.Decode(
                make_code(STATS_COUNTER,
                          Counters::k_keyed_load_function_prototype)));
-  CHECK_EQ(ExternalReference::builtin_passed_function().address(),
-           decoder.Decode(make_code(UNCLASSIFIED, 1)));
   CHECK_EQ(ExternalReference::the_hole_value_location().address(),
            decoder.Decode(make_code(UNCLASSIFIED, 2)));
   CHECK_EQ(ExternalReference::address_of_stack_limit().address(),