Make VirtualFrame::CallStub on IA32 responsible for moving arguments

into the appropriate registers for the stub call.  Since stubs that
take arguments in registers do not (currently) take any arguments on
the stack, the unused generality has been removed (it's easy to put
back in later).
Review URL: http://codereview.chromium.org/55003

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@1629 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
kmillikin@chromium.org 2009-03-27 10:29:37 +00:00
parent 6feb0d9a8f
commit b8af68b03f
7 changed files with 102 additions and 83 deletions

View File

@ -868,11 +868,11 @@ void DeferredInlineSmiOperation::Generate() {
} }
GenericBinaryOpStub igostub(op_); GenericBinaryOpStub igostub(op_);
Result arg0 = generator()->allocator()->Allocate(r0); Result arg0 = generator()->allocator()->Allocate(r1);
ASSERT(arg0.is_valid()); ASSERT(arg0.is_valid());
Result arg1 = generator()->allocator()->Allocate(r1); Result arg1 = generator()->allocator()->Allocate(r0);
ASSERT(arg1.is_valid()); ASSERT(arg1.is_valid());
generator()->frame()->CallStub(&igostub, &arg0, &arg1, 0); generator()->frame()->CallStub(&igostub, &arg0, &arg1);
exit_.Jump(); exit_.Jump();
} }

View File

@ -1508,12 +1508,10 @@ void CodeGenerator::Comparison(Condition cc,
__ test(left_side.reg(), Immediate(kSmiTagMask)); __ test(left_side.reg(), Immediate(kSmiTagMask));
is_smi.Branch(zero, &left_side, &right_side, taken); is_smi.Branch(zero, &left_side, &right_side, taken);
// Setup and call the compare stub, which expects arguments in edx // Setup and call the compare stub, which expects its arguments
// and eax. // in registers.
CompareStub stub(cc, strict); CompareStub stub(cc, strict);
left_side.ToRegister(edx); // Only left_side currently uses a register. Result result = frame_->CallStub(&stub, &left_side, &right_side);
right_side.ToRegister(eax); // left_side is not in eax. eax is free.
Result result = frame_->CallStub(&stub, &left_side, &right_side, 0);
result.ToRegister(); result.ToRegister();
__ cmp(result.reg(), 0); __ cmp(result.reg(), 0);
result.Unuse(); result.Unuse();
@ -1588,23 +1586,10 @@ void CodeGenerator::Comparison(Condition cc,
temp.Unuse(); temp.Unuse();
is_smi.Branch(zero, &left_side, &right_side, taken); is_smi.Branch(zero, &left_side, &right_side, taken);
} }
// When non-smi, call out to the compare stub. "parameters" setup by // When non-smi, call out to the compare stub, which expects its
// calling code in edx and eax and "result" is returned in the flags. // arguments in registers.
if (!left_side.reg().is(eax)) {
right_side.ToRegister(eax);
left_side.ToRegister(edx);
} else if (!right_side.reg().is(edx)) {
left_side.ToRegister(edx);
right_side.ToRegister(eax);
} else {
frame_->Spill(eax); // Can be multiply referenced, even now.
frame_->Spill(edx);
__ xchg(eax, edx);
// If left_side and right_side become real (non-dummy) arguments
// to CallStub, they need to be swapped in this case.
}
CompareStub stub(cc, strict); CompareStub stub(cc, strict);
Result answer = frame_->CallStub(&stub, &right_side, &left_side, 0); Result answer = frame_->CallStub(&stub, &left_side, &right_side);
if (cc == equal) { if (cc == equal) {
__ test(answer.reg(), Operand(answer.reg())); __ test(answer.reg(), Operand(answer.reg()));
} else { } else {
@ -4392,15 +4377,12 @@ void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) {
void CodeGenerator::GenerateArgumentsLength(ZoneList<Expression*>* args) { void CodeGenerator::GenerateArgumentsLength(ZoneList<Expression*>* args) {
ASSERT(args->length() == 0); ASSERT(args->length() == 0);
Result initial_value = allocator()->Allocate(eax);
ASSERT(initial_value.is_valid());
__ Set(initial_value.reg(),
Immediate(Smi::FromInt(scope_->num_parameters())));
// ArgumentsAccessStub takes the parameter count as an input argument // ArgumentsAccessStub takes the parameter count as an input argument
// in register eax. // in register eax. Create a constant result for it.
Result count(Handle<Smi>(Smi::FromInt(scope_->num_parameters())), this);
// Call the shared stub to get to the arguments.length. // Call the shared stub to get to the arguments.length.
ArgumentsAccessStub stub(ArgumentsAccessStub::READ_LENGTH); ArgumentsAccessStub stub(ArgumentsAccessStub::READ_LENGTH);
Result result = frame_->CallStub(&stub, &initial_value, 0); Result result = frame_->CallStub(&stub, &count);
frame_->Push(&result); frame_->Push(&result);
} }
@ -4475,20 +4457,15 @@ void CodeGenerator::GenerateSetValueOf(ZoneList<Expression*>* args) {
void CodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* args) { void CodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* args) {
ASSERT(args->length() == 1); ASSERT(args->length() == 1);
// Load the key into edx and set eax to the formal parameters count // ArgumentsAccessStub expects the key in edx and the formal
// for the currently executing function. // parameter count in eax.
Load(args->at(0)); Load(args->at(0));
Result key = frame_->Pop(); Result key = frame_->Pop();
key.ToRegister(edx); // Explicitly create a constant result.
Result count(Handle<Smi>(Smi::FromInt(scope_->num_parameters())), this);
Result parameters_count = allocator()->Allocate(eax);
ASSERT(parameters_count.is_valid());
__ Set(parameters_count.reg(),
Immediate(Smi::FromInt(scope_->num_parameters())));
// Call the shared stub to get to arguments[key]. // Call the shared stub to get to arguments[key].
ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT); ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT);
Result result = frame_->CallStub(&stub, &parameters_count, &key, 0); Result result = frame_->CallStub(&stub, &key, &count);
frame_->Push(&result); frame_->Push(&result);
} }
@ -4647,8 +4624,7 @@ void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) {
UnarySubStub stub; UnarySubStub stub;
// TODO(1222589): remove dependency of TOS being cached inside stub // TODO(1222589): remove dependency of TOS being cached inside stub
Result operand = frame_->Pop(); Result operand = frame_->Pop();
operand.ToRegister(eax); Result answer = frame_->CallStub(&stub, &operand);
Result answer = frame_->CallStub(&stub, &operand, 0);
frame_->Push(&answer); frame_->Push(&answer);
break; break;
} }
@ -4781,15 +4757,13 @@ void DeferredCountOperation::Generate() {
Result value(cgen); Result value(cgen);
enter()->Bind(&value); enter()->Bind(&value);
value.ToRegister(eax); // The stubs below expect their argument in eax.
if (is_postfix_) { if (is_postfix_) {
RevertToNumberStub to_number_stub(is_increment_); RevertToNumberStub to_number_stub(is_increment_);
value = generator()->frame()->CallStub(&to_number_stub, &value, 0); value = generator()->frame()->CallStub(&to_number_stub, &value);
} }
CounterOpStub stub(result_offset_, is_postfix_, is_increment_); CounterOpStub stub(result_offset_, is_postfix_, is_increment_);
value = generator()->frame()->CallStub(&stub, &value, 0); value = generator()->frame()->CallStub(&stub, &value);
exit_.Jump(&value); exit_.Jump(&value);
} }

