Revision: 3613
Author: [email protected]
Date: Fri Jan 15 04:25:24 2010
Log: Optimized calling of C++ builtins (and HandleApiCall
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
http://code.google.com/p/v8/source/detail?r=3613

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

=======================================
--- /branches/bleeding_edge/src/arm/builtins-arm.cc     Thu Nov 12 05:55:21 2009
+++ /branches/bleeding_edge/src/arm/builtins-arm.cc     Fri Jan 15 04:25:24 2010
@@ -38,15 +38,32 @@
 #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_JSConstructStubGeneric(MacroAssembler* masm) {
+static void Generate_JSConstructStubHelper(MacroAssembler* masm,
+                                           bool is_api_function) {
   // Enter a construct frame.
   __ EnterConstructFrame();

@@ -727,8 +745,17 @@
   // 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
@@ -781,6 +808,16 @@
   __ IncrementCounter(&Counters::constructed_objects, 1, r1, r2);
   __ Jump(lr);
 }
+
+
+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,
=======================================
--- /branches/bleeding_edge/src/assembler.cc    Wed Jan  6 03:09:30 2010
+++ /branches/bleeding_edge/src/assembler.cc    Fri Jan 15 04:25:24 2010
@@ -561,11 +561,6 @@
 ExternalReference ExternalReference::perform_gc_function() {
   return ExternalReference(Redirect(FUNCTION_ADDR(Runtime::PerformGC)));
 }
-
-
-ExternalReference ExternalReference::builtin_passed_function() {
-  return ExternalReference(&Builtins::builtin_passed_function);
-}


 ExternalReference ExternalReference::random_positive_smi_function() {
=======================================
--- /branches/bleeding_edge/src/assembler.h     Wed Jan  6 03:09:30 2010
+++ /branches/bleeding_edge/src/assembler.h     Fri Jan 15 04:25:24 2010
@@ -398,7 +398,6 @@
   // 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.
=======================================
--- /branches/bleeding_edge/src/builtins.cc     Thu Jan  7 02:25:20 2010
+++ /branches/bleeding_edge/src/builtins.cc     Fri Jan 15 04:25:24 2010
@@ -36,8 +36,75 @@
 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 @@
 //   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.
-// ----------------------------------------------------------------------------
-
-
-// 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_END                             \
-  return Heap::undefined_value();               \
-}
+// In the body of the builtin function the arguments can be accessed
+// through the BuiltinArguments object args.
+
+#ifdef DEBUG
+
+#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(name)                                           \
+  static Object* Builtin_##name(name##ArgumentsType args)
+
+#endif


 static inline bool CalledAsConstructor() {
@@ -126,13 +189,13 @@

 BUILTIN(Illegal) {
   UNREACHABLE();
-}
-BUILTIN_END
+  return Heap::undefined_value();  // Make compiler happy.
+}


 BUILTIN(EmptyFunction) {
-}
-BUILTIN_END
+  return Heap::undefined_value();
+}


 BUILTIN(ArrayCodeGeneric) {
@@ -140,7 +203,7 @@

   JSArray* array;
   if (CalledAsConstructor()) {
-    array = JSArray::cast(*receiver);
+    array = JSArray::cast(*args.receiver());
   } else {
     // Allocate the JS Array
     JSFunction* constructor =
@@ -194,11 +257,10 @@

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

   return top;
 }
-BUILTIN_END


// -----------------------------------------------------------------------------
@@ -320,20 +380,20 @@
 }


-BUILTIN(HandleApiCall) {
+template <bool is_construct>
+static Object* HandleApiCallHelper(
+    BuiltinArguments<NEEDS_CALLED_FUNCTION> args) {
+  ASSERT(is_construct == CalledAsConstructor());
+
   HandleScope scope;
-  bool 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));
+  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 @@
     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 @@
     if (!is_construct || result->IsJSObject()) return result;
   }

