#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));
}
}
-void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
+static void Generate_JSConstructStubHelper(MacroAssembler* masm,
+ bool is_api_function) {
// Enter a construct frame.
__ EnterConstructFrame();
// 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
}
+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
}
-ExternalReference ExternalReference::builtin_passed_function() {
- return ExternalReference(&Builtins::builtin_passed_function);
-}
-
-
ExternalReference ExternalReference::random_positive_smi_function() {
return ExternalReference(Redirect(FUNCTION_ADDR(V8::RandomPositiveSmi)));
}
// 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.
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:
// 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() {
BUILTIN(Illegal) {
UNREACHABLE();
+ return Heap::undefined_value(); // Make compiler happy.
}
-BUILTIN_END
BUILTIN(EmptyFunction) {
+ return Heap::undefined_value();
}
-BUILTIN_END
BUILTIN(ArrayCodeGeneric) {
JSArray* array;
if (CalledAsConstructor()) {
- array = JSArray::cast(*receiver);
+ array = JSArray::cast(*args.receiver());
} else {
// Allocate the JS Array
JSFunction* constructor =
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.
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();
return top;
}
-BUILTIN_END
// -----------------------------------------------------------------------------
}
-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();
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,
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());
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.
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,
BUILTIN(HandleApiCallAsFunction) {
return HandleApiCallAsFunctionOrConstructor(false, args);
}
-BUILTIN_END
// Handle calls to non-function objects created through the API. This delegate
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) {
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)
};
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) \
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.
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
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);
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.
V(ArgumentsAdaptorTrampoline, BUILTIN, UNINITIALIZED) \
V(JSConstructCall, BUILTIN, UNINITIALIZED) \
V(JSConstructStubGeneric, BUILTIN, UNINITIALIZED) \
+ V(JSConstructStubApi, BUILTIN, UNINITIALIZED) \
V(JSEntryTrampoline, BUILTIN, UNINITIALIZED) \
V(JSConstructEntryTrampoline, BUILTIN, UNINITIALIZED) \
\
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)
};
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
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];
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);
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()) {
}
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.
#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));
}
}
-void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
+static void Generate_JSConstructStubHelper(MacroAssembler* masm,
+ bool is_api_function) {
// Enter a construct frame.
__ EnterConstructFrame();
__ 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));
}
+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.
static const RefTableEntry ref_table[] = {
// Builtins
-#define DEF_ENTRY_C(name) \
+#define DEF_ENTRY_C(name, ignored) \
{ C_BUILTIN, \
Builtins::c_##name, \
"Builtins::" #name },
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)
"V8::RandomPositiveSmi");
// Miscellaneous
- Add(ExternalReference::builtin_passed_function().address(),
- UNCLASSIFIED,
- 1,
- "Builtins::builtin_passed_function");
Add(ExternalReference::the_hole_value_location().address(),
UNCLASSIFIED,
2,
#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);
}
}
-void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
+static void Generate_JSConstructStubHelper(MacroAssembler* masm,
+ bool is_api_function) {
// Enter a construct frame.
__ EnterConstructFrame();
__ 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));
}
+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.
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());
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),
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(),