// The expression is a variable proxy that does not rewrite to a
// property. Global variables are treated as named property references.
if (var->is_global()) {
- // Named loads require object in eax. Named stores don't use references.
- // Spilling eax makes it free, so LoadGlobal loads directly into eax.
+ // If eax is free, the register allocator prefers it. Thus the code
+ // generator will load the global object into eax, which is where
+ // LoadIC wants it. Most uses of Reference call LoadIC directly
+ // after the reference is created.
frame_->Spill(eax);
LoadGlobal();
ref->set_type(Reference::NAMED);
// All extension objects were empty and it is safe to use a global
// load IC call.
+ // The register allocator prefers eax if it is free, so the code generator
+ // will load the global object directly into eax, which is where the LoadIC
+ // expects it.
+ frame_->Spill(eax);
LoadGlobal();
frame_->Push(slot->var()->name());
RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF)
// Duplicate the object as the IC receiver.
frame_->Dup();
Load(property->value());
- frame_->Push(key);
- Result ignored = frame_->CallStoreIC();
+ Result dummy = frame_->CallStoreIC(Handle<String>::cast(key), false);
+ dummy.Unuse();
break;
}
// Fall through
bool is_trivial_receiver = false;
if (var != NULL) {
name = var->name();
- LoadGlobal();
} else {
Literal* lit = prop->key()->AsLiteral();
- ASSERT(lit != NULL);
+ ASSERT_NOT_NULL(lit);
name = Handle<String>::cast(lit->handle());
// Do not materialize the receiver on the frame if it is trivial.
is_trivial_receiver = prop->obj()->IsTrivial();
}
if (node->starts_initialization_block()) {
+ ASSERT_EQ(NULL, var);
// Change to slow case in the beginning of an initialization block to
// avoid the quadratic behavior of repeatedly adding fast properties.
if (is_trivial_receiver) {
if (node->is_compound()) {
if (is_trivial_receiver) {
frame()->Push(prop->obj());
+ } else if (var != NULL) {
+ // The LoadIC stub expects the object in eax.
+ // Freeing eax causes the code generator to load the global into it.
+ frame_->Spill(eax);
+ LoadGlobal();
} else {
frame()->Dup();
}
// Perform the assignment. It is safe to ignore constants here.
ASSERT(var == NULL || var->mode() != Variable::CONST);
- ASSERT(node->op() != Token::INIT_CONST);
+ ASSERT_NE(Token::INIT_CONST, node->op());
if (is_trivial_receiver) {
Result value = frame()->Pop();
frame()->Push(prop->obj());
frame()->Push(&value);
}
CodeForSourcePosition(node->position());
- Result answer = EmitNamedStore(name);
+ bool is_contextual = (var != NULL);
+ Result answer = EmitNamedStore(name, is_contextual);
frame()->Push(&answer);
if (node->ends_initialization_block()) {
+ ASSERT_EQ(NULL, var);
// The argument to the runtime call is the receiver.
if (is_trivial_receiver) {
frame()->Push(prop->obj());
Result ignored = frame_->CallRuntime(Runtime::kToFastProperties, 1);
}
- ASSERT(frame()->height() == original_height + 1);
+ ASSERT_EQ(frame()->height(), original_height + 1);
}
#endif
Comment cmnt(masm_, "[ Named Property Assignment");
Property* prop = node->target()->AsProperty();
- ASSERT(prop != NULL);
+ ASSERT_NOT_NULL(prop);
// Evaluate the receiver subexpression.
Load(prop->obj());
}
-Result CodeGenerator::EmitNamedStore(Handle<String> name) {
+Result CodeGenerator::EmitNamedStore(Handle<String> name, bool is_contextual) {
#ifdef DEBUG
- int original_height = frame()->height();
+ int expected_height = frame()->height() - (is_contextual ? 1 : 2);
#endif
- frame()->Push(name);
- Result result = frame()->CallStoreIC();
+ Result result = frame()->CallStoreIC(name, is_contextual);
- ASSERT(frame()->height() == original_height - 2);
+ ASSERT_EQ(expected_height, frame()->height());
return result;
}
case NAMED: {
Comment cmnt(masm, "[ Store to named Property");
- Result answer = cgen_->EmitNamedStore(GetName());
+ Result answer = cgen_->EmitNamedStore(GetName(), false);
cgen_->frame()->Push(&answer);
set_unloaded();
break;
}
-Result VirtualFrame::CallStoreIC() {
- // Name, value, and receiver are on top of the frame. The IC
- // expects name in ecx, value in eax, and receiver in edx.
+Result VirtualFrame::CallStoreIC(Handle<String> name, bool is_contextual) {
+ // Value and (if not contextual) receiver are on top of the frame.
+ // The IC expects name in ecx, value in eax, and receiver in edx.
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
- Result name = Pop();
Result value = Pop();
- Result receiver = Pop();
- PrepareForCall(0, 0);
+ if (is_contextual) {
+ PrepareForCall(0, 0);
+ value.ToRegister(eax);
+ __ mov(edx, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
+ __ mov(ecx, name);
+ } else {
+ Result receiver = Pop();
+ PrepareForCall(0, 0);
- // Optimized for case in which name is a constant value.
- if (name.is_register() && (name.reg().is(edx) || name.reg().is(eax))) {
- if (!is_used(ecx)) {
- name.ToRegister(ecx);
- } else if (!is_used(ebx)) {
- name.ToRegister(ebx);
- } else {
- ASSERT(!is_used(edi)); // Only three results are live, so edi is free.
- name.ToRegister(edi);
- }
- }
- // Now name is not in edx or eax, so we can fix them, then move name to ecx.
- if (value.is_register() && value.reg().is(edx)) {
- if (receiver.is_register() && receiver.reg().is(eax)) {
- // Wrong registers.
- __ xchg(eax, edx);
+ if (value.is_register() && value.reg().is(edx)) {
+ if (receiver.is_register() && receiver.reg().is(eax)) {
+ // Wrong registers.
+ __ xchg(eax, edx);
+ } else {
+ // Register eax is free for value, which frees edx for receiver.
+ value.ToRegister(eax);
+ receiver.ToRegister(edx);
+ }
} else {
- // Register eax is free for value, which frees edx for receiver.
- value.ToRegister(eax);
+ // Register edx is free for receiver, which guarantees eax is free for
+ // value.
receiver.ToRegister(edx);
+ value.ToRegister(eax);
}
- } else {
- // Register edx is free for receiver, which guarantees eax is free for
- // value.
- receiver.ToRegister(edx);
- value.ToRegister(eax);
}
- // Receiver and value are in the right place, so ecx is free for name.
- name.ToRegister(ecx);
- name.Unuse();
+ __ mov(ecx, name);
value.Unuse();
- receiver.Unuse();
return RawCallCodeObject(ic, RelocInfo::CODE_TARGET);
}
Result CallLoadIC(RelocInfo::Mode mode);
// Call keyed load IC. Key and receiver are found on top of the
- // frame. They are not dropped.
+ // frame. Both are 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 store IC. If the load is contextual, value is found on top of the
+ // frame. If not, value and receiver are on the frame. Both are dropped.
+ Result CallStoreIC(Handle<String> name, bool is_contextual);
// Call keyed store IC. Value, key, and receiver are found on top
// of the frame. Key and receiver are not dropped.