-  return *receiver;
-}
-BUILTIN_END
+  return *args.receiver();
+}
+
+
+BUILTIN(HandleApiCall) {
+  return HandleApiCallHelper<false>(args);
+}
+
+
+BUILTIN(HandleApiCallConstruct) {
+  return HandleApiCallHelper<true>(args);
+}


// 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 @@
   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 @@
   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 @@
 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(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 @@
 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 @@
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 @@
       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 @@
       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 @@
     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);
=======================================
--- /branches/bleeding_edge/src/builtins.h      Thu Jan  7 02:25:20 2010
+++ /branches/bleeding_edge/src/builtins.h      Fri Jan 15 04:25:24 2010
@@ -31,20 +31,28 @@
 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 @@
   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 @@
   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 @@
   };

   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
@@ -211,8 +220,6 @@
static int GetArgumentsCount(JavaScript id) { return javascript_argc_[id]; }
   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.
@@ -226,9 +233,12 @@
   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);
=======================================
--- /branches/bleeding_edge/src/factory.cc      Wed Dec 16 07:43:20 2009
+++ /branches/bleeding_edge/src/factory.cc      Fri Jan 15 04:25:24 2010
@@ -766,6 +766,8 @@
 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 @@
   }

   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.
=======================================
--- /branches/bleeding_edge/src/ia32/builtins-ia32.cc Fri Dec 18 03:13:33 2009 +++ /branches/bleeding_edge/src/ia32/builtins-ia32.cc Fri Jan 15 04:25:24 2010
@@ -36,15 +36,36 @@
 #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_JSConstructStubGeneric(MacroAssembler* masm) {
+static void Generate_JSConstructStubHelper(MacroAssembler* masm,
+                                           bool is_api_function) {
   // Enter a construct frame.
   __ EnterConstructFrame();

@@ -277,8 +299,17 @@
   __ 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));
@@ -317,6 +348,16 @@
   __ IncrementCounter(&Counters::constructed_objects, 1);
   __ ret(0);
 }
+
+
+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,
=======================================
--- /branches/bleeding_edge/src/serialize.cc    Thu Jan 14 06:46:31 2010
+++ /branches/bleeding_edge/src/serialize.cc    Fri Jan 15 04:25:24 2010
@@ -241,7 +241,7 @@

   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 @@
   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 @@
       "V8::RandomPositiveSmi");

   // Miscellaneous
-  Add(ExternalReference::builtin_passed_function().address(),
-      UNCLASSIFIED,
-      1,
-      "Builtins::builtin_passed_function");
   Add(ExternalReference::the_hole_value_location().address(),
       UNCLASSIFIED,
       2,
=======================================
--- /branches/bleeding_edge/src/x64/builtins-x64.cc     Thu Nov  5 05:59:40 2009
+++ /branches/bleeding_edge/src/x64/builtins-x64.cc     Fri Jan 15 04:25:24 2010
@@ -34,16 +34,36 @@

 #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_JSConstructStubGeneric(MacroAssembler* masm) {
+static void Generate_JSConstructStubHelper(MacroAssembler* masm,
+                                           bool is_api_function) {
     // Enter a construct frame.
   __ EnterConstructFrame();

@@ -1091,8 +1112,17 @@
   __ 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));
@@ -1127,6 +1157,16 @@
   __ IncrementCounter(&Counters::constructed_objects, 1);
   __ ret(0);
 }
+
+
+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,
=======================================
--- /branches/bleeding_edge/test/cctest/test-api.cc     Mon Jan 11 04:13:24 2010
+++ /branches/bleeding_edge/test/cctest/test-api.cc     Fri Jan 15 04:25:24 2010
@@ -4895,8 +4895,7 @@
   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());
=======================================
--- /branches/bleeding_edge/test/cctest/test-serialize.cc Thu Jan 14 06:46:31 2010 +++ /branches/bleeding_edge/test/cctest/test-serialize.cc Fri Jan 15 04:25:24 2010
@@ -117,10 +117,6 @@
       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 @@
            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(),
-- 
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to