Port KeyedCallIC implementation to x64 and ARM.

Also edited ic-ia32.cc for clarity and better formatting.

Review URL: http://codereview.chromium.org/2853003

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4873 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent ed0fc417
...@@ -4088,28 +4088,34 @@ void CodeGenerator::VisitCall(Call* node) { ...@@ -4088,28 +4088,34 @@ void CodeGenerator::VisitCall(Call* node) {
VirtualFrame::SpilledScope spilled_scope(frame_); VirtualFrame::SpilledScope spilled_scope(frame_);
Load(property->obj()); Load(property->obj());
if (!property->is_synthetic()) {
// Duplicate receiver for later use.
__ ldr(r0, MemOperand(sp, 0));
frame_->EmitPush(r0);
}
Load(property->key());
EmitKeyedLoad();
// Put the function below the receiver.
if (property->is_synthetic()) { if (property->is_synthetic()) {
Load(property->key());
EmitKeyedLoad();
// Put the function below the receiver.
// Use the global receiver. // Use the global receiver.
frame_->EmitPush(r0); // Function. frame_->EmitPush(r0); // Function.
LoadGlobalReceiver(r0); LoadGlobalReceiver(r0);
// Call the function.
CallWithArguments(args, RECEIVER_MIGHT_BE_VALUE, node->position());
frame_->EmitPush(r0);
} else { } else {
// Switch receiver and function. // Load the arguments.
frame_->EmitPop(r1); // Receiver. int arg_count = args->length();
frame_->EmitPush(r0); // Function. for (int i = 0; i < arg_count; i++) {
frame_->EmitPush(r1); // Receiver. Load(args->at(i));
} }
// Call the function. // Set the name register and call the IC initialization code.
CallWithArguments(args, RECEIVER_MIGHT_BE_VALUE, node->position()); Load(property->key());
frame_->EmitPush(r0); frame_->EmitPop(r2); // Function name.
InLoopFlag in_loop = loop_nesting() > 0 ? IN_LOOP : NOT_IN_LOOP;
Handle<Code> stub = ComputeKeyedCallInitialize(arg_count, in_loop);
CodeForSourcePosition(node->position());
frame_->CallCodeObject(stub, RelocInfo::CODE_TARGET, arg_count + 1);
__ ldr(cp, frame_->Context());
frame_->EmitPush(r0);
}
} }
} else { } else {
......
...@@ -1648,6 +1648,30 @@ void FullCodeGenerator::EmitCallWithIC(Call* expr, ...@@ -1648,6 +1648,30 @@ void FullCodeGenerator::EmitCallWithIC(Call* expr,
} }
void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr,
Expression* key,
RelocInfo::Mode mode) {
// Code common for calls using the IC.
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
for (int i = 0; i < arg_count; i++) {
VisitForValue(args->at(i), kStack);
}
VisitForValue(key, kAccumulator);
__ mov(r2, r0);
// Record source position for debugger.
SetSourcePosition(expr->position());
// Call the IC initialization code.
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
Handle<Code> ic = CodeGenerator::ComputeKeyedCallInitialize(arg_count,
in_loop);
__ Call(ic, mode);
// Restore context register.
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
Apply(context_, r0);
}
void FullCodeGenerator::EmitCallWithStub(Call* expr) { void FullCodeGenerator::EmitCallWithStub(Call* expr) {
// Code common for calls using the call stub. // Code common for calls using the call stub.
ZoneList<Expression*>* args = expr->arguments(); ZoneList<Expression*>* args = expr->arguments();
...@@ -1743,35 +1767,28 @@ void FullCodeGenerator::VisitCall(Call* expr) { ...@@ -1743,35 +1767,28 @@ void FullCodeGenerator::VisitCall(Call* expr) {
VisitForValue(prop->obj(), kStack); VisitForValue(prop->obj(), kStack);
EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET); EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET);
} else { } else {
// Call to a keyed property, use keyed load IC followed by function // Call to a keyed property.
// call. // For a synthetic property use keyed load IC followed by function call,
// for a regular property use keyed CallIC.
VisitForValue(prop->obj(), kStack); VisitForValue(prop->obj(), kStack);
VisitForValue(prop->key(), kAccumulator);
// Record source code position for IC call.
SetSourcePosition(prop->position());
if (prop->is_synthetic()) { if (prop->is_synthetic()) {
VisitForValue(prop->key(), kAccumulator);
// Record source code position for IC call.
SetSourcePosition(prop->position());
__ pop(r1); // We do not need to keep the receiver. __ pop(r1); // We do not need to keep the receiver.
} else {
__ ldr(r1, MemOperand(sp, 0)); // Keep receiver, to call function on.
}
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET); __ Call(ic, RelocInfo::CODE_TARGET);
if (prop->is_synthetic()) {
// Push result (function). // Push result (function).
__ push(r0); __ push(r0);
// Push Global receiver. // Push Global receiver.
__ ldr(r1, CodeGenerator::GlobalObject()); __ ldr(r1, CodeGenerator::GlobalObject());
__ ldr(r1, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset)); __ ldr(r1, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
__ push(r1); __ push(r1);
EmitCallWithStub(expr);
} else { } else {
// Pop receiver. EmitKeyedCallWithIC(expr, prop->key(), RelocInfo::CODE_TARGET);
__ pop(r1);
// Push result (function).
__ push(r0);
__ push(r1);
} }
EmitCallWithStub(expr);
} }
} else { } else {
// Call to some other expression. If the expression is an anonymous // Call to some other expression. If the expression is an anonymous
......
This diff is collapsed.
...@@ -1019,6 +1019,14 @@ Object* StubCompiler::CompileLazyCompile(Code::Flags flags) { ...@@ -1019,6 +1019,14 @@ Object* StubCompiler::CompileLazyCompile(Code::Flags flags) {
} }
void CallStubCompiler::GenerateNameCheck(String* name, Label* miss) {
if (kind_ == Code::KEYED_CALL_IC) {
__ cmp(r2, Operand(Handle<String>(name)));
__ b(ne, miss);
}
}
void CallStubCompiler::GenerateMissBranch() { void CallStubCompiler::GenerateMissBranch() {
Handle<Code> ic = ComputeCallMiss(arguments().immediate(), kind_); Handle<Code> ic = ComputeCallMiss(arguments().immediate(), kind_);
__ Jump(ic, RelocInfo::CODE_TARGET); __ Jump(ic, RelocInfo::CODE_TARGET);
...@@ -1035,6 +1043,8 @@ Object* CallStubCompiler::CompileCallField(JSObject* object, ...@@ -1035,6 +1043,8 @@ Object* CallStubCompiler::CompileCallField(JSObject* object,
// ----------------------------------- // -----------------------------------
Label miss; Label miss;
GenerateNameCheck(name, &miss);
const int argc = arguments().immediate(); const int argc = arguments().immediate();
// Get the receiver of the function from the stack into r0. // Get the receiver of the function from the stack into r0.
...@@ -1078,6 +1088,8 @@ Object* CallStubCompiler::CompileArrayPushCall(Object* object, ...@@ -1078,6 +1088,8 @@ Object* CallStubCompiler::CompileArrayPushCall(Object* object,
Label miss; Label miss;
GenerateNameCheck(name, &miss);
// Get the receiver from the stack // Get the receiver from the stack
const int argc = arguments().immediate(); const int argc = arguments().immediate();
__ ldr(r1, MemOperand(sp, argc * kPointerSize)); __ ldr(r1, MemOperand(sp, argc * kPointerSize));
...@@ -1127,6 +1139,8 @@ Object* CallStubCompiler::CompileArrayPopCall(Object* object, ...@@ -1127,6 +1139,8 @@ Object* CallStubCompiler::CompileArrayPopCall(Object* object,
Label miss; Label miss;
GenerateNameCheck(name, &miss);
// Get the receiver from the stack // Get the receiver from the stack
const int argc = arguments().immediate(); const int argc = arguments().immediate();
__ ldr(r1, MemOperand(sp, argc * kPointerSize)); __ ldr(r1, MemOperand(sp, argc * kPointerSize));
...@@ -1198,6 +1212,8 @@ Object* CallStubCompiler::CompileCallConstant(Object* object, ...@@ -1198,6 +1212,8 @@ Object* CallStubCompiler::CompileCallConstant(Object* object,
Label miss_in_smi_check; Label miss_in_smi_check;
GenerateNameCheck(name, &miss_in_smi_check);
// Get the receiver from the stack // Get the receiver from the stack
const int argc = arguments().immediate(); const int argc = arguments().immediate();
__ ldr(r1, MemOperand(sp, argc * kPointerSize)); __ ldr(r1, MemOperand(sp, argc * kPointerSize));
...@@ -1337,6 +1353,8 @@ Object* CallStubCompiler::CompileCallInterceptor(JSObject* object, ...@@ -1337,6 +1353,8 @@ Object* CallStubCompiler::CompileCallInterceptor(JSObject* object,
Label miss; Label miss;
GenerateNameCheck(name, &miss);
// Get the number of arguments. // Get the number of arguments.
const int argc = arguments().immediate(); const int argc = arguments().immediate();
...@@ -1384,6 +1402,8 @@ Object* CallStubCompiler::CompileCallGlobal(JSObject* object, ...@@ -1384,6 +1402,8 @@ Object* CallStubCompiler::CompileCallGlobal(JSObject* object,
// ----------------------------------- // -----------------------------------
Label miss; Label miss;
GenerateNameCheck(name, &miss);
// Get the number of arguments. // Get the number of arguments.
const int argc = arguments().immediate(); const int argc = arguments().immediate();
......
...@@ -367,6 +367,7 @@ void VirtualFrame::CallCodeObject(Handle<Code> code, ...@@ -367,6 +367,7 @@ void VirtualFrame::CallCodeObject(Handle<Code> code,
int dropped_args) { int dropped_args) {
switch (code->kind()) { switch (code->kind()) {
case Code::CALL_IC: case Code::CALL_IC:
case Code::KEYED_CALL_IC:
case Code::FUNCTION: case Code::FUNCTION:
break; break;
case Code::KEYED_LOAD_IC: case Code::KEYED_LOAD_IC:
......
This diff is collapsed.
...@@ -3108,25 +3108,31 @@ void CodeGenerator::VisitCall(Call* node) { ...@@ -3108,25 +3108,31 @@ void CodeGenerator::VisitCall(Call* node) {
ref.GetValue(); ref.GetValue();
// Use global object as receiver. // Use global object as receiver.
LoadGlobalReceiver(); LoadGlobalReceiver();
// Call the function.
CallWithArguments(args, RECEIVER_MIGHT_BE_VALUE, node->position());
} else { } else {
Reference ref(this, property, false); // Push the receiver onto the frame.
ASSERT(ref.size() == 2); Load(property->obj());
Result key = frame_->Pop();
frame_->Dup(); // Duplicate the receiver.
frame_->Push(&key);
ref.GetValue();
// Top of frame contains function to call, with duplicate copy of
// receiver below it. Swap them.
Result function = frame_->Pop();
Result receiver = frame_->Pop();
frame_->Push(&function);
frame_->Push(&receiver);
}
// Call the function. // Load the arguments.
CallWithArguments(args, RECEIVER_MIGHT_BE_VALUE, node->position()); int arg_count = args->length();
} for (int i = 0; i < arg_count; i++) {
Load(args->at(i));
frame_->SpillTop();
}
// Load the name of the function.
Load(property->key());
// Call the IC initialization code.
CodeForSourcePosition(node->position());
Result result = frame_->CallKeyedCallIC(RelocInfo::CODE_TARGET,
arg_count,
loop_nesting());
frame_->RestoreContextRegister();
frame_->Push(&result);
}
}
} else { } else {
// ---------------------------------- // ----------------------------------
// JavaScript example: 'foo(1, 2, 3)' // foo is not global // JavaScript example: 'foo(1, 2, 3)' // foo is not global
......
...@@ -1729,6 +1729,30 @@ void FullCodeGenerator::EmitCallWithIC(Call* expr, ...@@ -1729,6 +1729,30 @@ void FullCodeGenerator::EmitCallWithIC(Call* expr,
} }
void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr,
Expression* key,
RelocInfo::Mode mode) {
// Code common for calls using the IC.
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
for (int i = 0; i < arg_count; i++) {
VisitForValue(args->at(i), kStack);
}
VisitForValue(key, kAccumulator);
__ movq(rcx, rax);
// Record source position for debugger.
SetSourcePosition(expr->position());
// Call the IC initialization code.
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
Handle<Code> ic = CodeGenerator::ComputeKeyedCallInitialize(arg_count,
in_loop);
__ Call(ic, mode);
// Restore context register.
__ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
Apply(context_, rax);
}
void FullCodeGenerator::EmitCallWithStub(Call* expr) { void FullCodeGenerator::EmitCallWithStub(Call* expr) {
// Code common for calls using the call stub. // Code common for calls using the call stub.
ZoneList<Expression*>* args = expr->arguments(); ZoneList<Expression*>* args = expr->arguments();
...@@ -1820,30 +1844,32 @@ void FullCodeGenerator::VisitCall(Call* expr) { ...@@ -1820,30 +1844,32 @@ void FullCodeGenerator::VisitCall(Call* expr) {
VisitForValue(prop->obj(), kStack); VisitForValue(prop->obj(), kStack);
EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET); EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET);
} else { } else {
// Call to a keyed property, use keyed load IC followed by function // Call to a keyed property.
// call. // For a synthetic property use keyed load IC followed by function call,
// for a regular property use KeyedCallIC.
VisitForValue(prop->obj(), kStack); VisitForValue(prop->obj(), kStack);
VisitForValue(prop->key(), kAccumulator);
__ movq(rdx, Operand(rsp, 0));
// Record source code position for IC call.
SetSourcePosition(prop->position());
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
__ call(ic, RelocInfo::CODE_TARGET);
// By emitting a nop we make sure that we do not have a "test rax,..."
// instruction after the call it is treated specially by the LoadIC code.
__ nop();
// Pop receiver.
__ pop(rbx);
// Push result (function).
__ push(rax);
// Push receiver object on stack.
if (prop->is_synthetic()) { if (prop->is_synthetic()) {
VisitForValue(prop->key(), kAccumulator);
__ movq(rdx, Operand(rsp, 0));
// Record source code position for IC call.
SetSourcePosition(prop->position());
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
__ call(ic, RelocInfo::CODE_TARGET);
// By emitting a nop we make sure that we do not have a "test rax,..."
// instruction after the call as it is treated specially
// by the LoadIC code.
__ nop();
// Pop receiver.
__ pop(rbx);
// Push result (function).
__ push(rax);
// Push receiver object on stack.
__ movq(rcx, CodeGenerator::GlobalObject()); __ movq(rcx, CodeGenerator::GlobalObject());
__ push(FieldOperand(rcx, GlobalObject::kGlobalReceiverOffset)); __ push(FieldOperand(rcx, GlobalObject::kGlobalReceiverOffset));
EmitCallWithStub(expr);
} else { } else {
__ push(rbx); EmitKeyedCallWithIC(expr, prop->key(), RelocInfo::CODE_TARGET);
} }
EmitCallWithStub(expr);
} }
} else { } else {
// Call to some other expression. If the expression is an anonymous // Call to some other expression. If the expression is an anonymous
......
This diff is collapsed.
...@@ -706,6 +706,15 @@ static Object* GenerateCheckPropertyCell(MacroAssembler* masm, ...@@ -706,6 +706,15 @@ static Object* GenerateCheckPropertyCell(MacroAssembler* masm,
#define __ ACCESS_MASM((masm())) #define __ ACCESS_MASM((masm()))
void CallStubCompiler::GenerateNameCheck(String* name, Label* miss) {
if (kind_ == Code::KEYED_CALL_IC) {
__ Cmp(rcx, Handle<String>(name));
__ j(not_equal, miss);
}
}
void CallStubCompiler::GenerateMissBranch() { void CallStubCompiler::GenerateMissBranch() {
Handle<Code> ic = ComputeCallMiss(arguments().immediate(), kind_); Handle<Code> ic = ComputeCallMiss(arguments().immediate(), kind_);
__ Jump(ic, RelocInfo::CODE_TARGET); __ Jump(ic, RelocInfo::CODE_TARGET);
...@@ -740,6 +749,8 @@ Object* CallStubCompiler::CompileCallConstant(Object* object, ...@@ -740,6 +749,8 @@ Object* CallStubCompiler::CompileCallConstant(Object* object,
Label miss_in_smi_check; Label miss_in_smi_check;
GenerateNameCheck(name, &miss_in_smi_check);
// Get the receiver from the stack. // Get the receiver from the stack.
const int argc = arguments().immediate(); const int argc = arguments().immediate();
__ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
...@@ -881,6 +892,8 @@ Object* CallStubCompiler::CompileCallField(JSObject* object, ...@@ -881,6 +892,8 @@ Object* CallStubCompiler::CompileCallField(JSObject* object,
// ----------------------------------- // -----------------------------------
Label miss; Label miss;
GenerateNameCheck(name, &miss);
// Get the receiver from the stack. // Get the receiver from the stack.
const int argc = arguments().immediate(); const int argc = arguments().immediate();
__ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
...@@ -938,6 +951,8 @@ Object* CallStubCompiler::CompileArrayPushCall(Object* object, ...@@ -938,6 +951,8 @@ Object* CallStubCompiler::CompileArrayPushCall(Object* object,
Label miss; Label miss;
GenerateNameCheck(name, &miss);
// Get the receiver from the stack. // Get the receiver from the stack.
const int argc = arguments().immediate(); const int argc = arguments().immediate();
__ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
...@@ -1092,6 +1107,8 @@ Object* CallStubCompiler::CompileArrayPopCall(Object* object, ...@@ -1092,6 +1107,8 @@ Object* CallStubCompiler::CompileArrayPopCall(Object* object,
Label miss, return_undefined, call_builtin; Label miss, return_undefined, call_builtin;
GenerateNameCheck(name, &miss);
// Get the receiver from the stack. // Get the receiver from the stack.
const int argc = arguments().immediate(); const int argc = arguments().immediate();
__ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
...@@ -1190,6 +1207,8 @@ Object* CallStubCompiler::CompileCallInterceptor(JSObject* object, ...@@ -1190,6 +1207,8 @@ Object* CallStubCompiler::CompileCallInterceptor(JSObject* object,
// ----------------------------------- // -----------------------------------
Label miss; Label miss;
GenerateNameCheck(name, &miss);
// Get the number of arguments. // Get the number of arguments.
const int argc = arguments().immediate(); const int argc = arguments().immediate();
...@@ -1254,6 +1273,8 @@ Object* CallStubCompiler::CompileCallGlobal(JSObject* object, ...@@ -1254,6 +1273,8 @@ Object* CallStubCompiler::CompileCallGlobal(JSObject* object,
// rsp[(argc + 1) * 8] : argument 0 = receiver // rsp[(argc + 1) * 8] : argument 0 = receiver
Label miss; Label miss;
GenerateNameCheck(name, &miss);
// Get the number of arguments. // Get the number of arguments.
const int argc = arguments().immediate(); const int argc = arguments().immediate();
......
...@@ -1164,6 +1164,25 @@ Result VirtualFrame::CallCallIC(RelocInfo::Mode mode, ...@@ -1164,6 +1164,25 @@ Result VirtualFrame::CallCallIC(RelocInfo::Mode mode,
} }
Result VirtualFrame::CallKeyedCallIC(RelocInfo::Mode mode,
int arg_count,
int loop_nesting) {
// Function name, arguments, and receiver are found on top of the frame
// and dropped by the call. The IC expects the name in rcx 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()->ComputeKeyedCallInitialize(arg_count, in_loop);
Result name = Pop();
// Spill args, receiver, and function. The call will drop args and
// receiver.
PrepareForCall(arg_count + 1, arg_count + 1);
name.ToRegister(rcx);
name.Unuse();
return RawCallCodeObject(ic, mode);
}
Result VirtualFrame::CallConstructor(int arg_count) { Result VirtualFrame::CallConstructor(int arg_count) {
// Arguments, receiver, and function are on top of the frame. The // Arguments, receiver, and function are on top of the frame. The
// IC expects arg count in rax, function in rdi, and the arguments // IC expects arg count in rax, function in rdi, and the arguments
......
...@@ -369,6 +369,8 @@ class VirtualFrame : public ZoneObject { ...@@ -369,6 +369,8 @@ class VirtualFrame : public ZoneObject {
// The argument count does not include the receiver. // The argument count does not include the receiver.
Result CallCallIC(RelocInfo::Mode mode, int arg_count, int loop_nesting); Result CallCallIC(RelocInfo::Mode mode, int arg_count, int loop_nesting);
Result CallKeyedCallIC(RelocInfo::Mode mode, int arg_count, int loop_nesting);
// Allocate and call JS function as constructor. Arguments, // Allocate and call JS function as constructor. Arguments,
// receiver (global object), and function are found on top of the // receiver (global object), and function are found on top of the
// frame. Function is not dropped. The argument count does not // frame. Function is not dropped. The argument count does not
......
...@@ -94,3 +94,20 @@ testMany(fixed_array, first3num, first3num); ...@@ -94,3 +94,20 @@ testMany(fixed_array, first3num, first3num);
testMany(dict_array, first3num, first3num); testMany(dict_array, first3num, first3num);
testMany(fast_prop, first3str, first3num); testMany(fast_prop, first3str, first3num);
testMany(normal_prop, first3str, first3num); testMany(normal_prop, first3str, first3num);
function testException(receiver, keys, exceptions) {
for (var i = 0; i != 10; i++) {
for (var k = 0; k != keys.length; k++) {
var thrown = false;
try {
var result = receiver[keys[k]]();
} catch (e) {
thrown = true;
}
assertEquals(exceptions[k], thrown);
}
}
}
testException([zero, one, /* hole */ ], [0, 1, 2], [false, false, true]);
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