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) { ...@@ -3877,16 +3877,12 @@ void CodeGenerator::VisitCall(Call* node) {
Load(args->at(i)); Load(args->at(i));
} }
// Setup the receiver register and call the IC initialization code. // Call the IC initialization code.
Handle<Code> stub = (loop_nesting() > 0)
? ComputeCallInitializeInLoop(arg_count)
: ComputeCallInitialize(arg_count);
CodeForSourcePosition(node->position()); CodeForSourcePosition(node->position());
Result result = frame_->CallCodeObject(stub, Result result = frame_->CallCallIC(RelocInfo::CODE_TARGET_CONTEXT,
RelocInfo::CODE_TARGET_CONTEXT, arg_count,
arg_count + 1); loop_nesting());
frame_->RestoreContextRegister(); frame_->RestoreContextRegister();
// Replace the function on the stack with the result. // Replace the function on the stack with the result.
frame_->SetElementAt(0, &result); frame_->SetElementAt(0, &result);
...@@ -3929,15 +3925,10 @@ void CodeGenerator::VisitCall(Call* node) { ...@@ -3929,15 +3925,10 @@ void CodeGenerator::VisitCall(Call* node) {
} }
// Call the IC initialization code. // Call the IC initialization code.
Handle<Code> stub = (loop_nesting() > 0)
? ComputeCallInitializeInLoop(arg_count)
: ComputeCallInitialize(arg_count);
CodeForSourcePosition(node->position()); CodeForSourcePosition(node->position());
Result result = frame_->CallCodeObject(stub, Result result =
RelocInfo::CODE_TARGET, frame_->CallCallIC(RelocInfo::CODE_TARGET, arg_count, loop_nesting());
arg_count + 1);
frame_->RestoreContextRegister(); frame_->RestoreContextRegister();
// Replace the function on the stack with the result. // Replace the function on the stack with the result.
frame_->SetElementAt(0, &result); frame_->SetElementAt(0, &result);
...@@ -4003,30 +3994,10 @@ void CodeGenerator::VisitCallNew(CallNew* node) { ...@@ -4003,30 +3994,10 @@ void CodeGenerator::VisitCallNew(CallNew* node) {
Load(args->at(i)); 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 // Call the construct call builtin that handles allocation and
// constructor invocation. // constructor invocation.
CodeForSourcePosition(node->position()); CodeForSourcePosition(node->position());
Handle<Code> ic(Builtins::builtin(Builtins::JSConstructCall)); Result result = frame_->CallConstructor(arg_count);
Result result = frame_->CallCodeObject(ic,
RelocInfo::CONSTRUCT_CALL,
&num_args,
&function,
arg_count + 1);
// Replace the function on the stack with the result. // Replace the function on the stack with the result.
frame_->SetElementAt(0, &result); frame_->SetElementAt(0, &result);
} }
...@@ -4439,10 +4410,9 @@ void CodeGenerator::VisitCallRuntime(CallRuntime* node) { ...@@ -4439,10 +4410,9 @@ void CodeGenerator::VisitCallRuntime(CallRuntime* node) {
} }
if (function == NULL) { if (function == NULL) {
// Call the JS runtime function. // Call the JS runtime function. Pass 0 as the loop nesting depth
Handle<Code> stub = ComputeCallInitialize(arg_count); // because we do not handle runtime calls specially in loops.
Result answer = Result answer = frame_->CallCallIC(RelocInfo::CODE_TARGET, arg_count, 0);
frame_->CallCodeObject(stub, RelocInfo::CODE_TARGET, arg_count + 1);
frame_->RestoreContextRegister(); frame_->RestoreContextRegister();
frame_->SetElementAt(0, &answer); frame_->SetElementAt(0, &answer);
} else { } else {
......
...@@ -232,7 +232,7 @@ void VirtualFrame::PushTryHandler(HandlerType type) { ...@@ -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()); ASSERT(cgen_->HasValidEntryRegisters());
__ CallStub(stub); __ CallStub(stub);
Result result = cgen_->allocator()->Allocate(r0); Result result = cgen_->allocator()->Allocate(r0);
...@@ -241,22 +241,20 @@ Result VirtualFrame::RawCallStub(CodeStub* stub, int frame_arg_count) { ...@@ -241,22 +241,20 @@ Result VirtualFrame::RawCallStub(CodeStub* stub, int frame_arg_count) {
} }
Result VirtualFrame::CallRuntime(Runtime::Function* f, Result VirtualFrame::CallRuntime(Runtime::Function* f, int arg_count) {
int frame_arg_count) { PrepareForCall(arg_count, arg_count);
PrepareForCall(frame_arg_count, frame_arg_count);
ASSERT(cgen_->HasValidEntryRegisters()); ASSERT(cgen_->HasValidEntryRegisters());
__ CallRuntime(f, frame_arg_count); __ CallRuntime(f, arg_count);
Result result = cgen_->allocator()->Allocate(r0); Result result = cgen_->allocator()->Allocate(r0);
ASSERT(result.is_valid()); ASSERT(result.is_valid());
return result; return result;
} }
Result VirtualFrame::CallRuntime(Runtime::FunctionId id, Result VirtualFrame::CallRuntime(Runtime::FunctionId id, int arg_count) {
int frame_arg_count) { PrepareForCall(arg_count, arg_count);
PrepareForCall(frame_arg_count, frame_arg_count);
ASSERT(cgen_->HasValidEntryRegisters()); ASSERT(cgen_->HasValidEntryRegisters());
__ CallRuntime(id, frame_arg_count); __ CallRuntime(id, arg_count);
Result result = cgen_->allocator()->Allocate(r0); Result result = cgen_->allocator()->Allocate(r0);
ASSERT(result.is_valid()); ASSERT(result.is_valid());
return result; return result;
...@@ -266,9 +264,9 @@ Result VirtualFrame::CallRuntime(Runtime::FunctionId id, ...@@ -266,9 +264,9 @@ Result VirtualFrame::CallRuntime(Runtime::FunctionId id,
Result VirtualFrame::InvokeBuiltin(Builtins::JavaScript id, Result VirtualFrame::InvokeBuiltin(Builtins::JavaScript id,
InvokeJSFlags flags, InvokeJSFlags flags,
Result* arg_count_register, Result* arg_count_register,
int frame_arg_count) { int arg_count) {
ASSERT(arg_count_register->reg().is(r0)); ASSERT(arg_count_register->reg().is(r0));
PrepareForCall(frame_arg_count, frame_arg_count); PrepareForCall(arg_count, arg_count);
arg_count_register->Unuse(); arg_count_register->Unuse();
__ InvokeBuiltin(id, flags); __ InvokeBuiltin(id, flags);
Result result = cgen_->allocator()->Allocate(r0); Result result = cgen_->allocator()->Allocate(r0);
...@@ -286,6 +284,33 @@ Result VirtualFrame::RawCallCodeObject(Handle<Code> code, ...@@ -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, Result VirtualFrame::CallCodeObject(Handle<Code> code,
RelocInfo::Mode rmode, RelocInfo::Mode rmode,
Result* arg, Result* arg,
......
...@@ -250,24 +250,21 @@ class VirtualFrame : public Malloced { ...@@ -250,24 +250,21 @@ class VirtualFrame : public Malloced {
// Call a code stub, given the number of arguments it expects on (and // Call a code stub, given the number of arguments it expects on (and
// removes from) the top of the physical frame. // removes from) the top of the physical frame.
Result CallStub(CodeStub* stub, int frame_arg_count); Result CallStub(CodeStub* stub, int arg_count);
Result CallStub(CodeStub* stub, Result* arg, int frame_arg_count); Result CallStub(CodeStub* stub, Result* arg, int arg_count);
Result CallStub(CodeStub* stub, Result CallStub(CodeStub* stub, Result* arg0, Result* arg1, int arg_count);
Result* arg0,
Result* arg1,
int frame_arg_count);
// Call the runtime, given the number of arguments expected on (and // Call the runtime, given the number of arguments expected on (and
// removed from) the top of the physical frame. // removed from) the top of the physical frame.
Result CallRuntime(Runtime::Function* f, int frame_arg_count); Result CallRuntime(Runtime::Function* f, int arg_count);
Result CallRuntime(Runtime::FunctionId id, int frame_arg_count); Result CallRuntime(Runtime::FunctionId id, int arg_count);
// Invoke a builtin, given the number of arguments it expects on (and // Invoke a builtin, given the number of arguments it expects on (and
// removes from) the top of the physical frame. // removes from) the top of the physical frame.
Result InvokeBuiltin(Builtins::JavaScript id, Result InvokeBuiltin(Builtins::JavaScript id,
InvokeJSFlags flag, InvokeJSFlags flag,
Result* arg_count_register, Result* arg_count_register,
int frame_arg_count); int arg_count);
// Call into a JS code object, given the number of arguments it // Call into a JS code object, given the number of arguments it
// removes from the top of the physical frame. // removes from the top of the physical frame.
...@@ -460,7 +457,7 @@ class VirtualFrame : public Malloced { ...@@ -460,7 +457,7 @@ class VirtualFrame : public Malloced {
// Call a code stub that has already been prepared for calling (via // Call a code stub that has already been prepared for calling (via
// PrepareForCall). // PrepareForCall).
Result RawCallStub(CodeStub* stub, int frame_arg_count); Result RawCallStub(CodeStub* stub);
// Calls a code object which has already been prepared for calling // Calls a code object which has already been prepared for calling
// (via PrepareForCall). // (via PrepareForCall).
......
...@@ -725,7 +725,7 @@ void VirtualFrame::PushTryHandler(HandlerType type) { ...@@ -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()); ASSERT(cgen_->HasValidEntryRegisters());
__ CallStub(stub); __ CallStub(stub);
Result result = cgen_->allocator()->Allocate(eax); Result result = cgen_->allocator()->Allocate(eax);
...@@ -734,22 +734,20 @@ Result VirtualFrame::RawCallStub(CodeStub* stub, int frame_arg_count) { ...@@ -734,22 +734,20 @@ Result VirtualFrame::RawCallStub(CodeStub* stub, int frame_arg_count) {
} }
Result VirtualFrame::CallRuntime(Runtime::Function* f, Result VirtualFrame::CallRuntime(Runtime::Function* f, int arg_count) {
int frame_arg_count) { PrepareForCall(arg_count, arg_count);
PrepareForCall(frame_arg_count, frame_arg_count);
ASSERT(cgen_->HasValidEntryRegisters()); ASSERT(cgen_->HasValidEntryRegisters());
__ CallRuntime(f, frame_arg_count); __ CallRuntime(f, arg_count);
Result result = cgen_->allocator()->Allocate(eax); Result result = cgen_->allocator()->Allocate(eax);
ASSERT(result.is_valid()); ASSERT(result.is_valid());
return result; return result;
} }
Result VirtualFrame::CallRuntime(Runtime::FunctionId id, Result VirtualFrame::CallRuntime(Runtime::FunctionId id, int arg_count) {
int frame_arg_count) { PrepareForCall(arg_count, arg_count);
PrepareForCall(frame_arg_count, frame_arg_count);
ASSERT(cgen_->HasValidEntryRegisters()); ASSERT(cgen_->HasValidEntryRegisters());
__ CallRuntime(id, frame_arg_count); __ CallRuntime(id, arg_count);
Result result = cgen_->allocator()->Allocate(eax); Result result = cgen_->allocator()->Allocate(eax);
ASSERT(result.is_valid()); ASSERT(result.is_valid());
return result; return result;
...@@ -758,8 +756,8 @@ Result VirtualFrame::CallRuntime(Runtime::FunctionId id, ...@@ -758,8 +756,8 @@ Result VirtualFrame::CallRuntime(Runtime::FunctionId id,
Result VirtualFrame::InvokeBuiltin(Builtins::JavaScript id, Result VirtualFrame::InvokeBuiltin(Builtins::JavaScript id,
InvokeFlag flag, InvokeFlag flag,
int frame_arg_count) { int arg_count) {
PrepareForCall(frame_arg_count, frame_arg_count); PrepareForCall(arg_count, arg_count);
ASSERT(cgen_->HasValidEntryRegisters()); ASSERT(cgen_->HasValidEntryRegisters());
__ InvokeBuiltin(id, flag); __ InvokeBuiltin(id, flag);
Result result = cgen_->allocator()->Allocate(eax); Result result = cgen_->allocator()->Allocate(eax);
...@@ -845,29 +843,43 @@ Result VirtualFrame::CallKeyedStoreIC() { ...@@ -845,29 +843,43 @@ Result VirtualFrame::CallKeyedStoreIC() {
} }
Result VirtualFrame::CallCodeObject(Handle<Code> code, Result VirtualFrame::CallCallIC(RelocInfo::Mode mode,
RelocInfo::Mode rmode, int arg_count,
Result* arg0, int loop_nesting) {
Result* arg1, // Arguments, receiver, and function name are on top of the frame.
int dropped_args) { // The IC expects them on the stack. It does not drop the function
int spilled_args = 1; // name slot (but it does drop the rest).
switch (code->kind()) { Handle<Code> ic = (loop_nesting > 0)
case Code::BUILTIN: ? cgen_->ComputeCallInitializeInLoop(arg_count)
ASSERT(*code == Builtins::builtin(Builtins::JSConstructCall)); : cgen_->ComputeCallInitialize(arg_count);
ASSERT(arg0->reg().is(eax)); // Spill args, receiver, and function. The call will drop args and
ASSERT(arg1->reg().is(edi)); // receiver.
spilled_args = dropped_args + 1; PrepareForCall(arg_count + 2, arg_count + 1);
break; return RawCallCodeObject(ic, mode);
default: }
// No other types of code objects are called with values
// in exactly two registers.
UNREACHABLE(); Result VirtualFrame::CallConstructor(int arg_count) {
break; // Arguments, receiver, and function are on top of the frame. The
} // IC expects arg count in eax, function in edi, and the arguments
PrepareForCall(spilled_args, dropped_args); // and receiver on the stack.
arg0->Unuse(); Handle<Code> ic(Builtins::builtin(Builtins::JSConstructCall));
arg1->Unuse(); // Duplicate the function before preparing the frame.
return RawCallCodeObject(code, rmode); 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 { ...@@ -243,35 +243,20 @@ class VirtualFrame : public Malloced {
// Call a code stub, given the number of arguments it expects on (and // Call a code stub, given the number of arguments it expects on (and
// removes from) the top of the physical frame. // removes from) the top of the physical frame.
Result CallStub(CodeStub* stub, int frame_arg_count); Result CallStub(CodeStub* stub, int arg_count);
Result CallStub(CodeStub* stub, Result* arg, int frame_arg_count); Result CallStub(CodeStub* stub, Result* arg, int arg_count);
Result CallStub(CodeStub* stub, Result CallStub(CodeStub* stub, Result* arg0, Result* arg1, int arg_count);
Result* arg0,
Result* arg1,
int frame_arg_count);
// Call the runtime, given the number of arguments expected on (and // Call the runtime, given the number of arguments expected on (and
// removed from) the top of the physical frame. // removed from) the top of the physical frame.
Result CallRuntime(Runtime::Function* f, int frame_arg_count); Result CallRuntime(Runtime::Function* f, int arg_count);
Result CallRuntime(Runtime::FunctionId id, int frame_arg_count); Result CallRuntime(Runtime::FunctionId id, int arg_count);
// Invoke a builtin, given the number of arguments it expects on (and // Invoke a builtin, given the number of arguments it expects on (and
// removes from) the top of the physical frame. // removes from) the top of the physical frame.
Result InvokeBuiltin(Builtins::JavaScript id, Result InvokeBuiltin(Builtins::JavaScript id,
InvokeFlag flag, InvokeFlag flag,
int frame_arg_count); int 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);
// Call load IC. Name and receiver are found on top of the frame. // Call load IC. Name and receiver are found on top of the frame.
// Receiver is not dropped. // Receiver is not dropped.
...@@ -289,6 +274,17 @@ class VirtualFrame : public Malloced { ...@@ -289,6 +274,17 @@ class VirtualFrame : public Malloced {
// of the frame. Key and receiver are not dropped. // of the frame. Key and receiver are not dropped.
Result CallKeyedStoreIC(); 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 // 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 // emit code to affect the physical frame. Does not clobber any registers
// excepting possibly the stack pointer. // excepting possibly the stack pointer.
...@@ -467,7 +463,7 @@ class VirtualFrame : public Malloced { ...@@ -467,7 +463,7 @@ class VirtualFrame : public Malloced {
// Call a code stub that has already been prepared for calling (via // Call a code stub that has already been prepared for calling (via
// PrepareForCall). // PrepareForCall).
Result RawCallStub(CodeStub* stub, int frame_arg_count); Result RawCallStub(CodeStub* stub);
// Calls a code object which has already been prepared for calling // Calls a code object which has already been prepared for calling
// (via PrepareForCall). // (via PrepareForCall).
......
...@@ -431,58 +431,27 @@ void VirtualFrame::PushFrameSlotAt(int index) { ...@@ -431,58 +431,27 @@ void VirtualFrame::PushFrameSlotAt(int index) {
} }
Result VirtualFrame::CallStub(CodeStub* stub, int frame_arg_count) { Result VirtualFrame::CallStub(CodeStub* stub, int arg_count) {
PrepareForCall(frame_arg_count, frame_arg_count); PrepareForCall(arg_count, arg_count);
return RawCallStub(stub, frame_arg_count); return RawCallStub(stub);
} }
Result VirtualFrame::CallStub(CodeStub* stub, Result VirtualFrame::CallStub(CodeStub* stub, Result* arg, int arg_count) {
Result* arg, PrepareForCall(arg_count, arg_count);
int frame_arg_count) {
PrepareForCall(frame_arg_count, frame_arg_count);
arg->Unuse(); arg->Unuse();
return RawCallStub(stub, frame_arg_count); return RawCallStub(stub);
} }
Result VirtualFrame::CallStub(CodeStub* stub, Result VirtualFrame::CallStub(CodeStub* stub,
Result* arg0, Result* arg0,
Result* arg1, Result* arg1,
int frame_arg_count) { int arg_count) {
PrepareForCall(frame_arg_count, frame_arg_count); PrepareForCall(arg_count, arg_count);
arg0->Unuse(); arg0->Unuse();
arg1->Unuse(); arg1->Unuse();
return RawCallStub(stub, frame_arg_count); return RawCallStub(stub);
}
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);
} }
......
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