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) {
VirtualFrame::SpilledScope spilled_scope(frame_);
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()) {
Load(property->key());
EmitKeyedLoad();
// Put the function below the receiver.
// Use the global receiver.
frame_->EmitPush(r0); // Function.
LoadGlobalReceiver(r0);
// Call the function.
CallWithArguments(args, RECEIVER_MIGHT_BE_VALUE, node->position());
frame_->EmitPush(r0);
} else {
// Switch receiver and function.
frame_->EmitPop(r1); // Receiver.
frame_->EmitPush(r0); // Function.
frame_->EmitPush(r1); // Receiver.
}
// Load the arguments.
int arg_count = args->length();
for (int i = 0; i < arg_count; i++) {
Load(args->at(i));
}
// Call the function.
CallWithArguments(args, RECEIVER_MIGHT_BE_VALUE, node->position());
frame_->EmitPush(r0);
// Set the name register and call the IC initialization code.
Load(property->key());
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 {
......
......@@ -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) {
// Code common for calls using the call stub.
ZoneList<Expression*>* args = expr->arguments();
......@@ -1743,35 +1767,28 @@ void FullCodeGenerator::VisitCall(Call* expr) {
VisitForValue(prop->obj(), kStack);
EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET);
} else {
// Call to a keyed property, use keyed load IC followed by function
// call.
// Call to a keyed property.
// 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->key(), kAccumulator);
// Record source code position for IC call.
SetSourcePosition(prop->position());
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.
} else {
__ ldr(r1, MemOperand(sp, 0)); // Keep receiver, to call function on.
}
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET);
if (prop->is_synthetic()) {
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET);
// Push result (function).
__ push(r0);
// Push Global receiver.
__ ldr(r1, CodeGenerator::GlobalObject());
__ ldr(r1, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
__ push(r1);
EmitCallWithStub(expr);
} else {
// Pop receiver.
__ pop(r1);
// Push result (function).
__ push(r0);
__ push(r1);
EmitKeyedCallWithIC(expr, prop->key(), RelocInfo::CODE_TARGET);
}
EmitCallWithStub(expr);
}
} else {
// 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) {
}
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() {
Handle<Code> ic = ComputeCallMiss(arguments().immediate(), kind_);
__ Jump(ic, RelocInfo::CODE_TARGET);
......@@ -1035,6 +1043,8 @@ Object* CallStubCompiler::CompileCallField(JSObject* object,
// -----------------------------------
Label miss;
GenerateNameCheck(name, &miss);
const int argc = arguments().immediate();
// Get the receiver of the function from the stack into r0.
......@@ -1078,6 +1088,8 @@ Object* CallStubCompiler::CompileArrayPushCall(Object* object,
Label miss;
GenerateNameCheck(name, &miss);
// Get the receiver from the stack
const int argc = arguments().immediate();
__ ldr(r1, MemOperand(sp, argc * kPointerSize));
......@@ -1127,6 +1139,8 @@ Object* CallStubCompiler::CompileArrayPopCall(Object* object,
Label miss;
GenerateNameCheck(name, &miss);
// Get the receiver from the stack
const int argc = arguments().immediate();
__ ldr(r1, MemOperand(sp, argc * kPointerSize));
......@@ -1198,6 +1212,8 @@ Object* CallStubCompiler::CompileCallConstant(Object* object,
Label miss_in_smi_check;
GenerateNameCheck(name, &miss_in_smi_check);
// Get the receiver from the stack
const int argc = arguments().immediate();
__ ldr(r1, MemOperand(sp, argc * kPointerSize));
......@@ -1337,6 +1353,8 @@ Object* CallStubCompiler::CompileCallInterceptor(JSObject* object,
Label miss;
GenerateNameCheck(name, &miss);
// Get the number of arguments.
const int argc = arguments().immediate();
......@@ -1384,6 +1402,8 @@ Object* CallStubCompiler::CompileCallGlobal(JSObject* object,
// -----------------------------------
Label miss;
GenerateNameCheck(name, &miss);
// Get the number of arguments.
const int argc = arguments().immediate();
......
......@@ -367,6 +367,7 @@ void VirtualFrame::CallCodeObject(Handle<Code> code,
int dropped_args) {
switch (code->kind()) {
case Code::CALL_IC:
case Code::KEYED_CALL_IC:
case Code::FUNCTION:
break;
case Code::KEYED_LOAD_IC:
......
This diff is collapsed.
......@@ -3108,25 +3108,31 @@ void CodeGenerator::VisitCall(Call* node) {
ref.GetValue();
// Use global object as receiver.
LoadGlobalReceiver();
// Call the function.
CallWithArguments(args, RECEIVER_MIGHT_BE_VALUE, node->position());
} else {
Reference ref(this, property, false);
ASSERT(ref.size() == 2);
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);
}
// Push the receiver onto the frame.
Load(property->obj());
// Call the function.
CallWithArguments(args, RECEIVER_MIGHT_BE_VALUE, node->position());
}
// Load the arguments.
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 {
// ----------------------------------
// JavaScript example: 'foo(1, 2, 3)' // foo is not global
......
......@@ -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) {
// Code common for calls using the call stub.
ZoneList<Expression*>* args = expr->arguments();
......@@ -1820,30 +1844,32 @@ void FullCodeGenerator::VisitCall(Call* expr) {
VisitForValue(prop->obj(), kStack);
EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET);
} else {
// Call to a keyed property, use keyed load IC followed by function
// call.
// Call to a keyed property.
// For a synthetic property use keyed load IC followed by function call,
// for a regular property use KeyedCallIC.
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()) {
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());
__ push(FieldOperand(rcx, GlobalObject::kGlobalReceiverOffset));
EmitCallWithStub(expr);
} else {
__ push(rbx);
EmitKeyedCallWithIC(expr, prop->key(), RelocInfo::CODE_TARGET);
}
EmitCallWithStub(expr);
}
} else {
// Call to some other expression. If the expression is an anonymous
......
This diff is collapsed.
......@@ -706,6 +706,15 @@ static Object* GenerateCheckPropertyCell(MacroAssembler* 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() {
Handle<Code> ic = ComputeCallMiss(arguments().immediate(), kind_);
__ Jump(ic, RelocInfo::CODE_TARGET);
......@@ -740,6 +749,8 @@ Object* CallStubCompiler::CompileCallConstant(Object* object,
Label miss_in_smi_check;
GenerateNameCheck(name, &miss_in_smi_check);
// Get the receiver from the stack.
const int argc = arguments().immediate();
__ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
......@@ -881,6 +892,8 @@ Object* CallStubCompiler::CompileCallField(JSObject* object,
// -----------------------------------
Label miss;
GenerateNameCheck(name, &miss);
// Get the receiver from the stack.
const int argc = arguments().immediate();
__ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
......@@ -938,6 +951,8 @@ Object* CallStubCompiler::CompileArrayPushCall(Object* object,
Label miss;
GenerateNameCheck(name, &miss);
// Get the receiver from the stack.
const int argc = arguments().immediate();
__ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
......@@ -1092,6 +1107,8 @@ Object* CallStubCompiler::CompileArrayPopCall(Object* object,
Label miss, return_undefined, call_builtin;
GenerateNameCheck(name, &miss);
// Get the receiver from the stack.
const int argc = arguments().immediate();
__ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
......@@ -1190,6 +1207,8 @@ Object* CallStubCompiler::CompileCallInterceptor(JSObject* object,
// -----------------------------------
Label miss;
GenerateNameCheck(name, &miss);
// Get the number of arguments.
const int argc = arguments().immediate();
......@@ -1254,6 +1273,8 @@ Object* CallStubCompiler::CompileCallGlobal(JSObject* object,
// rsp[(argc + 1) * 8] : argument 0 = receiver
Label miss;
GenerateNameCheck(name, &miss);
// Get the number of arguments.
const int argc = arguments().immediate();
......
......@@ -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) {
// Arguments, receiver, and function are on top of the frame. The
// IC expects arg count in rax, function in rdi, and the arguments
......
......@@ -369,6 +369,8 @@ class VirtualFrame : public ZoneObject {
// The argument count does not include the receiver.
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,
// receiver (global object), and function are found on top of the
// frame. Function is not dropped. The argument count does not
......
......@@ -94,3 +94,20 @@ testMany(fixed_array, first3num, first3num);
testMany(dict_array, first3num, first3num);
testMany(fast_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