Simplify the way the code generator handles calls to IC stubs. Before

we dispatched on the IC stub kind in a generic CallCodeObject
function.  Now, we have special functions for the load and store IC
stubs.

We also (for the load and store ICs) handle moving register arguments
into place only after the stack is prepared for the call.  This
replaces some memory-to-memory moves (for copies whose backing store
is occupied by a register needed for the arguments) with
memory-to-register moves.
Review URL: http://codereview.chromium.org/42602

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@1613 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 49af1766
......@@ -3235,17 +3235,12 @@ Result CodeGenerator::LoadFromGlobalSlotCheckExtensions(
// All extension objects were empty and it is safe to use a global
// load IC call.
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
// Load the global object.
LoadGlobal();
// Setup the name register. All non-reserved registers are available.
Result name = allocator_->Allocate(ecx);
ASSERT(name.is_valid());
__ mov(name.reg(), slot->var()->name());
RelocInfo::Mode rmode = (typeof_state == INSIDE_TYPEOF)
? RelocInfo::CODE_TARGET
: RelocInfo::CODE_TARGET_CONTEXT;
Result answer = frame_->CallCodeObject(ic, rmode, &name, 0);
frame_->Push(slot->var()->name());
RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF)
? RelocInfo::CODE_TARGET
: RelocInfo::CODE_TARGET_CONTEXT;
Result answer = frame_->CallLoadIC(mode);
// Discard the global object. The result is in answer.
frame_->Drop();
......@@ -3552,20 +3547,12 @@ void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) {
// else fall through.
case ObjectLiteral::Property::COMPUTED: {
Handle<Object> key(property->key()->handle());
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
if (key->IsSymbol()) {
// Duplicate the object as the IC receiver.
frame_->Dup();
Load(property->value());
Result value = frame_->Pop();
value.ToRegister(eax);
Result name = allocator_->Allocate(ecx);
ASSERT(name.is_valid());
__ Set(name.reg(), Immediate(key));
Result ignored =
frame_->CallCodeObject(ic, RelocInfo::CODE_TARGET,
&value, &name, 0);
frame_->Push(key);
Result ignored = frame_->CallStoreIC();
// Drop the duplicated receiver and ignore the result.
frame_->Drop();
break;
......@@ -5187,7 +5174,6 @@ class DeferredReferenceGetKeyedValue: public DeferredCode {
void DeferredReferenceGetKeyedValue::Generate() {
CodeGenerator* cgen = generator();
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
Result receiver(cgen);
Result key(cgen);
enter()->Bind(&receiver, &key);
......@@ -5200,14 +5186,10 @@ void DeferredReferenceGetKeyedValue::Generate() {
// it in the IC initialization code and patch the cmp instruction.
// This means that we cannot allow test instructions after calls to
// KeyedLoadIC stubs in other places.
Result value(cgen);
if (is_global_) {
value = cgen->frame()->CallCodeObject(ic,
RelocInfo::CODE_TARGET_CONTEXT,
0);
} else {
value = cgen->frame()->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0);
}
RelocInfo::Mode mode = is_global_
? RelocInfo::CODE_TARGET_CONTEXT
: RelocInfo::CODE_TARGET;
Result value = cgen->frame()->CallKeyedLoadIC(mode);
// The result needs to be specifically the eax register because the
// offset to the patch site will be expected in a test eax
// instruction.
......@@ -5269,21 +5251,16 @@ void Reference::GetValue(TypeofState typeof_state) {
// thrown below, we must distinguish between the two kinds of
// loads (typeof expression loads must not throw a reference
// error).
VirtualFrame* frame = cgen_->frame();
Comment cmnt(masm, "[ Load from named Property");
Handle<String> name(GetName());
cgen_->frame()->Push(GetName());
Variable* var = expression_->AsVariableProxy()->AsVariable();
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
// Setup the name register.
Result name_reg = cgen_->allocator()->Allocate(ecx);
ASSERT(name_reg.is_valid());
__ mov(name_reg.reg(), name);
ASSERT(var == NULL || var->is_global());
RelocInfo::Mode rmode = (var == NULL)
? RelocInfo::CODE_TARGET
: RelocInfo::CODE_TARGET_CONTEXT;
Result answer = frame->CallCodeObject(ic, rmode, &name_reg, 0);
frame->Push(&answer);
RelocInfo::Mode mode = (var == NULL)
? RelocInfo::CODE_TARGET
: RelocInfo::CODE_TARGET_CONTEXT;
Result answer = cgen_->frame()->CallLoadIC(mode);
cgen_->frame()->Push(&answer);
break;
}
......@@ -5373,20 +5350,18 @@ void Reference::GetValue(TypeofState typeof_state) {
cgen_->frame()->Push(&value);
} else {
VirtualFrame* frame = cgen_->frame();
Comment cmnt(masm, "[ Load from keyed Property");
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
RelocInfo::Mode rmode = is_global
? RelocInfo::CODE_TARGET_CONTEXT
: RelocInfo::CODE_TARGET;
Result answer = frame->CallCodeObject(ic, rmode, 0);
RelocInfo::Mode mode = is_global
? RelocInfo::CODE_TARGET_CONTEXT
: RelocInfo::CODE_TARGET;
Result answer = cgen_->frame()->CallKeyedLoadIC(mode);
// Make sure that we do not have a test instruction after the
// call. A test instruction after the call is used to
// indicate that we have generated an inline version of the
// keyed load. The explicit nop instruction is here because
// the push that follows might be peep-hole optimized away.
__ nop();
frame->Push(&answer);
cgen_->frame()->Push(&answer);
}
break;
}
......@@ -5430,11 +5405,9 @@ void Reference::TakeValue(TypeofState typeof_state) {
void Reference::SetValue(InitState init_state) {
ASSERT(cgen_->HasValidEntryRegisters());
ASSERT(!is_illegal());
MacroAssembler* masm = cgen_->masm();
VirtualFrame* frame = cgen_->frame();
switch (type_) {
case SLOT: {
Comment cmnt(masm, "[ Store to Slot");
Comment cmnt(cgen_->masm(), "[ Store to Slot");
Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot();
ASSERT(slot != NULL);
cgen_->StoreToSlot(slot, init_state);
......@@ -5442,35 +5415,17 @@ void Reference::SetValue(InitState init_state) {
}
case NAMED: {
Comment cmnt(masm, "[ Store to named Property");
// Call the appropriate IC code.
Handle<String> name(GetName());
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
// TODO(1222589): Make the IC grab the values from the stack.
Result argument = frame->Pop();
argument.ToRegister(eax);
ASSERT(argument.is_valid());
Result property_name = cgen_->allocator()->Allocate(ecx);
ASSERT(property_name.is_valid());
// Setup the name register.
__ mov(property_name.reg(), name);
Result answer = frame->CallCodeObject(ic, RelocInfo::CODE_TARGET,
&argument, &property_name, 0);
frame->Push(&answer);
Comment cmnt(cgen_->masm(), "[ Store to named Property");
cgen_->frame()->Push(GetName());
Result answer = cgen_->frame()->CallStoreIC();
cgen_->frame()->Push(&answer);
break;
}
case KEYED: {
Comment cmnt(masm, "[ Store to keyed Property");
// Call IC code.
Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
// TODO(1222589): Make the IC grab the values from the stack.
Result arg = frame->Pop();
arg.ToRegister(eax);
ASSERT(arg.is_valid());
Result answer = frame->CallCodeObject(ic, RelocInfo::CODE_TARGET,
&arg, 0);
frame->Push(&answer);
Comment cmnt(cgen_->masm(), "[ Store to keyed Property");
Result answer = cgen_->frame()->CallKeyedStoreIC();
cgen_->frame()->Push(&answer);
break;
}
......
......@@ -778,31 +778,70 @@ Result VirtualFrame::RawCallCodeObject(Handle<Code> code,
}
Result VirtualFrame::CallCodeObject(Handle<Code> code,
RelocInfo::Mode rmode,
Result* arg,
int dropped_args) {
int spilled_args = 0;
switch (code->kind()) {
case Code::LOAD_IC:
ASSERT(arg->reg().is(ecx));
ASSERT(dropped_args == 0);
spilled_args = 1;
break;
case Code::KEYED_STORE_IC:
ASSERT(arg->reg().is(eax));
ASSERT(dropped_args == 0);
spilled_args = 2;
break;
default:
// No other types of code objects are called with values
// in exactly one register.
UNREACHABLE();
break;
Result VirtualFrame::CallLoadIC(RelocInfo::Mode mode) {
// Name and receiver are on the top of the frame. The IC expects
// name in ecx and receiver on the stack. It does not drop the
// receiver.
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
Result name = Pop();
PrepareForCall(1, 0); // One stack arg, not callee-dropped.
name.ToRegister(ecx);
name.Unuse();
return RawCallCodeObject(ic, mode);
}
Result VirtualFrame::CallKeyedLoadIC(RelocInfo::Mode mode) {
// Key and receiver are on top of the frame. The IC expects them on
// the stack. It does not drop them.
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
PrepareForCall(2, 0); // Two stack args, neither callee-dropped.
return RawCallCodeObject(ic, mode);
}
Result VirtualFrame::CallStoreIC() {
// Name, value, and receiver are on top of the frame. The IC
// expects name in ecx, value in eax, and receiver on the stack. It
// does not drop the receiver.
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
Result name = Pop();
Result value = Pop();
PrepareForCall(1, 0); // One stack arg, not callee-dropped.
if (value.is_register() && value.reg().is(ecx)) {
if (name.is_register() && name.reg().is(eax)) {
// Wrong registers.
__ xchg(eax, ecx);
} else {
// Register eax is free for value, which frees ecx for name.
value.ToRegister(eax);
name.ToRegister(ecx);
}
} else {
// Register ecx is free for name, which guarantees eax is free for
// value.
name.ToRegister(ecx);
value.ToRegister(eax);
}
PrepareForCall(spilled_args, dropped_args);
arg->Unuse();
return RawCallCodeObject(code, rmode);
name.Unuse();
value.Unuse();
return RawCallCodeObject(ic, RelocInfo::CODE_TARGET);
}
Result VirtualFrame::CallKeyedStoreIC() {
// Value, key, and receiver are on the top of the frame. The IC
// expects value in eax and key and receiver on the stack. It does
// not drop the key and receiver.
Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
// TODO(1222589): Make the IC grab the values from the stack.
Result value = Pop();
PrepareForCall(2, 0); // Two stack args, neither callee-dropped.
value.ToRegister(eax);
value.Unuse();
return RawCallCodeObject(ic, RelocInfo::CODE_TARGET);
}
......@@ -813,12 +852,6 @@ Result VirtualFrame::CallCodeObject(Handle<Code> code,
int dropped_args) {
int spilled_args = 1;
switch (code->kind()) {
case Code::STORE_IC:
ASSERT(arg0->reg().is(eax));
ASSERT(arg1->reg().is(ecx));
ASSERT(dropped_args == 0);
spilled_args = 1;
break;
case Code::BUILTIN:
ASSERT(*code == Builtins::builtin(Builtins::JSConstructCall));
ASSERT(arg0->reg().is(eax));
......
......@@ -261,22 +261,34 @@ class VirtualFrame : public Malloced {
InvokeFlag flag,
int frame_arg_count);
// Call into a JS code object, given the number of arguments it
// removes from the top of the physical frame.
// Register arguments are passed as results and consumed by the call.
// 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* arg,
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.
// Receiver is not dropped.
Result CallLoadIC(RelocInfo::Mode mode);
// Call keyed load IC. Key and receiver are found on top of the
// frame. They are not dropped.
Result CallKeyedLoadIC(RelocInfo::Mode mode);
// Call store IC. Name, value, and receiver are found on top of the
// frame. Receiver is not dropped.
Result CallStoreIC();
// Call keyed store IC. Value, key, and receiver are found on top
// of the frame. Key and receiver are not dropped.
Result CallKeyedStoreIC();
// 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.
......
......@@ -455,10 +455,12 @@ Result VirtualFrame::CallCodeObject(Handle<Code> code,
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
......
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