Stop adapting the arguments passed to the builtin implementations

of Array.prototype.push and Array.prototype.pop. Avoid going 
through the arguments adaptor trampoline for call ICs that end
up calling a builtin that does not need arguments adaption.
Review URL: http://codereview.chromium.org/2884

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@312 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
kasperl@chromium.org 2008-09-16 07:24:46 +00:00
parent 64923a6a83
commit 3f67d5b90f
8 changed files with 71 additions and 44 deletions

View File

@ -291,8 +291,7 @@ class Genesis BASE_EMBEDDED {
void AddSpecialFunction(Handle<JSObject> prototype, void AddSpecialFunction(Handle<JSObject> prototype,
const char* name, const char* name,
Handle<Code> code, Handle<Code> code);
int parameter_count);
void BuildSpecialFunctionTable(); void BuildSpecialFunctionTable();
@ -1266,8 +1265,7 @@ void Genesis::MakeFunctionInstancePrototypeWritable() {
void Genesis::AddSpecialFunction(Handle<JSObject> prototype, void Genesis::AddSpecialFunction(Handle<JSObject> prototype,
const char* name, const char* name,
Handle<Code> code, Handle<Code> code) {
int parameter_count) {
Handle<String> key = Factory::LookupAsciiSymbol(name); Handle<String> key = Factory::LookupAsciiSymbol(name);
Handle<Object> value = Handle<Object>(prototype->GetProperty(*key)); Handle<Object> value = Handle<Object>(prototype->GetProperty(*key));
if (value->IsJSFunction()) { if (value->IsJSFunction()) {
@ -1276,7 +1274,7 @@ void Genesis::AddSpecialFunction(Handle<JSObject> prototype,
JSObject::kHeaderSize, JSObject::kHeaderSize,
code, code,
false); false);
optimized->shared()->set_formal_parameter_count(parameter_count); optimized->shared()->DontAdaptArguments();
int len = global_context()->special_function_table()->length(); int len = global_context()->special_function_table()->length();
Handle<FixedArray> new_array = Factory::NewFixedArray(len + 3); Handle<FixedArray> new_array = Factory::NewFixedArray(len + 3);
for (int index = 0; index < len; index++) { for (int index = 0; index < len; index++) {
@ -1301,11 +1299,9 @@ void Genesis::BuildSpecialFunctionTable() {
Handle<JSObject> prototype = Handle<JSObject> prototype =
Handle<JSObject>(JSObject::cast(function->prototype())); Handle<JSObject>(JSObject::cast(function->prototype()));
AddSpecialFunction(prototype, "pop", AddSpecialFunction(prototype, "pop",
Handle<Code>(Builtins::builtin(Builtins::ArrayPop)), Handle<Code>(Builtins::builtin(Builtins::ArrayPop)));
0);
AddSpecialFunction(prototype, "push", AddSpecialFunction(prototype, "push",
Handle<Code>(Builtins::builtin(Builtins::ArrayPush)), Handle<Code>(Builtins::builtin(Builtins::ArrayPush)));
1);
} }

View File

@ -40,12 +40,21 @@ namespace v8 { namespace internal {
void Builtins::Generate_Adaptor(MacroAssembler* masm, void Builtins::Generate_Adaptor(MacroAssembler* masm,
int argc, int argc,
CFunctionId id) { CFunctionId id) {
// r0 contains the number of arguments excluding the receiver. // TODO(1238487): Don't pass the function in a static variable.
// JumpToBuiltin expects r0 to contains the number of arguments
// including the receiver.
__ mov(r0, Operand(argc + 1));
__ mov(ip, Operand(ExternalReference::builtin_passed_function())); __ mov(ip, Operand(ExternalReference::builtin_passed_function()));
__ str(r1, MemOperand(ip, 0)); __ str(r1, MemOperand(ip, 0));
if (argc == -1) {
// The actual argument count has already been loaded into register
// r0, but JumpToBuiltin expects r0 to contain the number of
// arguments including the receiver.
__ add(r0, r0, Operand(1));
} else {
// The number passed in argc excludes the receiver, but
// JumpToBuiltin expects r0 to contain the number of arguments
// including the receiver.
__ mov(r0, Operand(argc + 1));
}
__ JumpToBuiltin(ExternalReference(id)); __ JumpToBuiltin(ExternalReference(id));
} }

View File

@ -40,12 +40,21 @@ namespace v8 { namespace internal {
void Builtins::Generate_Adaptor(MacroAssembler* masm, void Builtins::Generate_Adaptor(MacroAssembler* masm,
int argc, int argc,
CFunctionId id) { CFunctionId id) {
// argc is the number of arguments excluding the receiver. // TODO(1238487): Don't pass the function in a static variable.
// JumpToBuiltin expects eax to contain the number of arguments ExternalReference passed = ExternalReference::builtin_passed_function();
// including the receiver. __ mov(Operand::StaticVariable(passed), edi);
__ mov(eax, argc + 1);
__ mov(Operand::StaticVariable(ExternalReference::builtin_passed_function()), if (argc == -1) {
edi); // The actual argument count has already been loaded into register
// eax, but JumpToBuiltin expects eax to contain the number of
// arguments including the receiver.
__ inc(eax);
} else {
// The number passed in argc excludes the receiver, but
// JumpToBuiltin expects eax to contain the number of arguments
// including the receiver.
__ mov(eax, argc + 1);
}
__ JumpToBuiltin(ExternalReference(id)); __ JumpToBuiltin(ExternalReference(id));
} }

View File

@ -67,7 +67,7 @@ namespace v8 { namespace internal {
// and start calling the builtins in a more direct way. Looking at the // and start calling the builtins in a more direct way. Looking at the
// stack frames for all builtin invocations comes with a pretty // stack frames for all builtin invocations comes with a pretty
// significant performance penalty. // significant performance penalty.
#define BUILTIN_0(name) \ #define BUILTIN(name) \
static Object* Builtin_##name(int __argc__, \ static Object* Builtin_##name(int __argc__, \
Object** __argv__) { \ Object** __argv__) { \
Handle<Object> receiver(&__argv__[0]); \ Handle<Object> receiver(&__argv__[0]); \
@ -95,19 +95,13 @@ namespace v8 { namespace internal {
} }
#define BUILTIN_1(name, a0) \ // We're transitioning to a much simpler builtins framework where all
BUILTIN_0(name) \ // builtins are called *without* arguments adaption. For now, only a
Object* a0 = BUILTIN_ARG(1); // few of the builtins have been rewritten to support this and they
// all use the NEW_BUILTIN macro instead of plain old BUILTIN.
#define NEW_BUILTIN(name) \
#define BUILTIN_2(name, a0, a1) \ static Object* Builtin_##name(int __argc__, Object** __argv__) { \
BUILTIN_1(name, a0) \ Handle<Object> receiver(&__argv__[0]);
Object* a1 = BUILTIN_ARG(2);
#define BUILTIN_3(name, a0, a1, a2) \
BUILTIN_2(name, a0, a1) \
Object* a2 = BUILTIN_ARG(3);
// Use an inline function to avoid evaluating the index (n) more than // Use an inline function to avoid evaluating the index (n) more than
@ -172,18 +166,18 @@ Handle<Code> Builtins::GetCode(JavaScript id, bool* resolved) {
} }
BUILTIN_0(Illegal) { BUILTIN(Illegal) {
UNREACHABLE(); UNREACHABLE();
} }
BUILTIN_END BUILTIN_END
BUILTIN_0(EmptyFunction) { BUILTIN(EmptyFunction) {
} }
BUILTIN_END BUILTIN_END
BUILTIN_0(ArrayCode) { BUILTIN(ArrayCode) {
JSArray* array; JSArray* array;
if (is_construct) { if (is_construct) {
array = JSArray::cast(*receiver); array = JSArray::cast(*receiver);
@ -241,7 +235,7 @@ BUILTIN_0(ArrayCode) {
BUILTIN_END BUILTIN_END
BUILTIN_0(ArrayPush) { NEW_BUILTIN(ArrayPush) {
JSArray* array = JSArray::cast(*receiver); JSArray* array = JSArray::cast(*receiver);
ASSERT(array->HasFastElements()); ASSERT(array->HasFastElements());
@ -280,7 +274,7 @@ BUILTIN_0(ArrayPush) {
BUILTIN_END BUILTIN_END
BUILTIN_0(ArrayPop) { NEW_BUILTIN(ArrayPop) {
JSArray* array = JSArray::cast(*receiver); JSArray* array = JSArray::cast(*receiver);
ASSERT(array->HasFastElements()); ASSERT(array->HasFastElements());
Object* undefined = Heap::undefined_value(); Object* undefined = Heap::undefined_value();
@ -365,7 +359,7 @@ static inline Object* TypeCheck(int argc,
} }
BUILTIN_0(HandleApiCall) { BUILTIN(HandleApiCall) {
HandleScope scope; HandleScope scope;
// TODO(1238487): This is not nice. We need to get rid of this // TODO(1238487): This is not nice. We need to get rid of this
@ -445,7 +439,7 @@ BUILTIN_END
// Handle calls to non-function objects created through the API that // Handle calls to non-function objects created through the API that
// support calls. // support calls.
BUILTIN_0(HandleApiCallAsFunction) { BUILTIN(HandleApiCallAsFunction) {
// Non-functions are never called as constructors. // Non-functions are never called as constructors.
ASSERT(!is_construct); ASSERT(!is_construct);

View File

@ -38,8 +38,8 @@ namespace v8 { namespace internal {
\ \
V(ArrayCode, 0) \ V(ArrayCode, 0) \
\ \
V(ArrayPush, 1) \ V(ArrayPush, -1) \
V(ArrayPop, 0) \ V(ArrayPop, -1) \
\ \
V(HandleApiCall, 0) \ V(HandleApiCall, 0) \
V(HandleApiCallAsFunction, 0) V(HandleApiCallAsFunction, 0)

View File

@ -299,7 +299,16 @@ void MacroAssembler::InvokePrologue(const ParameterCount& expected,
definitely_matches = true; definitely_matches = true;
} else { } else {
mov(r0, Operand(actual.immediate())); mov(r0, Operand(actual.immediate()));
mov(r2, Operand(expected.immediate())); const int sentinel = SharedFunctionInfo::kDontAdaptArgumentsSentinel;
if (expected.immediate() == sentinel) {
// Don't worry about adapting arguments for builtins that
// don't want that done. Skip adaption code by making it look
// like we have a match between expected and actual number of
// arguments.
definitely_matches = true;
} else {
mov(r2, Operand(expected.immediate()));
}
} }
} else { } else {
if (actual.is_immediate()) { if (actual.is_immediate()) {

View File

@ -572,7 +572,16 @@ void MacroAssembler::InvokePrologue(const ParameterCount& expected,
definitely_matches = true; definitely_matches = true;
} else { } else {
mov(eax, actual.immediate()); mov(eax, actual.immediate());
mov(ebx, expected.immediate()); const int sentinel = SharedFunctionInfo::kDontAdaptArgumentsSentinel;
if (expected.immediate() == sentinel) {
// Don't worry about adapting arguments for builtins that
// don't want that done. Skip adaption code by making it look
// like we have a match between expected and actual number of
// arguments.
definitely_matches = true;
} else {
mov(ebx, expected.immediate());
}
} }
} else { } else {
if (actual.is_immediate()) { if (actual.is_immediate()) {

View File

@ -1783,6 +1783,7 @@ INT_ACCESSORS(SharedFunctionInfo, function_token_position,
void SharedFunctionInfo::DontAdaptArguments() { void SharedFunctionInfo::DontAdaptArguments() {
ASSERT(code()->kind() == Code::BUILTIN);
set_formal_parameter_count(kDontAdaptArgumentsSentinel); set_formal_parameter_count(kDontAdaptArgumentsSentinel);
} }