View File

@ -241,6 +241,21 @@ Result VirtualFrame::RawCallStub(CodeStub* stub) {
} }
Result VirtualFrame::CallStub(CodeStub* stub, Result* arg) {
PrepareForCall(0, 0);
arg->Unuse();
return RawCallStub(stub);
}
Result VirtualFrame::CallStub(CodeStub* stub, Result* arg0, Result* arg1) {
PrepareForCall(0, 0);
arg0->Unuse();
arg1->Unuse();
return RawCallStub(stub);
}
Result VirtualFrame::CallRuntime(Runtime::Function* f, int arg_count) { Result VirtualFrame::CallRuntime(Runtime::Function* f, int arg_count) {
PrepareForCall(arg_count, arg_count); PrepareForCall(arg_count, arg_count);
ASSERT(cgen_->HasValidEntryRegisters()); ASSERT(cgen_->HasValidEntryRegisters());

View File

@ -248,27 +248,33 @@ class VirtualFrame : public Malloced {
// Push a try-catch or try-finally handler on top of the virtual frame. // Push a try-catch or try-finally handler on top of the virtual frame.
void PushTryHandler(HandlerType type); void PushTryHandler(HandlerType type);
// Call a code stub, given the number of arguments it expects on (and // Call stub given the number of arguments it expects on (and
// removes from) the top of the physical frame. // removes from) the stack.
Result CallStub(CodeStub* stub, int 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 // Call stub that expects its argument in r0. The argument is given
// removed from) the top of the physical frame. // as a result which must be the register r0.
Result CallStub(CodeStub* stub, Result* arg);
// Call stub that expects its arguments in r1 and r0. The arguments
// are given as results which must be the appropriate registers.
Result CallStub(CodeStub* stub, Result* arg0, Result* arg1);
// Call runtime given the number of arguments expected on (and
// removed from) the stack.
Result CallRuntime(Runtime::Function* f, int arg_count); Result CallRuntime(Runtime::Function* f, int arg_count);
Result CallRuntime(Runtime::FunctionId id, int arg_count); Result CallRuntime(Runtime::FunctionId id, int arg_count);
// Invoke a builtin, given the number of arguments it expects on (and // Invoke builtin given the number of arguments it expects on (and
// removes from) the top of the physical frame. // removes from) the stack.
Result InvokeBuiltin(Builtins::JavaScript id, Result InvokeBuiltin(Builtins::JavaScript id,
InvokeJSFlags flag, InvokeJSFlags flag,
Result* arg_count_register, Result* arg_count_register,
int arg_count); int arg_count);
// Call into a JS code object, given the number of arguments it // Call into an IC stub given the number of arguments it removes
// removes from the top of the physical frame. // from the stack. Register arguments are passed as results and
// Register arguments are passed as results and consumed by the call. // consumed by the call.
Result CallCodeObject(Handle<Code> ic, Result CallCodeObject(Handle<Code> ic,
RelocInfo::Mode rmode, RelocInfo::Mode rmode,
int dropped_args); int dropped_args);

View File

@ -734,6 +734,39 @@ Result VirtualFrame::RawCallStub(CodeStub* stub) {
} }
Result VirtualFrame::CallStub(CodeStub* stub, Result* arg) {
PrepareForCall(0, 0);
arg->ToRegister(eax);
arg->Unuse();
return RawCallStub(stub);
}
Result VirtualFrame::CallStub(CodeStub* stub, Result* arg0, Result* arg1) {
PrepareForCall(0, 0);
if (arg0->is_register() && arg0->reg().is(eax)) {
if (arg1->is_register() && arg1->reg().is(edx)) {
// Wrong registers.
__ xchg(eax, edx);
} else {
// Register edx is free for arg0, which frees eax for arg1.
arg0->ToRegister(edx);
arg1->ToRegister(eax);
}
} else {
// Register eax is free for arg1, which guarantees edx is free for
// arg0.
arg1->ToRegister(eax);
arg0->ToRegister(edx);
}
arg0->Unuse();
arg1->Unuse();
return RawCallStub(stub);
}
Result VirtualFrame::CallRuntime(Runtime::Function* f, int arg_count) { Result VirtualFrame::CallRuntime(Runtime::Function* f, int arg_count) {
PrepareForCall(arg_count, arg_count); PrepareForCall(arg_count, arg_count);
ASSERT(cgen_->HasValidEntryRegisters()); ASSERT(cgen_->HasValidEntryRegisters());

View File

@ -241,19 +241,28 @@ class VirtualFrame : public Malloced {
// Push a try-catch or try-finally handler on top of the virtual frame. // Push a try-catch or try-finally handler on top of the virtual frame.
void PushTryHandler(HandlerType type); void PushTryHandler(HandlerType type);
// Call a code stub, given the number of arguments it expects on (and // Call stub given the number of arguments it expects on (and
// removes from) the top of the physical frame. // removes from) the stack.
Result CallStub(CodeStub* stub, int 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 // Call stub that takes a single argument passed in eax. The
// removed from) the top of the physical frame. // argument is given as a result which does not have to be eax or
// even a register. The argument is consumed by the call.
Result CallStub(CodeStub* stub, Result* arg);
// Call stub that takes a pair of arguments passed in edx (arg0) and
// eax (arg1). The arguments are given as results which do not have
// to be in the proper registers or even in registers. The
// arguments are consumed by the call.
Result CallStub(CodeStub* stub, Result* arg0, Result* arg1);
// Call runtime given the number of arguments expected on (and
// removed from) the stack.
Result CallRuntime(Runtime::Function* f, int arg_count); Result CallRuntime(Runtime::Function* f, int arg_count);
Result CallRuntime(Runtime::FunctionId id, int arg_count); Result CallRuntime(Runtime::FunctionId id, int arg_count);
// Invoke a builtin, given the number of arguments it expects on (and // Invoke builtin given the number of arguments it expects on (and
// removes from) the top of the physical frame. // removes from) the stack.
Result InvokeBuiltin(Builtins::JavaScript id, Result InvokeBuiltin(Builtins::JavaScript id,
InvokeFlag flag, InvokeFlag flag,
int arg_count); int arg_count);

View File

@ -437,24 +437,6 @@ Result VirtualFrame::CallStub(CodeStub* stub, int arg_count) {
} }
Result VirtualFrame::CallStub(CodeStub* stub, Result* arg, int arg_count) {
PrepareForCall(arg_count, arg_count);
arg->Unuse();
return RawCallStub(stub);
}
Result VirtualFrame::CallStub(CodeStub* stub,
Result* arg0,
Result* arg1,
int arg_count) {
PrepareForCall(arg_count, arg_count);
arg0->Unuse();
arg1->Unuse();
return RawCallStub(stub);
}
void VirtualFrame::Push(Register reg) { void VirtualFrame::Push(Register reg) {
if (is_used(reg)) { if (is_used(reg)) {
elements_.Add(CopyElementAt(register_index(reg))); elements_.Add(CopyElementAt(register_index(reg)));