From 6af6a82ae3793ebb737ab6f74dadfb280d8bd2a9 Mon Sep 17 00:00:00 2001 From: "kmillikin@chromium.org" Date: Thu, 17 Dec 2009 10:23:20 +0000 Subject: [PATCH] Streamline the calling convention of the call ICs by passing the property name in a register rather than on the stack below the receiver and arguments. Implemented only for IA32, passing the name in the ecx register to match the calling convention of the load ICs. Review URL: http://codereview.chromium.org/502028 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3484 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/arm/fast-codegen-arm.cc | 10 ++-- src/arm/ic-arm.cc | 10 ++-- src/fast-codegen.h | 2 +- src/ia32/builtins-ia32.cc | 47 +++++++++--------- src/ia32/codegen-ia32.cc | 23 +++++---- src/ia32/fast-codegen-ia32.cc | 39 +++++++-------- src/ia32/ic-ia32.cc | 75 +++++++++++++++++------------ src/ia32/stub-cache-ia32.cc | 87 +++++++++++++++++++++------------- src/ia32/virtual-frame-ia32.cc | 11 +++-- src/ia32/virtual-frame-ia32.h | 6 +-- src/ic.cc | 10 ---- src/ic.h | 8 ++-- src/x64/fast-codegen-x64.cc | 10 ++-- src/x64/ic-x64.cc | 10 ++-- 14 files changed, 186 insertions(+), 162 deletions(-) diff --git a/src/arm/fast-codegen-arm.cc b/src/arm/fast-codegen-arm.cc index 42b3bf3e51..55d87b7c2d 100644 --- a/src/arm/fast-codegen-arm.cc +++ b/src/arm/fast-codegen-arm.cc @@ -1080,7 +1080,9 @@ void FastCodeGenerator::VisitProperty(Property* expr) { DropAndMove(expr->context(), r0); } -void FastCodeGenerator::EmitCallWithIC(Call* expr, RelocInfo::Mode reloc_info) { +void FastCodeGenerator::EmitCallWithIC(Call* expr, + Handle ignored, + RelocInfo::Mode mode) { // Code common for calls using the IC. ZoneList* args = expr->arguments(); int arg_count = args->length(); @@ -1093,7 +1095,7 @@ void FastCodeGenerator::EmitCallWithIC(Call* expr, RelocInfo::Mode reloc_info) { // Call the IC initialization code. Handle ic = CodeGenerator::ComputeCallInitialize(arg_count, NOT_IN_LOOP); - __ Call(ic, reloc_info); + __ Call(ic, mode); // Restore context register. __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); // Discard the function left on TOS. @@ -1133,7 +1135,7 @@ void FastCodeGenerator::VisitCall(Call* expr) { // Push global object as receiver for the call IC lookup. __ ldr(r0, CodeGenerator::GlobalObject()); __ stm(db_w, sp, r1.bit() | r0.bit()); - EmitCallWithIC(expr, RelocInfo::CODE_TARGET_CONTEXT); + EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT); } else if (var != NULL && var->slot() != NULL && var->slot()->type() == Slot::LOOKUP) { // Call to a lookup slot. @@ -1147,7 +1149,7 @@ void FastCodeGenerator::VisitCall(Call* expr) { __ mov(r0, Operand(key->handle())); __ push(r0); Visit(prop->obj()); - EmitCallWithIC(expr, RelocInfo::CODE_TARGET); + EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET); } else { // Call to a keyed property, use keyed load IC followed by function // call. diff --git a/src/arm/ic-arm.cc b/src/arm/ic-arm.cc index c56f414a14..b57aa93967 100644 --- a/src/arm/ic-arm.cc +++ b/src/arm/ic-arm.cc @@ -276,7 +276,7 @@ void CallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) { // Cache miss: Jump to runtime. __ bind(&miss); - Generate(masm, argc, ExternalReference(IC_Utility(kCallIC_Miss))); + GenerateMiss(masm, argc); } @@ -371,13 +371,11 @@ void CallIC::GenerateNormal(MacroAssembler* masm, int argc) { // Cache miss: Jump to runtime. __ bind(&miss); - Generate(masm, argc, ExternalReference(IC_Utility(kCallIC_Miss))); + GenerateMiss(masm, argc); } -void CallIC::Generate(MacroAssembler* masm, - int argc, - const ExternalReference& f) { +void CallIC::GenerateMiss(MacroAssembler* masm, int argc) { // ----------- S t a t e ------------- // -- lr: return address // ----------------------------------- @@ -394,7 +392,7 @@ void CallIC::Generate(MacroAssembler* masm, // Call the entry. __ mov(r0, Operand(2)); - __ mov(r1, Operand(f)); + __ mov(r1, Operand(ExternalReference(IC_Utility(kCallIC_Miss)))); CEntryStub stub(1); __ CallStub(&stub); diff --git a/src/fast-codegen.h b/src/fast-codegen.h index 1ce759d7a6..54f0df1152 100644 --- a/src/fast-codegen.h +++ b/src/fast-codegen.h @@ -240,7 +240,7 @@ class FastCodeGenerator: public AstVisitor { // Platform-specific code sequences for calls void EmitCallWithStub(Call* expr); - void EmitCallWithIC(Call* expr, RelocInfo::Mode reloc_info); + void EmitCallWithIC(Call* expr, Handle name, RelocInfo::Mode mode); // Platform-specific code for loading variables. void EmitVariableLoad(Variable* expr, Expression::Context context); diff --git a/src/ia32/builtins-ia32.cc b/src/ia32/builtins-ia32.cc index a164cfa85c..f4dd2f931d 100644 --- a/src/ia32/builtins-ia32.cc +++ b/src/ia32/builtins-ia32.cc @@ -472,35 +472,38 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) { __ bind(&done); } - // 4. Shift stuff one slot down the stack. + // 4. Check that the function really is a function. + { Label done; + __ test(edi, Operand(edi)); + __ j(not_zero, &done, taken); + __ xor_(ebx, Operand(ebx)); + // CALL_NON_FUNCTION will expect to find the non-function callee on the + // expression stack of the caller. Transfer it from receiver to the + // caller's expression stack (and make the first argument the receiver + // for CALL_NON_FUNCTION) by decrementing the argument count. + __ dec(eax); + __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION); + __ jmp(Handle(builtin(ArgumentsAdaptorTrampoline)), + RelocInfo::CODE_TARGET); + __ bind(&done); + } + + // 5. Shift arguments and return address one slot down on the stack + // (overwriting the receiver). { Label loop; - __ lea(ecx, Operand(eax, +1)); // +1 ~ copy receiver too + __ mov(ecx, eax); __ bind(&loop); __ mov(ebx, Operand(esp, ecx, times_4, 0)); __ mov(Operand(esp, ecx, times_4, kPointerSize), ebx); __ dec(ecx); - __ j(not_zero, &loop); + __ j(not_sign, &loop); + __ pop(ebx); // Discard copy of return address. + __ dec(eax); // One fewer argument (first argument is new receiver). } - // 5. Remove TOS (copy of last arguments), but keep return address. - __ pop(ebx); - __ pop(ecx); - __ push(ebx); - __ dec(eax); - - // 6. Check that function really was a function and get the code to - // call from the function and check that the number of expected - // arguments matches what we're providing. - { Label invoke; - __ test(edi, Operand(edi)); - __ j(not_zero, &invoke, taken); - __ xor_(ebx, Operand(ebx)); - __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION); - __ jmp(Handle(builtin(ArgumentsAdaptorTrampoline)), - RelocInfo::CODE_TARGET); - - __ bind(&invoke); - __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); + // 6. Get the code to call from the function and check that the number of + // expected arguments matches what we're providing. + { __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); __ mov(ebx, FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset)); __ mov(edx, FieldOperand(edx, SharedFunctionInfo::kCodeOffset)); diff --git a/src/ia32/codegen-ia32.cc b/src/ia32/codegen-ia32.cc index 21e0426970..5c3a2c64b9 100644 --- a/src/ia32/codegen-ia32.cc +++ b/src/ia32/codegen-ia32.cc @@ -4560,9 +4560,6 @@ void CodeGenerator::VisitCall(Call* node) { // JavaScript example: 'foo(1, 2, 3)' // foo is global // ---------------------------------- - // Push the name of the function and the receiver onto the stack. - frame_->Push(var->name()); - // Pass the global object as the receiver and let the IC stub // patch the stack to use the global proxy as 'this' in the // invoked function. @@ -4574,14 +4571,16 @@ void CodeGenerator::VisitCall(Call* node) { Load(args->at(i)); } + // Push the name of the function onto the frame. + frame_->Push(var->name()); + // Call the IC initialization code. CodeForSourcePosition(node->position()); Result result = frame_->CallCallIC(RelocInfo::CODE_TARGET_CONTEXT, arg_count, loop_nesting()); frame_->RestoreContextRegister(); - // Replace the function on the stack with the result. - frame_->SetElementAt(0, &result); + frame_->Push(&result); } else if (var != NULL && var->slot() != NULL && var->slot()->type() == Slot::LOOKUP) { @@ -4634,8 +4633,7 @@ void CodeGenerator::VisitCall(Call* node) { node->position()); } else { - // Push the name of the function and the receiver onto the stack. - frame_->Push(name); + // Push the receiver onto the frame. Load(property->obj()); // Load the arguments. @@ -4644,14 +4642,16 @@ void CodeGenerator::VisitCall(Call* node) { Load(args->at(i)); } + // Push the name of the function onto the frame. + frame_->Push(name); + // Call the IC initialization code. CodeForSourcePosition(node->position()); Result result = frame_->CallCallIC(RelocInfo::CODE_TARGET, arg_count, loop_nesting()); frame_->RestoreContextRegister(); - // Replace the function on the stack with the result. - frame_->SetElementAt(0, &result); + frame_->Push(&result); } } else { @@ -5309,8 +5309,6 @@ void CodeGenerator::VisitCallRuntime(CallRuntime* node) { Runtime::Function* function = node->function(); if (function == NULL) { - // Prepare stack for calling JS runtime function. - frame_->Push(node->name()); // Push the builtins object found in the current global object. Result temp = allocator()->Allocate(); ASSERT(temp.is_valid()); @@ -5327,11 +5325,12 @@ void CodeGenerator::VisitCallRuntime(CallRuntime* node) { if (function == NULL) { // Call the JS runtime function. + frame_->Push(node->name()); Result answer = frame_->CallCallIC(RelocInfo::CODE_TARGET, arg_count, loop_nesting_); frame_->RestoreContextRegister(); - frame_->SetElementAt(0, &answer); + frame_->Push(&answer); } else { // Call the C runtime function. Result answer = frame_->CallRuntime(function, arg_count); diff --git a/src/ia32/fast-codegen-ia32.cc b/src/ia32/fast-codegen-ia32.cc index a927e9a3f6..46524d7dce 100644 --- a/src/ia32/fast-codegen-ia32.cc +++ b/src/ia32/fast-codegen-ia32.cc @@ -1066,7 +1066,9 @@ void FastCodeGenerator::VisitProperty(Property* expr) { } -void FastCodeGenerator::EmitCallWithIC(Call* expr, RelocInfo::Mode reloc_info) { +void FastCodeGenerator::EmitCallWithIC(Call* expr, + Handle name, + RelocInfo::Mode mode) { // Code common for calls using the IC. ZoneList* args = expr->arguments(); int arg_count = args->length(); @@ -1074,16 +1076,15 @@ void FastCodeGenerator::EmitCallWithIC(Call* expr, RelocInfo::Mode reloc_info) { Visit(args->at(i)); ASSERT_EQ(Expression::kValue, args->at(i)->context()); } - // Record source position for debugger. + __ Set(ecx, Immediate(name)); + // Record source position of the IC call. SetSourcePosition(expr->position()); - // Call the IC initialization code. - Handle ic = CodeGenerator::ComputeCallInitialize(arg_count, - NOT_IN_LOOP); - __ call(ic, reloc_info); + InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; + Handle ic = CodeGenerator::ComputeCallInitialize(arg_count, in_loop); + __ call(ic, mode); // Restore context register. __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); - // Discard the function left on TOS. - DropAndMove(expr->context(), eax); + Move(expr->context(), eax); } @@ -1100,7 +1101,6 @@ void FastCodeGenerator::EmitCallWithStub(Call* expr) { __ CallStub(&stub); // Restore context register. __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); - // Discard the function left on TOS. DropAndMove(expr->context(), eax); } @@ -1114,11 +1114,9 @@ void FastCodeGenerator::VisitCall(Call* expr) { // Call to the identifier 'eval'. UNREACHABLE(); } else if (var != NULL && !var->is_this() && var->is_global()) { - // Call to a global variable. - __ push(Immediate(var->name())); - // Push global object as receiver for the call IC lookup. + // Push global object as receiver for the call IC. __ push(CodeGenerator::GlobalObject()); - EmitCallWithIC(expr, RelocInfo::CODE_TARGET_CONTEXT); + EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT); } else if (var != NULL && var->slot() != NULL && var->slot()->type() == Slot::LOOKUP) { // Call to a lookup slot. @@ -1129,9 +1127,8 @@ void FastCodeGenerator::VisitCall(Call* expr) { Literal* key = prop->key()->AsLiteral(); if (key != NULL && key->handle()->IsSymbol()) { // Call to a named property, use call IC. - __ push(Immediate(key->handle())); Visit(prop->obj()); - EmitCallWithIC(expr, RelocInfo::CODE_TARGET); + EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET); } else { // Call to a keyed property, use keyed load IC followed by function // call. @@ -1223,7 +1220,6 @@ void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) { if (expr->is_jsruntime()) { // Prepare for calling JS runtime function. - __ push(Immediate(expr->name())); __ mov(eax, CodeGenerator::GlobalObject()); __ push(FieldOperand(eax, GlobalObject::kBuiltinsOffset)); } @@ -1236,19 +1232,18 @@ void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) { } if (expr->is_jsruntime()) { - // Call the JS runtime function. - Handle ic = CodeGenerator::ComputeCallInitialize(arg_count, - NOT_IN_LOOP); + // Call the JS runtime function via a call IC. + __ Set(ecx, Immediate(expr->name())); + InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; + Handle ic = CodeGenerator::ComputeCallInitialize(arg_count, in_loop); __ call(ic, RelocInfo::CODE_TARGET); // Restore context register. __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); - // Discard the function left on TOS. - DropAndMove(expr->context(), eax); } else { // Call the C runtime function. __ CallRuntime(expr->function(), arg_count); - Move(expr->context(), eax); } + Move(expr->context(), eax); } diff --git a/src/ia32/ic-ia32.cc b/src/ia32/ic-ia32.cc index 2e30b28056..58fe2dc994 100644 --- a/src/ia32/ic-ia32.cc +++ b/src/ia32/ic-ia32.cc @@ -888,13 +888,16 @@ Object* CallIC_Miss(Arguments args); void CallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) { // ----------- S t a t e ------------- + // -- ecx : name + // -- esp[0] : return address + // -- esp[(argc - n) * 4] : arg[n] (zero-based) + // -- ... + // -- esp[(argc + 1) * 4] : receiver // ----------------------------------- Label number, non_number, non_string, boolean, probe, miss; // Get the receiver of the function from the stack; 1 ~ return address. __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); - // Get the name of the function from the stack; 2 ~ return address, receiver - __ mov(ecx, Operand(esp, (argc + 2) * kPointerSize)); // Probe the stub cache. Code::Flags flags = @@ -940,7 +943,7 @@ void CallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) { // Cache miss: Jump to runtime. __ bind(&miss); - Generate(masm, argc, ExternalReference(IC_Utility(kCallIC_Miss))); + GenerateMiss(masm, argc); } @@ -948,27 +951,34 @@ static void GenerateNormalHelper(MacroAssembler* masm, int argc, bool is_global_object, Label* miss) { - // Search dictionary - put result in register edx. - GenerateDictionaryLoad(masm, miss, eax, edx, ebx, ecx, CHECK_DICTIONARY); + // ----------- S t a t e ------------- + // -- ecx : name + // -- edx : receiver + // -- esp[0] : return address + // -- esp[(argc - n) * 4] : arg[n] (zero-based) + // -- ... + // -- esp[(argc + 1) * 4] : receiver + // ----------------------------------- - // Move the result to register edi and check that it isn't a smi. - __ mov(edi, Operand(edx)); - __ test(edx, Immediate(kSmiTagMask)); + // Search dictionary - put result in register edi. + __ mov(edi, edx); + GenerateDictionaryLoad(masm, miss, eax, edi, ebx, ecx, CHECK_DICTIONARY); + + // Check that the result is not a smi. + __ test(edi, Immediate(kSmiTagMask)); __ j(zero, miss, not_taken); - // Check that the value is a JavaScript function. - __ CmpObjectType(edx, JS_FUNCTION_TYPE, edx); + // Check that the value is a JavaScript function, fetching its map into eax. + __ CmpObjectType(edi, JS_FUNCTION_TYPE, eax); __ j(not_equal, miss, not_taken); - // Check that the function has been loaded. - __ mov(edx, FieldOperand(edi, JSFunction::kMapOffset)); - __ mov(edx, FieldOperand(edx, Map::kBitField2Offset)); - __ test(edx, Immediate(1 << Map::kNeedsLoading)); + // Check that the function has been loaded. eax holds function's map. + __ mov(eax, FieldOperand(eax, Map::kBitField2Offset)); + __ test(eax, Immediate(1 << Map::kNeedsLoading)); __ j(not_zero, miss, not_taken); - // Patch the receiver with the global proxy if necessary. + // Patch the receiver on stack with the global proxy if necessary. if (is_global_object) { - __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset)); __ mov(Operand(esp, (argc + 1) * kPointerSize), edx); } @@ -981,14 +991,17 @@ static void GenerateNormalHelper(MacroAssembler* masm, void CallIC::GenerateNormal(MacroAssembler* masm, int argc) { // ----------- S t a t e ------------- + // -- ecx : name + // -- esp[0] : return address + // -- esp[(argc - n) * 4] : arg[n] (zero-based) + // -- ... + // -- esp[(argc + 1) * 4] : receiver // ----------------------------------- Label miss, global_object, non_global_object; // Get the receiver of the function from the stack; 1 ~ return address. __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); - // Get the name of the function from the stack; 2 ~ return address, receiver. - __ mov(ecx, Operand(esp, (argc + 2) * kPointerSize)); // Check that the receiver isn't a smi. __ test(edx, Immediate(kSmiTagMask)); @@ -1037,33 +1050,33 @@ void CallIC::GenerateNormal(MacroAssembler* masm, int argc) { // Cache miss: Jump to runtime. __ bind(&miss); - Generate(masm, argc, ExternalReference(IC_Utility(kCallIC_Miss))); + GenerateMiss(masm, argc); } -void CallIC::Generate(MacroAssembler* masm, - int argc, - const ExternalReference& f) { +void CallIC::GenerateMiss(MacroAssembler* masm, int argc) { // ----------- S t a t e ------------- + // -- ecx : name + // -- esp[0] : return address + // -- esp[(argc - n) * 4] : arg[n] (zero-based) + // -- ... + // -- esp[(argc + 1) * 4] : receiver // ----------------------------------- // Get the receiver of the function from the stack; 1 ~ return address. __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); - // Get the name of the function to call from the stack. - // 2 ~ receiver, return address. - __ mov(ebx, Operand(esp, (argc + 2) * kPointerSize)); // Enter an internal frame. __ EnterInternalFrame(); // Push the receiver and the name of the function. __ push(edx); - __ push(ebx); + __ push(ecx); // Call the entry. CEntryStub stub(1); __ mov(eax, Immediate(2)); - __ mov(ebx, Immediate(f)); + __ mov(ebx, Immediate(ExternalReference(IC_Utility(kCallIC_Miss)))); __ CallStub(&stub); // Move result to edi and exit the internal frame. @@ -1075,11 +1088,11 @@ void CallIC::Generate(MacroAssembler* masm, __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); // receiver __ test(edx, Immediate(kSmiTagMask)); __ j(zero, &invoke, not_taken); - __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); - __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); - __ cmp(ecx, JS_GLOBAL_OBJECT_TYPE); + __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset)); + __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); + __ cmp(ebx, JS_GLOBAL_OBJECT_TYPE); __ j(equal, &global); - __ cmp(ecx, JS_BUILTINS_OBJECT_TYPE); + __ cmp(ebx, JS_BUILTINS_OBJECT_TYPE); __ j(not_equal, &invoke); // Patch the receiver on the stack. diff --git a/src/ia32/stub-cache-ia32.cc b/src/ia32/stub-cache-ia32.cc index 8aca1ef0a2..0e836154d3 100644 --- a/src/ia32/stub-cache-ia32.cc +++ b/src/ia32/stub-cache-ia32.cc @@ -152,11 +152,10 @@ void StubCache::GenerateProbe(MacroAssembler* masm, } -template static void PushInterceptorArguments(MacroAssembler* masm, Register receiver, Register holder, - Pushable name, + Register name, JSObject* holder_obj) { __ push(receiver); __ push(holder); @@ -285,11 +284,10 @@ void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm, } -template static void CompileCallLoadPropertyWithInterceptor(MacroAssembler* masm, Register receiver, Register holder, - Pushable name, + Register name, JSObject* holder_obj) { PushInterceptorArguments(masm, receiver, holder, name, holder_obj); @@ -495,8 +493,8 @@ class LoadInterceptorCompiler BASE_EMBEDDED { class CallInterceptorCompiler BASE_EMBEDDED { public: - explicit CallInterceptorCompiler(const ParameterCount& arguments) - : arguments_(arguments), argc_(arguments.immediate()) {} + CallInterceptorCompiler(const ParameterCount& arguments, Register name) + : arguments_(arguments), argc_(arguments.immediate()), name_(name) {} void CompileCacheable(MacroAssembler* masm, StubCompiler* stub_compiler, @@ -527,17 +525,17 @@ class CallInterceptorCompiler BASE_EMBEDDED { } __ EnterInternalFrame(); - __ push(holder); // save the holder + __ push(holder); // Save the holder. + __ push(name_); // Save the name. - CompileCallLoadPropertyWithInterceptor( - masm, - receiver, - holder, - // Under EnterInternalFrame this refers to name. - Operand(ebp, (argc_ + 3) * kPointerSize), - holder_obj); + CompileCallLoadPropertyWithInterceptor(masm, + receiver, + holder, + name_, + holder_obj); - __ pop(receiver); // restore holder + __ pop(name_); // Restore the name. + __ pop(receiver); // Restore the holder. __ LeaveInternalFrame(); __ cmp(eax, Factory::no_interceptor_result_sentinel()); @@ -577,11 +575,13 @@ class CallInterceptorCompiler BASE_EMBEDDED { JSObject* holder_obj, Label* miss_label) { __ EnterInternalFrame(); + // Save the name_ register across the call. + __ push(name_); PushInterceptorArguments(masm, receiver, holder, - Operand(ebp, (argc_ + 3) * kPointerSize), + name_, holder_obj); ExternalReference ref = ExternalReference( @@ -592,12 +592,15 @@ class CallInterceptorCompiler BASE_EMBEDDED { CEntryStub stub(1); __ CallStub(&stub); + // Restore the name_ register. + __ pop(name_); __ LeaveInternalFrame(); } private: const ParameterCount& arguments_; int argc_; + Register name_; }; @@ -894,6 +897,11 @@ Object* CallStubCompiler::CompileCallField(Object* object, int index, String* name) { // ----------- S t a t e ------------- + // -- ecx : name + // -- esp[0] : return address + // -- esp[(argc - n) * 4] : arg[n] (zero-based) + // -- ... + // -- esp[(argc + 1) * 4] : receiver // ----------------------------------- Label miss; @@ -908,7 +916,7 @@ Object* CallStubCompiler::CompileCallField(Object* object, // Do the right check and compute the holder register. Register reg = CheckPrototypes(JSObject::cast(object), edx, holder, - ebx, ecx, name, &miss); + ebx, eax, name, &miss); GenerateFastPropertyLoad(masm(), edi, reg, holder, index); @@ -944,6 +952,11 @@ Object* CallStubCompiler::CompileCallConstant(Object* object, String* name, CheckType check) { // ----------- S t a t e ------------- + // -- ecx : name + // -- esp[0] : return address + // -- esp[(argc - n) * 4] : arg[n] (zero-based) + // -- ... + // -- esp[(argc + 1) * 4] : receiver // ----------------------------------- Label miss; @@ -965,7 +978,7 @@ Object* CallStubCompiler::CompileCallConstant(Object* object, case RECEIVER_MAP_CHECK: // Check that the maps haven't changed. CheckPrototypes(JSObject::cast(object), edx, holder, - ebx, ecx, name, &miss); + ebx, eax, name, &miss); // Patch the receiver on the stack with the global proxy if // necessary. @@ -977,15 +990,15 @@ Object* CallStubCompiler::CompileCallConstant(Object* object, case STRING_CHECK: // Check that the object is a two-byte string or a symbol. - __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); - __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); - __ cmp(ecx, FIRST_NONSTRING_TYPE); + __ mov(eax, FieldOperand(edx, HeapObject::kMapOffset)); + __ movzx_b(eax, FieldOperand(eax, Map::kInstanceTypeOffset)); + __ cmp(eax, FIRST_NONSTRING_TYPE); __ j(above_equal, &miss, not_taken); // Check that the maps starting from the prototype haven't changed. GenerateLoadGlobalFunctionPrototype(masm(), Context::STRING_FUNCTION_INDEX, - ecx); - CheckPrototypes(JSObject::cast(object->GetPrototype()), ecx, holder, + eax); + CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder, ebx, edx, name, &miss); break; @@ -994,14 +1007,14 @@ Object* CallStubCompiler::CompileCallConstant(Object* object, // Check that the object is a smi or a heap number. __ test(edx, Immediate(kSmiTagMask)); __ j(zero, &fast, taken); - __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ecx); + __ CmpObjectType(edx, HEAP_NUMBER_TYPE, eax); __ j(not_equal, &miss, not_taken); __ bind(&fast); // Check that the maps starting from the prototype haven't changed. GenerateLoadGlobalFunctionPrototype(masm(), Context::NUMBER_FUNCTION_INDEX, - ecx); - CheckPrototypes(JSObject::cast(object->GetPrototype()), ecx, holder, + eax); + CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder, ebx, edx, name, &miss); break; } @@ -1017,15 +1030,15 @@ Object* CallStubCompiler::CompileCallConstant(Object* object, // Check that the maps starting from the prototype haven't changed. GenerateLoadGlobalFunctionPrototype(masm(), Context::BOOLEAN_FUNCTION_INDEX, - ecx); - CheckPrototypes(JSObject::cast(object->GetPrototype()), ecx, holder, + eax); + CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder, ebx, edx, name, &miss); break; } case JSARRAY_HAS_FAST_ELEMENTS_CHECK: CheckPrototypes(JSObject::cast(object), edx, holder, - ebx, ecx, name, &miss); + ebx, eax, name, &miss); // Make sure object->HasFastElements(). // Get the elements array of the object. __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset)); @@ -1068,6 +1081,11 @@ Object* CallStubCompiler::CompileCallInterceptor(Object* object, JSObject* holder, String* name) { // ----------- S t a t e ------------- + // -- ecx : name + // -- esp[0] : return address + // -- esp[(argc - n) * 4] : arg[n] (zero-based) + // -- ... + // -- esp[(argc + 1) * 4] : receiver // ----------------------------------- Label miss; @@ -1080,7 +1098,7 @@ Object* CallStubCompiler::CompileCallInterceptor(Object* object, // Get the receiver from the stack. __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); - CallInterceptorCompiler compiler(arguments()); + CallInterceptorCompiler compiler(arguments(), ecx); CompileLoadInterceptor(&compiler, this, masm(), @@ -1090,7 +1108,7 @@ Object* CallStubCompiler::CompileCallInterceptor(Object* object, &lookup, edx, ebx, - ecx, + edi, &miss); // Restore receiver. @@ -1129,6 +1147,11 @@ Object* CallStubCompiler::CompileCallGlobal(JSObject* object, JSFunction* function, String* name) { // ----------- S t a t e ------------- + // -- ecx : name + // -- esp[0] : return address + // -- esp[(argc - n) * 4] : arg[n] (zero-based) + // -- ... + // -- esp[(argc + 1) * 4] : receiver // ----------------------------------- Label miss; @@ -1147,7 +1170,7 @@ Object* CallStubCompiler::CompileCallGlobal(JSObject* object, } // Check that the maps haven't changed. - CheckPrototypes(object, edx, holder, ebx, ecx, name, &miss); + CheckPrototypes(object, edx, holder, ebx, eax, name, &miss); // Get the value from the cell. __ mov(edi, Immediate(Handle(cell))); diff --git a/src/ia32/virtual-frame-ia32.cc b/src/ia32/virtual-frame-ia32.cc index e770cddb15..ba6488607d 100644 --- a/src/ia32/virtual-frame-ia32.cc +++ b/src/ia32/virtual-frame-ia32.cc @@ -925,14 +925,17 @@ Result VirtualFrame::CallKeyedStoreIC() { Result VirtualFrame::CallCallIC(RelocInfo::Mode mode, int arg_count, int loop_nesting) { - // Arguments, receiver, and function name are on top of the frame. - // The IC expects them on the stack. It does not drop the function - // name slot (but it does drop the rest). + // Function name, arguments, and receiver are on top of the frame. + // The IC expects the name in ecx and the rest on the stack and + // drops them all. InLoopFlag in_loop = loop_nesting > 0 ? IN_LOOP : NOT_IN_LOOP; Handle ic = cgen()->ComputeCallInitialize(arg_count, in_loop); // Spill args, receiver, and function. The call will drop args and // receiver. - PrepareForCall(arg_count + 2, arg_count + 1); + Result name = Pop(); + PrepareForCall(arg_count + 1, arg_count + 1); // Arguments + receiver. + name.ToRegister(ecx); + name.Unuse(); return RawCallCodeObject(ic, mode); } diff --git a/src/ia32/virtual-frame-ia32.h b/src/ia32/virtual-frame-ia32.h index 314ea73b28..6c6b4816d7 100644 --- a/src/ia32/virtual-frame-ia32.h +++ b/src/ia32/virtual-frame-ia32.h @@ -341,9 +341,9 @@ class VirtualFrame: public ZoneObject { // of the frame. Key and receiver are not dropped. Result CallKeyedStoreIC(); - // Call call IC. Arguments, reciever, and function name are found - // on top of the frame. Function name slot is not dropped. The - // argument count does not include the receiver. + // Call call IC. Function name, arguments, and receiver are found on top + // of the frame and dropped by the call. The argument count does not + // include the receiver. Result CallCallIC(RelocInfo::Mode mode, int arg_count, int loop_nesting); // Allocate and call JS function as constructor. Arguments, diff --git a/src/ic.cc b/src/ic.cc index 57c9af2574..2661a10241 100644 --- a/src/ic.cc +++ b/src/ic.cc @@ -1292,16 +1292,6 @@ Object* CallIC_Miss(Arguments args) { } -void CallIC::GenerateInitialize(MacroAssembler* masm, int argc) { - Generate(masm, argc, ExternalReference(IC_Utility(kCallIC_Miss))); -} - - -void CallIC::GenerateMiss(MacroAssembler* masm, int argc) { - Generate(masm, argc, ExternalReference(IC_Utility(kCallIC_Miss))); -} - - // Used from ic_.cc. Object* LoadIC_Miss(Arguments args) { NoHandleAllocation na; diff --git a/src/ic.h b/src/ic.h index f71eaaad24..f53c6ddf00 100644 --- a/src/ic.h +++ b/src/ic.h @@ -189,16 +189,14 @@ class CallIC: public IC { // Code generator routines. - static void GenerateInitialize(MacroAssembler* masm, int argc); + static void GenerateInitialize(MacroAssembler* masm, int argc) { + GenerateMiss(masm, argc); + } static void GenerateMiss(MacroAssembler* masm, int argc); static void GenerateMegamorphic(MacroAssembler* masm, int argc); static void GenerateNormal(MacroAssembler* masm, int argc); private: - static void Generate(MacroAssembler* masm, - int argc, - const ExternalReference& f); - // Update the inline cache and the global stub cache based on the // lookup result. void UpdateCaches(LookupResult* lookup, diff --git a/src/x64/fast-codegen-x64.cc b/src/x64/fast-codegen-x64.cc index cc7c2f011b..32c975c2f6 100644 --- a/src/x64/fast-codegen-x64.cc +++ b/src/x64/fast-codegen-x64.cc @@ -1076,7 +1076,9 @@ void FastCodeGenerator::VisitProperty(Property* expr) { } -void FastCodeGenerator::EmitCallWithIC(Call* expr, RelocInfo::Mode reloc_info) { +void FastCodeGenerator::EmitCallWithIC(Call* expr, + Handle ignored, + RelocInfo::Mode mode) { // Code common for calls using the IC. ZoneList* args = expr->arguments(); int arg_count = args->length(); @@ -1089,7 +1091,7 @@ void FastCodeGenerator::EmitCallWithIC(Call* expr, RelocInfo::Mode reloc_info) { // Call the IC initialization code. Handle ic = CodeGenerator::ComputeCallInitialize(arg_count, NOT_IN_LOOP); - __ call(ic, reloc_info); + __ call(ic, mode); // Restore context register. __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); // Discard the function left on TOS. @@ -1128,7 +1130,7 @@ void FastCodeGenerator::VisitCall(Call* expr) { __ Push(var->name()); // Push global object as receiver for the call IC lookup. __ push(CodeGenerator::GlobalObject()); - EmitCallWithIC(expr, RelocInfo::CODE_TARGET_CONTEXT); + EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT); } else if (var != NULL && var->slot() != NULL && var->slot()->type() == Slot::LOOKUP) { // Call to a lookup slot. @@ -1141,7 +1143,7 @@ void FastCodeGenerator::VisitCall(Call* expr) { // Call to a named property, use call IC. __ Push(key->handle()); Visit(prop->obj()); - EmitCallWithIC(expr, RelocInfo::CODE_TARGET); + EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET); } else { // Call to a keyed property, use keyed load IC followed by function // call. diff --git a/src/x64/ic-x64.cc b/src/x64/ic-x64.cc index 9e58f3091a..e24007559f 100644 --- a/src/x64/ic-x64.cc +++ b/src/x64/ic-x64.cc @@ -916,9 +916,7 @@ void KeyedStoreIC::GenerateExternalArray(MacroAssembler* masm, } -void CallIC::Generate(MacroAssembler* masm, - int argc, - ExternalReference const& f) { +void CallIC::GenerateMiss(MacroAssembler* masm, int argc) { // Get the receiver of the function from the stack; 1 ~ return address. __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); // Get the name of the function to call from the stack. @@ -935,7 +933,7 @@ void CallIC::Generate(MacroAssembler* masm, // Call the entry. CEntryStub stub(1); __ movq(rax, Immediate(2)); - __ movq(rbx, f); + __ movq(rbx, ExternalReference(IC_Utility(kCallIC_Miss))); __ CallStub(&stub); // Move result to rdi and exit the internal frame. @@ -1026,7 +1024,7 @@ void CallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) { // Cache miss: Jump to runtime. __ bind(&miss); - Generate(masm, argc, ExternalReference(IC_Utility(kCallIC_Miss))); + GenerateMiss(masm, argc); } @@ -1128,7 +1126,7 @@ void CallIC::GenerateNormal(MacroAssembler* masm, int argc) { // Cache miss: Jump to runtime. __ bind(&miss); - Generate(masm, argc, ExternalReference(IC_Utility(kCallIC_Miss))); + GenerateMiss(masm, argc); }