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