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
This commit is contained in:
parent
a3aa9e96ef
commit
6af6a82ae3
@ -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<Object> ignored,
|
||||
RelocInfo::Mode mode) {
|
||||
// Code common for calls using the IC.
|
||||
ZoneList<Expression*>* 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<Code> 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.
|
||||
|
@ -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);
|
||||
|
@ -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<Object> name, RelocInfo::Mode mode);
|
||||
|
||||
// Platform-specific code for loading variables.
|
||||
void EmitVariableLoad(Variable* expr, Expression::Context context);
|
||||
|
@ -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<Code>(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<Code>(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));
|
||||
|
@ -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);
|
||||
|
@ -1066,7 +1066,9 @@ void FastCodeGenerator::VisitProperty(Property* expr) {
|
||||
}
|
||||
|
||||
|
||||
void FastCodeGenerator::EmitCallWithIC(Call* expr, RelocInfo::Mode reloc_info) {
|
||||
void FastCodeGenerator::EmitCallWithIC(Call* expr,
|
||||
Handle<Object> name,
|
||||
RelocInfo::Mode mode) {
|
||||
// Code common for calls using the IC.
|
||||
ZoneList<Expression*>* 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<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count,
|
||||
NOT_IN_LOOP);
|
||||
__ call(ic, reloc_info);
|
||||
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
|
||||
Handle<Code> 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<Code> 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<Code> 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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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.
|
||||
|
@ -152,11 +152,10 @@ void StubCache::GenerateProbe(MacroAssembler* masm,
|
||||
}
|
||||
|
||||
|
||||
template <typename Pushable>
|
||||
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 <class Pushable>
|
||||
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<JSGlobalPropertyCell>(cell)));
|
||||
|
@ -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<Code> 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);
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
10
src/ic.cc
10
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_<arch>.cc.
|
||||
Object* LoadIC_Miss(Arguments args) {
|
||||
NoHandleAllocation na;
|
||||
|
8
src/ic.h
8
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,
|
||||
|
@ -1076,7 +1076,9 @@ void FastCodeGenerator::VisitProperty(Property* expr) {
|
||||
}
|
||||
|
||||
|
||||
void FastCodeGenerator::EmitCallWithIC(Call* expr, RelocInfo::Mode reloc_info) {
|
||||
void FastCodeGenerator::EmitCallWithIC(Call* expr,
|
||||
Handle<Object> ignored,
|
||||
RelocInfo::Mode mode) {
|
||||
// Code common for calls using the IC.
|
||||
ZoneList<Expression*>* 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<Code> 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.
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user