Commit bd06358b authored by vitalyr@chromium.org's avatar vitalyr@chromium.org

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3613 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 1cc579ff
......@@ -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
......
......@@ -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)));
}
......
......@@ -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.
......
This diff is collapsed.
......@@ -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 @@ 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);
......
......@@ -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.
......
......@@ -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.
......
......@@ -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,
......
......@@ -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.
......
......@@ -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());
......
......@@ -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(),
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment