Chromium Code Reviews| Index: src/codegen-ia32.cc |
| =================================================================== |
| --- src/codegen-ia32.cc (revision 246) |
| +++ src/codegen-ia32.cc (working copy) |
| @@ -115,9 +115,7 @@ |
| enum AccessType { |
| UNDEFINED, |
| LOAD, |
| - LOAD_TYPEOF_EXPR, |
| - STORE, |
| - INIT_CONST |
| + LOAD_TYPEOF_EXPR |
| }; |
| CodeGenState() |
| @@ -187,7 +185,6 @@ |
| // The following are used by class Reference. |
| void LoadReference(Reference* ref); |
| void UnloadReference(Reference* ref); |
| - friend class Reference; |
| // State |
| bool has_cc() const { return cc_reg_ >= 0; } |
| @@ -198,27 +195,40 @@ |
| Label* false_target() const { return state_->false_target(); } |
| // Expressions |
| - Operand GlobalObject() const { |
| + Operand GlobalObject() const { |
| return ContextOperand(esi, Context::GLOBAL_INDEX); |
| } |
| - // Support functions for accessing parameters. |
| + // Support functions for accessing parameters. Static versions can |
| + // require some code generator state to be passed in as arguments. |
| + static Operand ParameterOperand(Scope* scope, int index) { |
| + ASSERT(-2 <= index && index < scope->num_parameters()); |
| + return Operand(ebp, (1 + scope->num_parameters() - index) * kPointerSize); |
| + } |
| + |
| Operand ParameterOperand(int index) const { |
| - ASSERT(-2 <= index && index < scope_->num_parameters()); |
| - return Operand(ebp, (1 + scope_->num_parameters() - index) * kPointerSize); |
| + return ParameterOperand(scope_, index); |
| } |
| Operand ReceiverOperand() const { return ParameterOperand(-1); } |
| + |
| Operand FunctionOperand() const { |
| return Operand(ebp, JavaScriptFrameConstants::kFunctionOffset); |
| } |
| - Operand ContextOperand(Register context, int index) const { |
| + static Operand ContextOperand(Register context, int index) { |
| return Operand(context, Context::SlotOffset(index)); |
| } |
| - Operand SlotOperand(Slot* slot, Register tmp); |
| + static Operand SlotOperand(MacroAssembler* masm, |
| + Scope* scope, |
| + Slot* slot, |
| + Register tmp); |
| + Operand SlotOperand(Slot* slot, Register tmp) { |
| + return SlotOperand(masm_, scope_, slot, tmp); |
| + } |
| + |
| void LoadCondition(Expression* x, |
| CodeGenState::AccessType access, |
| Label* true_target, |
| @@ -237,20 +247,42 @@ |
| void LoadTypeofExpression(Expression* x); |
| // References |
| - void AccessReference(Reference* ref, CodeGenState::AccessType access); |
| - void GetValue(Reference* ref) { AccessReference(ref, CodeGenState::LOAD); } |
| - void SetValue(Reference* ref) { AccessReference(ref, CodeGenState::STORE); } |
| + // Generate code to fetch the value of a reference. The reference is |
| + // expected to be on top of the expression stack. It is left in place and |
| + // its value is pushed on top of it. |
| + void GetValue(Reference* ref); |
| + |
| + // Generate code to store a value in a reference. The stored value is |
| + // expected on top of the expression stack, with the reference immediately |
| + // below it. The expression stack is left unchanged. |
| + void SetValue(Reference* ref) { |
| + ASSERT(!has_cc()); |
| + ASSERT(!ref->is_illegal()); |
| + ref->expression()->GenerateStoreCode(masm_, scope_, ref, false); |
| + } |
| + |
| + // Same as SetValue, used to set the initial value of a constant. |
| void InitConst(Reference* ref) { |
| - AccessReference(ref, CodeGenState::INIT_CONST); |
| + ASSERT(!has_cc()); |
| + ASSERT(!ref->is_illegal()); |
| + ref->expression()->GenerateStoreCode(masm_, scope_, ref, true); |
| } |
| - void ToBoolean(Label* true_target, Label* false_target); |
| + // Generate code to fetch a value from a property of a reference. The |
| + // reference is expected on top of the expression stack. It is left in |
| + // place and its value is pushed on top of it. |
| + void GetReferenceProperty(Expression* key); |
| + // Generate code to store a value in a property of a reference. The |
| + // stored value is expected on top of the expression stack, with the |
| + // reference immediately below it. The expression stack is left |
| + // unchanged. |
| + static void SetReferenceProperty(MacroAssembler* masm, |
| + Reference* ref, |
| + Expression* key); |
| - // Access property from the reference (must be at the TOS). |
| - void AccessReferenceProperty(Expression* key, |
| - CodeGenState::AccessType access); |
| + void ToBoolean(Label* true_target, Label* false_target); |
| void GenericBinaryOperation( |
| Token::Value op, |
| @@ -316,6 +348,11 @@ |
| virtual void GenerateFastCharCodeAt(ZoneList<Expression*>* args); |
| virtual void GenerateObjectEquals(ZoneList<Expression*>* args); |
| + |
| + friend class Reference; |
| + friend class Property; |
| + friend class VariableProxy; |
| + friend class Slot; |
| }; |
| @@ -633,7 +670,10 @@ |
| } |
| -Operand Ia32CodeGenerator::SlotOperand(Slot* slot, Register tmp) { |
| +Operand Ia32CodeGenerator::SlotOperand(MacroAssembler* masm, |
| + Scope* scope, |
| + Slot* slot, |
| + Register tmp) { |
| // Currently, this assertion will fail if we try to assign to |
| // a constant variable that is constant because it is read-only |
| // (such as the variable referring to a named function expression). |
| @@ -645,10 +685,10 @@ |
| ASSERT(slot != NULL); |
| int index = slot->index(); |
| switch (slot->type()) { |
| - case Slot::PARAMETER: return ParameterOperand(index); |
| + case Slot::PARAMETER: return ParameterOperand(scope, index); |
| case Slot::LOCAL: { |
| - ASSERT(0 <= index && index < scope_->num_stack_slots()); |
| + ASSERT(0 <= index && index < scope->num_stack_slots()); |
| const int kLocal0Offset = JavaScriptFrameConstants::kLocal0Offset; |
| return Operand(ebp, kLocal0Offset - index * kPointerSize); |
| } |
| @@ -657,15 +697,15 @@ |
| // Follow the context chain if necessary. |
| ASSERT(!tmp.is(esi)); // do not overwrite context register |
| Register context = esi; |
| - int chain_length = scope_->ContextChainLength(slot->var()->scope()); |
| + int chain_length = scope->ContextChainLength(slot->var()->scope()); |
| for (int i = chain_length; i-- > 0;) { |
| // Load the closure. |
| // (All contexts, even 'with' contexts, have a closure, |
| // and it is the same for all contexts inside a function. |
| // There is no need to go to the function context first.) |
| - __ mov(tmp, ContextOperand(context, Context::CLOSURE_INDEX)); |
| + masm->mov(tmp, ContextOperand(context, Context::CLOSURE_INDEX)); |
| // Load the function context (which is the incoming, outer context). |
| - __ mov(tmp, FieldOperand(tmp, JSFunction::kContextOffset)); |
| + masm->mov(tmp, FieldOperand(tmp, JSFunction::kContextOffset)); |
| context = tmp; |
| } |
| // We may have a 'with' context now. Get the function context. |
| @@ -675,7 +715,7 @@ |
| // cause the function context of a function context is itself. Before |
| // deleting this mov we should try to create a counter-example first, |
| // though...) |
| - __ mov(tmp, ContextOperand(context, Context::FCONTEXT_INDEX)); |
| + masm->mov(tmp, ContextOperand(context, Context::FCONTEXT_INDEX)); |
| return ContextOperand(tmp, index); |
| } |
| @@ -852,18 +892,123 @@ |
| } |
| -void Ia32CodeGenerator::AccessReference(Reference* ref, |
| - CodeGenState::AccessType access) { |
| +void Ia32CodeGenerator::GetValue(Reference* ref) { |
| ASSERT(!has_cc()); |
| ASSERT(ref->type() != Reference::ILLEGAL); |
| CodeGenState* old_state = state_; |
| - CodeGenState new_state(access, ref, true_target(), false_target()); |
| + CodeGenState new_state(CodeGenState::LOAD, ref, true_target(), |
| + false_target()); |
| state_ = &new_state; |
| Visit(ref->expression()); |
| state_ = old_state; |
| } |
| +void Property::GenerateStoreCode(MacroAssembler* masm, |
| + Scope* scope, |
| + Reference* ref, |
| + bool is_const_init) { |
| + Comment cmnt(masm, "[ Store to Property"); |
| + masm->RecordPosition(position()); |
| + Ia32CodeGenerator::SetReferenceProperty(masm, ref, key()); |
| +} |
| + |
| + |
| +void VariableProxy::GenerateStoreCode(MacroAssembler* masm, |
| + Scope* scope, |
| + Reference* ref, |
| + bool is_const_init) { |
| + |
| + Comment cmnt(masm, "[ Store to VariableProxy"); |
| + Variable* node = var(); |
| + |
| + Expression* expr = node->rewrite(); |
| + if (expr != NULL) { |
| + expr->GenerateStoreCode(masm, scope, ref, is_const_init); |
| + } else { |
| + ASSERT(node->is_global()); |
| + if (node->AsProperty() != NULL) { |
| + masm->RecordPosition(node->AsProperty()->position()); |
| + } |
| + Ia32CodeGenerator::SetReferenceProperty(masm, ref, |
| + new Literal(node->name())); |
| + } |
| +} |
| + |
| + |
| +void Slot::GenerateStoreCode(MacroAssembler* masm, |
| + Scope* scope, |
| + Reference* ref, |
| + bool is_const_init) { |
| + Comment cmnt(masm, "[ Store to Slot"); |
| + |
| + if (type() == Slot::LOOKUP) { |
| + ASSERT(var()->mode() == Variable::DYNAMIC); |
| + |
| + // For now, just do a runtime call. |
| + masm->push(Operand(esi)); |
| + masm->push(Immediate(var()->name())); |
| + |
| + if (is_const_init) { |
| + // Same as the case for a normal store, but ignores attribute |
| + // (e.g. READ_ONLY) of context slot so that we can initialize const |
| + // properties (introduced via eval("const foo = (some expr);")). Also, |
| + // uses the current function context instead of the top context. |
| + // |
| + // Note that we must declare the foo upon entry of eval(), via a |
| + // context slot declaration, but we cannot initialize it at the same |
| + // time, because the const declaration may be at the end of the eval |
| + // code (sigh...) and the const variable may have been used before |
| + // (where its value is 'undefined'). Thus, we can only do the |
| + // initialization when we actually encounter the expression and when |
| + // the expression operands are defined and valid, and thus we need the |
| + // split into 2 operations: declaration of the context slot followed |
| + // by initialization. |
| + masm->CallRuntime(Runtime::kInitializeConstContextSlot, 3); |
| + } else { |
| + masm->CallRuntime(Runtime::kStoreContextSlot, 3); |
| + } |
| + // Storing a variable must keep the (new) value on the expression |
| + // stack. This is necessary for compiling assignment expressions. |
| + masm->push(eax); |
| + |
| + } else { |
| + ASSERT(var()->mode() != Variable::DYNAMIC); |
| + |
| + Label exit; |
| + if (is_const_init) { |
| + ASSERT(var()->mode() == Variable::CONST); |
| + // Only the first const initialization must be executed (the slot |
| + // still contains 'the hole' value). When the assignment is executed, |
| + // the code is identical to a normal store (see below). |
| + Comment cmnt(masm, "[ Init const"); |
| + masm->mov(eax, Ia32CodeGenerator::SlotOperand(masm, scope, this, ecx)); |
| + masm->cmp(eax, Factory::the_hole_value()); |
| + masm->j(not_equal, &exit); |
| + } |
| + |
| + // We must execute the store. |
| + // Storing a variable must keep the (new) value on the stack. This is |
| + // necessary for compiling assignment expressions. ecx may be loaded |
| + // with context; used below in RecordWrite. |
| + // |
| + // Note: We will reach here even with node->var()->mode() == |
| + // Variable::CONST because of const declarations which will initialize |
| + // consts to 'the hole' value and by doing so, end up calling this |
| + // code. |
| + masm->pop(eax); |
| + masm->mov(Ia32CodeGenerator::SlotOperand(masm, scope, this, ecx), eax); |
| + masm->push(eax); // RecordWrite may destroy the value in eax. |
| + if (type() == Slot::CONTEXT) { |
| + // ecx is loaded with context when calling SlotOperand above. |
| + int offset = FixedArray::kHeaderSize + index() * kPointerSize; |
| + masm->RecordWrite(ecx, offset, eax, ebx); |
| + } |
| + masm->bind(&exit); |
| + } |
| +} |
| + |
| + |
| #undef __ |
| #define __ masm-> |
| @@ -991,63 +1136,41 @@ |
| } |
| -void Ia32CodeGenerator::AccessReferenceProperty( |
| - Expression* key, |
| - CodeGenState::AccessType access) { |
| +void Ia32CodeGenerator::GetReferenceProperty(Expression* key) { |
| Reference::Type type = ref()->type(); |
| - ASSERT(type != Reference::ILLEGAL); |
| + ASSERT(!ref()->is_illegal()); |
|
iposva
2008/09/10 18:01:44
Same nit as on ARM: Don't you want to assert befor
Kevin Millikin (Chromium)
2008/09/11 07:15:55
Done.
|
| - // TODO(1241834): Make sure that this is sufficient. If there is a chance |
| - // that reference errors can be thrown below, we must distinguish |
| - // between the 2 kinds of loads (typeof expression loads must not |
| - // throw a reference error). |
| - bool is_load = (access == CodeGenState::LOAD || |
| - access == CodeGenState::LOAD_TYPEOF_EXPR); |
| - |
| + // TODO(1241834): Make sure that this it is safe to ignore the distinction |
| + // between access types LOAD and LOAD_TYPEOF_EXPR. If there is a chance |
| + // that reference errors can be thrown below, we must distinguish between |
| + // the two kinds of loads (typeof expression loads must not throw a |
| + // reference error). |
| if (type == Reference::NAMED) { |
| // Compute the name of the property. |
| Literal* literal = key->AsLiteral(); |
| Handle<String> name(String::cast(*literal->handle())); |
| - // Call the appropriate IC code. |
| - if (is_load) { |
| - Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
| - Variable* var = ref()->expression()->AsVariableProxy()->AsVariable(); |
| - // Setup the name register. |
| - __ Set(ecx, Immediate(name)); |
| - if (var != NULL) { |
| - ASSERT(var->is_global()); |
| - __ call(ic, code_target_context); |
| - } else { |
| - __ call(ic, code_target); |
| - } |
| + Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
| + Variable* var = ref()->expression()->AsVariableProxy()->AsVariable(); |
| + // Setup the name register. |
| + __ Set(ecx, Immediate(name)); |
| + if (var != NULL) { |
| + ASSERT(var->is_global()); |
| + __ call(ic, code_target_context); |
| } else { |
| - Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
| - // TODO(1222589): Make the IC grab the values from the stack. |
| - __ pop(eax); |
| - // Setup the name register. |
| - __ Set(ecx, Immediate(name)); |
| __ call(ic, code_target); |
| } |
| } else { |
| // Access keyed property. |
| ASSERT(type == Reference::KEYED); |
| - if (is_load) { |
| - // Call IC code. |
| - Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); |
| - Variable* var = ref()->expression()->AsVariableProxy()->AsVariable(); |
| - if (var != NULL) { |
| - ASSERT(var->is_global()); |
| - __ call(ic, code_target_context); |
| - } else { |
| - __ call(ic, code_target); |
| - } |
| + // Call IC code. |
| + Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); |
| + Variable* var = ref()->expression()->AsVariableProxy()->AsVariable(); |
| + if (var != NULL) { |
| + ASSERT(var->is_global()); |
| + __ call(ic, code_target_context); |
| } else { |
| - // Call IC code. |
| - Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); |
| - // TODO(1222589): Make the IC grab the values from the stack. |
| - __ pop(eax); |
| __ call(ic, code_target); |
| } |
| } |
| @@ -1055,6 +1178,38 @@ |
| } |
| +void Ia32CodeGenerator::SetReferenceProperty(MacroAssembler* masm, |
| + Reference* ref, |
| + Expression* key) { |
| + Reference::Type type = ref->type(); |
| + ASSERT(!ref->is_illegal()); |
| + |
| + if (type == Reference::NAMED) { |
| + // Compute the name of the property. |
| + Literal* literal = key->AsLiteral(); |
| + Handle<String> name(String::cast(*literal->handle())); |
| + |
| + // Call the appropriate IC code. |
| + Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
| + // TODO(1222589): Make the IC grab the values from the stack. |
| + masm->pop(eax); |
| + // Setup the name register. |
| + masm->Set(ecx, Immediate(name)); |
| + masm->call(ic, code_target); |
| + } else { |
| + // Access keyed property. |
| + ASSERT(type == Reference::KEYED); |
| + |
| + // Call IC code. |
| + Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); |
| + // TODO(1222589): Make the IC grab the values from the stack. |
| + masm->pop(eax); |
| + masm->call(ic, code_target); |
| + } |
| + masm->push(eax); // IC call leaves result in eax, push it out |
| +} |
| + |
| + |
| #undef __ |
| #define __ masm-> |
| @@ -3325,6 +3480,7 @@ |
| void Ia32CodeGenerator::VisitSlot(Slot* node) { |
| + ASSERT(access() != CodeGenState::UNDEFINED); |
| Comment cmnt(masm_, "[ Slot"); |
| if (node->type() == Slot::LOOKUP) { |
| @@ -3334,151 +3490,56 @@ |
| __ push(Operand(esi)); |
| __ push(Immediate(node->var()->name())); |
| - switch (access()) { |
| - case CodeGenState::UNDEFINED: |
| - UNREACHABLE(); |
| - break; |
| - |
| - case CodeGenState::LOAD: |
| - __ CallRuntime(Runtime::kLoadContextSlot, 2); |
| - __ push(eax); |
| - // result (TOS) is the value that was loaded |
| - break; |
| - |
| - case CodeGenState::LOAD_TYPEOF_EXPR: |
| - __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); |
| - __ push(eax); |
| - // result (TOS) is the value that was loaded |
| - break; |
| - |
| - case CodeGenState::STORE: |
| - // Storing a variable must keep the (new) value on the |
| - // stack. This is necessary for compiling assignment |
| - // expressions. |
| - __ CallRuntime(Runtime::kStoreContextSlot, 3); |
| - __ push(eax); |
| - // result (TOS) is the value that was stored |
| - break; |
| - |
| - case CodeGenState::INIT_CONST: |
| - // Same as STORE but ignores attribute (e.g. READ_ONLY) of |
| - // context slot so that we can initialize const properties |
| - // (introduced via eval("const foo = (some expr);")). Also, |
| - // uses the current function context instead of the top |
| - // context. |
| - // |
| - // Note that we must declare the foo upon entry of eval(), |
| - // via a context slot declaration, but we cannot initialize |
| - // it at the same time, because the const declaration may |
| - // be at the end of the eval code (sigh...) and the const |
| - // variable may have been used before (where its value is |
| - // 'undefined'). Thus, we can only do the initialization |
| - // when we actually encounter the expression and when the |
| - // expression operands are defined and valid, and thus we |
| - // need the split into 2 operations: declaration of the |
| - // context slot followed by initialization. |
| - // |
| - __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); |
| - __ push(eax); |
| - break; |
| + if (access() == CodeGenState::LOAD) { |
| + __ CallRuntime(Runtime::kLoadContextSlot, 2); |
| + } else { |
| + // CodeGenState::LOAD_TYPEOF_EXPR. |
|
iposva
2008/09/10 18:01:44
Same comment as on ARM: Please assert that the Cod
Kevin Millikin (Chromium)
2008/09/11 07:15:55
Done.
|
| + __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); |
| } |
| + __ push(eax); |
| } else { |
| - // Note: We would like to keep the assert below, but it fires because |
| - // of some nasty code in LoadTypeofExpression() which should be removed... |
| + // Note: We would like to keep the assert below, but it fires because of |
| + // some nasty code in LoadTypeofExpression() which should be removed... |
| // ASSERT(node->var()->mode() != Variable::DYNAMIC); |
| - switch (access()) { |
| - case CodeGenState::UNDEFINED: |
| - UNREACHABLE(); |
| - break; |
| - |
| - case CodeGenState::LOAD: // fall through |
| - case CodeGenState::LOAD_TYPEOF_EXPR: |
| - if (node->var()->mode() == Variable::CONST) { |
| - // Const slots may contain 'the hole' value (the constant hasn't |
| - // been initialized yet) which needs to be converted into the |
| - // 'undefined' value. |
| - Comment cmnt(masm_, "[ Load const"); |
| - Label L; |
| - __ mov(eax, SlotOperand(node, ecx)); |
| - __ cmp(eax, Factory::the_hole_value()); |
| - __ j(not_equal, &L); |
| - __ mov(eax, Factory::undefined_value()); |
| - __ bind(&L); |
| - __ push(eax); |
| - } else { |
| - __ push(SlotOperand(node, ecx)); |
| - } |
| - break; |
| - |
| - case CodeGenState::INIT_CONST: |
| - ASSERT(node->var()->mode() == Variable::CONST); |
| - // Only the first const initialization must be executed (the slot |
| - // still contains 'the hole' value). When the assignment is executed, |
| - // the code is identical to a normal store (see below). |
| - { Comment cmnt(masm_, "[ Init const"); |
| - Label L; |
| - __ mov(eax, SlotOperand(node, ecx)); |
| - __ cmp(eax, Factory::the_hole_value()); |
| - __ j(not_equal, &L); |
| - // We must execute the store. |
| - __ mov(eax, TOS); |
| - __ mov(SlotOperand(node, ecx), eax); |
| - if (node->type() == Slot::CONTEXT) { |
| - // ecx is loaded with context when calling SlotOperand above. |
| - int offset = FixedArray::kHeaderSize + node->index() * kPointerSize; |
| - __ RecordWrite(ecx, offset, eax, ebx); |
| - } |
| - __ bind(&L); |
| - } |
| - break; |
| - |
| - case CodeGenState::STORE: |
| - // Storing a variable must keep the (new) value on the stack. This |
| - // is necessary for compiling assignment expressions. |
| - // ecx may be loaded with context; used below in RecordWrite. |
| - // |
| - // Note: We will reach here even with node->var()->mode() == |
| - // Variable::CONST because of const declarations which will |
| - // initialize consts to 'the hole' value and by doing so, end |
| - // up calling this code. |
| - __ pop(eax); |
| - __ mov(SlotOperand(node, ecx), eax); |
| - __ push(eax); // RecordWrite may destroy the value in eax. |
| - if (node->type() == Slot::CONTEXT) { |
| - // ecx is loaded with context when calling SlotOperand above. |
| - int offset = FixedArray::kHeaderSize + node->index() * kPointerSize; |
| - __ RecordWrite(ecx, offset, eax, ebx); |
| - } |
| - break; |
| + if (node->var()->mode() == Variable::CONST) { |
| + // Const slots may contain 'the hole' value (the constant hasn't been |
| + // initialized yet) which needs to be converted into the 'undefined' |
| + // value. |
| + Comment cmnt(masm_, "[ Load const"); |
| + Label L; |
| + __ mov(eax, SlotOperand(node, ecx)); |
| + __ cmp(eax, Factory::the_hole_value()); |
| + __ j(not_equal, &L); |
| + __ mov(eax, Factory::undefined_value()); |
| + __ bind(&L); |
| + __ push(eax); |
| + } else { |
| + __ push(SlotOperand(node, ecx)); |
| } |
| } |
| } |
| -void Ia32CodeGenerator::VisitVariableProxy(VariableProxy* proxy_node) { |
| +void Ia32CodeGenerator::VisitVariableProxy(VariableProxy* node) { |
| Comment cmnt(masm_, "[ VariableProxy"); |
| - Variable* node = proxy_node->var(); |
| + Variable* var_node = node->var(); |
| - Expression* x = node->rewrite(); |
| - if (x != NULL) { |
| - Visit(x); |
| - return; |
| - } |
| - |
| - ASSERT(node->is_global()); |
| - if (is_referenced()) { |
| - if (node->AsProperty() != NULL) { |
| - __ RecordPosition(node->AsProperty()->position()); |
| + Expression* expr = var_node->rewrite(); |
| + if (expr != NULL) { |
| + Visit(expr); |
| + } else { |
| + ASSERT(var_node->is_global()); |
| + if (is_referenced()) { |
| + if (var_node->AsProperty() != NULL) { |
| + __ RecordPosition(var_node->AsProperty()->position()); |
| + } |
| + GetReferenceProperty(new Literal(var_node->name())); |
| + } else { |
| + Reference property(this, node); |
| + GetValue(&property); |
| } |
| - AccessReferenceProperty(new Literal(node->name()), access()); |
| - |
| - } else { |
| - // All stores are through references. |
| - ASSERT(access() != CodeGenState::STORE); |
| - Reference property(this, proxy_node); |
| - GetValue(&property); |
| } |
| } |
| @@ -3784,10 +3845,8 @@ |
| if (is_referenced()) { |
| __ RecordPosition(node->position()); |
| - AccessReferenceProperty(node->key(), access()); |
| + GetReferenceProperty(node->key()); |
| } else { |
| - // All stores are through references. |
| - ASSERT(access() != CodeGenState::STORE); |
| Reference property(this, node); |
| __ RecordPosition(node->position()); |
| GetValue(&property); |