In the IA32 code genrator, handle call ICs and constructor calls the

same as load and store ICs.  Eliminate the general function used to
call any IC.
Review URL: http://codereview.chromium.org/42638

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@1619 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 7d23b48a
......@@ -3877,16 +3877,12 @@ void CodeGenerator::VisitCall(Call* node) {
Load(args->at(i));
}
// Setup the receiver register and call the IC initialization code.
Handle<Code> stub = (loop_nesting() > 0)
? ComputeCallInitializeInLoop(arg_count)
: ComputeCallInitialize(arg_count);
// Call the IC initialization code.
CodeForSourcePosition(node->position());
Result result = frame_->CallCodeObject(stub,
RelocInfo::CODE_TARGET_CONTEXT,
arg_count + 1);
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);
......@@ -3929,15 +3925,10 @@ void CodeGenerator::VisitCall(Call* node) {
}
// Call the IC initialization code.
Handle<Code> stub = (loop_nesting() > 0)
? ComputeCallInitializeInLoop(arg_count)
: ComputeCallInitialize(arg_count);
CodeForSourcePosition(node->position());
Result result = frame_->CallCodeObject(stub,
RelocInfo::CODE_TARGET,
arg_count + 1);
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);
......@@ -4003,30 +3994,10 @@ void CodeGenerator::VisitCallNew(CallNew* node) {
Load(args->at(i));
}
// Constructors are called with the number of arguments in register
// eax for now. Another option would be to have separate construct
// call trampolines per different arguments counts encountered.
Result num_args = allocator()->Allocate(eax);
ASSERT(num_args.is_valid());
__ Set(num_args.reg(), Immediate(arg_count));
// Load the function into temporary function slot as per calling
// convention.
frame_->PushElementAt(arg_count + 1);
Result function = frame_->Pop();
function.ToRegister(edi);
ASSERT(function.is_valid());
// Call the construct call builtin that handles allocation and
// constructor invocation.
CodeForSourcePosition(node->position());
Handle<Code> ic(Builtins::builtin(Builtins::JSConstructCall));
Result result = frame_->CallCodeObject(ic,
RelocInfo::CONSTRUCT_CALL,
&num_args,
&function,
arg_count + 1);
Result result = frame_->CallConstructor(arg_count);
// Replace the function on the stack with the result.
frame_->SetElementAt(0, &result);
}
......@@ -4439,10 +4410,9 @@ void CodeGenerator::VisitCallRuntime(CallRuntime* node) {
}
if (function == NULL) {
// Call the JS runtime function.
Handle<Code> stub = ComputeCallInitialize(arg_count);
Result answer =
frame_->CallCodeObject(stub, RelocInfo::CODE_TARGET, arg_count + 1);
// Call the JS runtime function. Pass 0 as the loop nesting depth
// because we do not handle runtime calls specially in loops.
Result answer = frame_->CallCallIC(RelocInfo::CODE_TARGET, arg_count, 0);
frame_->RestoreContextRegister();
frame_->SetElementAt(0, &answer);
} else {
......
......@@ -232,7 +232,7 @@ void VirtualFrame::PushTryHandler(HandlerType type) {
}
Result VirtualFrame::RawCallStub(CodeStub* stub, int frame_arg_count) {
Result VirtualFrame::RawCallStub(CodeStub* stub) {
ASSERT(cgen_->HasValidEntryRegisters());
__ CallStub(stub);
Result result = cgen_->allocator()->Allocate(r0);
......@@ -241,22 +241,20 @@ Result VirtualFrame::RawCallStub(CodeStub* stub, int frame_arg_count) {
}
Result VirtualFrame::CallRuntime(Runtime::Function* f,
int frame_arg_count) {
PrepareForCall(frame_arg_count, frame_arg_count);
Result VirtualFrame::CallRuntime(Runtime::Function* f, int arg_count) {
PrepareForCall(arg_count, arg_count);
ASSERT(cgen_->HasValidEntryRegisters());
__ CallRuntime(f, frame_arg_count);
__ CallRuntime(f, arg_count);
Result result = cgen_->allocator()->Allocate(r0);
ASSERT(result.is_valid());
return result;
}
Result VirtualFrame::CallRuntime(Runtime::FunctionId id,
int frame_arg_count) {
PrepareForCall(frame_arg_count, frame_arg_count);
Result VirtualFrame::CallRuntime(Runtime::FunctionId id, int arg_count) {
PrepareForCall(arg_count, arg_count);
ASSERT(cgen_->HasValidEntryRegisters());
__ CallRuntime(id, frame_arg_count);
__ CallRuntime(id, arg_count);
Result result = cgen_->allocator()->Allocate(r0);
ASSERT(result.is_valid());
return result;
......@@ -266,9 +264,9 @@ Result VirtualFrame::CallRuntime(Runtime::FunctionId id,
Result VirtualFrame::InvokeBuiltin(Builtins::JavaScript id,
InvokeJSFlags flags,
Result* arg_count_register,
int frame_arg_count) {
int arg_count) {
ASSERT(arg_count_register->reg().is(r0));
PrepareForCall(frame_arg_count, frame_arg_count);
PrepareForCall(arg_count, arg_count);
arg_count_register->Unuse();
__ InvokeBuiltin(id, flags);
Result result = cgen_->allocator()->Allocate(r0);
......@@ -286,6 +284,33 @@ Result VirtualFrame::RawCallCodeObject(Handle<Code> code,
}
Result VirtualFrame::CallCodeObject(Handle<Code> code,
RelocInfo::Mode rmode,
int dropped_args) {
int spilled_args = 0;
switch (code->kind()) {
case Code::CALL_IC:
spilled_args = dropped_args + 1;
break;
case Code::FUNCTION:
spilled_args = dropped_args + 1;
break;
case Code::KEYED_LOAD_IC:
ASSERT(dropped_args == 0);
spilled_args = 2;
break;
default:
// The other types of code objects are called with values
// in specific registers, and are handled in functions with
// a different signature.
UNREACHABLE();
break;
}
PrepareForCall(spilled_args, dropped_args);
return RawCallCodeObject(code, rmode);
}
Result VirtualFrame::CallCodeObject(Handle<Code> code,
RelocInfo::Mode rmode,
Result* arg,
......
......@@ -250,24 +250,21 @@ class VirtualFrame : public Malloced {
// Call a code stub, given the number of arguments it expects on (and
// removes from) the top of the physical frame.
Result CallStub(CodeStub* stub, int frame_arg_count);
Result CallStub(CodeStub* stub, Result* arg, int frame_arg_count);
Result CallStub(CodeStub* stub,
Result* arg0,
Result* arg1,
int frame_arg_count);
Result CallStub(CodeStub* stub, int arg_count);
Result CallStub(CodeStub* stub, Result* arg, int arg_count);
Result CallStub(CodeStub* stub, Result* arg0, Result* arg1, int arg_count);
// Call the runtime, given the number of arguments expected on (and
// removed from) the top of the physical frame.
Result CallRuntime(Runtime::Function* f, int frame_arg_count);
Result CallRuntime(Runtime::FunctionId id, int frame_arg_count);
Result CallRuntime(Runtime::Function* f, int arg_count);
Result CallRuntime(Runtime::FunctionId id, int arg_count);
// Invoke a builtin, given the number of arguments it expects on (and
// removes from) the top of the physical frame.
Result InvokeBuiltin(Builtins::JavaScript id,
InvokeJSFlags flag,
Result* arg_count_register,
int frame_arg_count);
int arg_count);
// Call into a JS code object, given the number of arguments it
// removes from the top of the physical frame.
......@@ -460,7 +457,7 @@ class VirtualFrame : public Malloced {
// Call a code stub that has already been prepared for calling (via
// PrepareForCall).
Result RawCallStub(CodeStub* stub, int frame_arg_count);
Result RawCallStub(CodeStub* stub);
// Calls a code object which has already been prepared for calling
// (via PrepareForCall).
......
......@@ -725,7 +725,7 @@ void VirtualFrame::PushTryHandler(HandlerType type) {
}
Result VirtualFrame::RawCallStub(CodeStub* stub, int frame_arg_count) {
Result VirtualFrame::RawCallStub(CodeStub* stub) {
ASSERT(cgen_->HasValidEntryRegisters());
__ CallStub(stub);
Result result = cgen_->allocator()->Allocate(eax);
......@@ -734,22 +734,20 @@ Result VirtualFrame::RawCallStub(CodeStub* stub, int frame_arg_count) {
}
Result VirtualFrame::CallRuntime(Runtime::Function* f,
int frame_arg_count) {
PrepareForCall(frame_arg_count, frame_arg_count);
Result VirtualFrame::CallRuntime(Runtime::Function* f, int arg_count) {
PrepareForCall(arg_count, arg_count);
ASSERT(cgen_->HasValidEntryRegisters());
__ CallRuntime(f, frame_arg_count);
__ CallRuntime(f, arg_count);
Result result = cgen_->allocator()->Allocate(eax);
ASSERT(result.is_valid());
return result;
}
Result VirtualFrame::CallRuntime(Runtime::FunctionId id,
int frame_arg_count) {
PrepareForCall(frame_arg_count, frame_arg_count);
Result VirtualFrame::CallRuntime(Runtime::FunctionId id, int arg_count) {
PrepareForCall(arg_count, arg_count);
ASSERT(cgen_->HasValidEntryRegisters());
__ CallRuntime(id, frame_arg_count);
__ CallRuntime(id, arg_count);
Result result = cgen_->allocator()->Allocate(eax);
ASSERT(result.is_valid());
return result;
......@@ -758,8 +756,8 @@ Result VirtualFrame::CallRuntime(Runtime::FunctionId id,
Result VirtualFrame::InvokeBuiltin(Builtins::JavaScript id,
InvokeFlag flag,
int frame_arg_count) {
PrepareForCall(frame_arg_count, frame_arg_count);
int arg_count) {
PrepareForCall(arg_count, arg_count);
ASSERT(cgen_->HasValidEntryRegisters());
__ InvokeBuiltin(id, flag);
Result result = cgen_->allocator()->Allocate(eax);
......@@ -845,29 +843,43 @@ Result VirtualFrame::CallKeyedStoreIC() {
}
Result VirtualFrame::CallCodeObject(Handle<Code> code,
RelocInfo::Mode rmode,
Result* arg0,
Result* arg1,
int dropped_args) {
int spilled_args = 1;
switch (code->kind()) {
case Code::BUILTIN:
ASSERT(*code == Builtins::builtin(Builtins::JSConstructCall));
ASSERT(arg0->reg().is(eax));
ASSERT(arg1->reg().is(edi));
spilled_args = dropped_args + 1;
break;
default:
// No other types of code objects are called with values
// in exactly two registers.
UNREACHABLE();
break;
}
PrepareForCall(spilled_args, dropped_args);
arg0->Unuse();
arg1->Unuse();
return RawCallCodeObject(code, rmode);
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).
Handle<Code> ic = (loop_nesting > 0)
? cgen_->ComputeCallInitializeInLoop(arg_count)
: cgen_->ComputeCallInitialize(arg_count);
// Spill args, receiver, and function. The call will drop args and
// receiver.
PrepareForCall(arg_count + 2, arg_count + 1);
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 eax, function in edi, and the arguments
// and receiver on the stack.
Handle<Code> ic(Builtins::builtin(Builtins::JSConstructCall));
// Duplicate the function before preparing the frame.
PushElementAt(arg_count + 1);
Result function = Pop();
PrepareForCall(arg_count + 1, arg_count + 1); // Spill args and receiver.
function.ToRegister(edi);
// Constructors are called with the number of arguments in register
// eax for now. Another option would be to have separate construct
// call trampolines per different arguments counts encountered.
Result num_args = cgen_->allocator()->Allocate(eax);
ASSERT(num_args.is_valid());
__ Set(num_args.reg(), Immediate(arg_count));
function.Unuse();
num_args.Unuse();
return RawCallCodeObject(ic, RelocInfo::CONSTRUCT_CALL);
}
......
......@@ -243,35 +243,20 @@ class VirtualFrame : public Malloced {
// Call a code stub, given the number of arguments it expects on (and
// removes from) the top of the physical frame.
Result CallStub(CodeStub* stub, int frame_arg_count);
Result CallStub(CodeStub* stub, Result* arg, int frame_arg_count);
Result CallStub(CodeStub* stub,
Result* arg0,
Result* arg1,
int frame_arg_count);
Result CallStub(CodeStub* stub, int arg_count);
Result CallStub(CodeStub* stub, Result* arg, int arg_count);
Result CallStub(CodeStub* stub, Result* arg0, Result* arg1, int arg_count);
// Call the runtime, given the number of arguments expected on (and
// removed from) the top of the physical frame.
Result CallRuntime(Runtime::Function* f, int frame_arg_count);
Result CallRuntime(Runtime::FunctionId id, int frame_arg_count);
Result CallRuntime(Runtime::Function* f, int arg_count);
Result CallRuntime(Runtime::FunctionId id, int arg_count);
// Invoke a builtin, given the number of arguments it expects on (and
// removes from) the top of the physical frame.
Result InvokeBuiltin(Builtins::JavaScript id,
InvokeFlag flag,
int frame_arg_count);
// Call into a call IC or a JS code object given the number of
// arguments it drops from the top of the stack. Arguments passed
// in registers are given as results and invalidated by the call.
Result CallCodeObject(Handle<Code> ic,
RelocInfo::Mode rmode,
int dropped_args);
Result CallCodeObject(Handle<Code> ic,
RelocInfo::Mode rmode,
Result* arg0,
Result* arg1,
int dropped_args);
int arg_count);
// Call load IC. Name and receiver are found on top of the frame.
// Receiver is not dropped.
......@@ -289,6 +274,17 @@ class VirtualFrame : public Malloced {
// 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.
Result CallCallIC(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
// include the receiver.
Result CallConstructor(int arg_count);
// Drop a number of elements from the top of the expression stack. May
// emit code to affect the physical frame. Does not clobber any registers
// excepting possibly the stack pointer.
......@@ -467,7 +463,7 @@ class VirtualFrame : public Malloced {
// Call a code stub that has already been prepared for calling (via
// PrepareForCall).
Result RawCallStub(CodeStub* stub, int frame_arg_count);
Result RawCallStub(CodeStub* stub);
// Calls a code object which has already been prepared for calling
// (via PrepareForCall).
......
......@@ -431,58 +431,27 @@ void VirtualFrame::PushFrameSlotAt(int index) {
}
Result VirtualFrame::CallStub(CodeStub* stub, int frame_arg_count) {
PrepareForCall(frame_arg_count, frame_arg_count);
return RawCallStub(stub, frame_arg_count);
Result VirtualFrame::CallStub(CodeStub* stub, int arg_count) {
PrepareForCall(arg_count, arg_count);
return RawCallStub(stub);
}
Result VirtualFrame::CallStub(CodeStub* stub,
Result* arg,
int frame_arg_count) {
PrepareForCall(frame_arg_count, frame_arg_count);
Result VirtualFrame::CallStub(CodeStub* stub, Result* arg, int arg_count) {
PrepareForCall(arg_count, arg_count);
arg->Unuse();
return RawCallStub(stub, frame_arg_count);
return RawCallStub(stub);
}
Result VirtualFrame::CallStub(CodeStub* stub,
Result* arg0,
Result* arg1,
int frame_arg_count) {
PrepareForCall(frame_arg_count, frame_arg_count);
int arg_count) {
PrepareForCall(arg_count, arg_count);
arg0->Unuse();
arg1->Unuse();
return RawCallStub(stub, frame_arg_count);
}
Result VirtualFrame::CallCodeObject(Handle<Code> code,
RelocInfo::Mode rmode,
int dropped_args) {
int spilled_args = 0;
switch (code->kind()) {
case Code::CALL_IC:
spilled_args = dropped_args + 1;
break;
case Code::FUNCTION:
spilled_args = dropped_args + 1;
break;
#ifdef ARM
case Code::KEYED_LOAD_IC:
ASSERT(dropped_args == 0);
spilled_args = 2;
break;
#endif
default:
// The other types of code objects are called with values
// in specific registers, and are handled in functions with
// a different signature.
UNREACHABLE();
break;
}
PrepareForCall(spilled_args, dropped_args);
return RawCallCodeObject(code, rmode);
return RawCallStub(stub);
}
......
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