Index: src/codegen-arm.cc |
=================================================================== |
--- src/codegen-arm.cc (revision 246) |
+++ src/codegen-arm.cc (working copy) |
@@ -109,9 +109,7 @@ |
enum AccessType { |
UNDEFINED, |
LOAD, |
- LOAD_TYPEOF_EXPR, |
- STORE, |
- INIT_CONST |
+ LOAD_TYPEOF_EXPR |
}; |
CodeGenState() |
@@ -181,7 +179,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_ != al; } |
@@ -197,22 +194,33 @@ |
return ContextOperand(cp, Context::GLOBAL_INDEX); |
} |
- MemOperand ContextOperand(Register context, int index) const { |
+ static MemOperand ContextOperand(Register context, int index) { |
return MemOperand(context, Context::SlotOffset(index)); |
} |
- MemOperand ParameterOperand(int index) const { |
+ static MemOperand ParameterOperand(Scope* scope, int index) { |
// index -2 corresponds to the activated closure, -1 corresponds |
// to the receiver |
- ASSERT(-2 <= index && index < scope_->num_parameters()); |
+ ASSERT(-2 <= index && index < scope->num_parameters()); |
int offset = JavaScriptFrameConstants::kParam0Offset - index * kPointerSize; |
return MemOperand(pp, offset); |
} |
+ MemOperand ParameterOperand(int index) const { |
+ return ParameterOperand(scope_, index); |
+ } |
+ |
MemOperand FunctionOperand() const { return ParameterOperand(-2); } |
- MemOperand SlotOperand(Slot* slot, Register tmp); |
+ static MemOperand SlotOperand(MacroAssembler* masm, |
+ Scope* scope, |
+ Slot* slot, |
+ Register tmp); |
+ MemOperand SlotOperand(Slot* slot, Register tmp) { |
+ return SlotOperand(masm_, scope_, slot, tmp); |
+ } |
+ |
void LoadCondition(Expression* x, CodeGenState::AccessType access, |
Label* true_target, Label* false_target, bool force_cc); |
void Load(Expression* x, |
@@ -227,22 +235,48 @@ |
// through the context chain. |
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); } |
- void InitConst(Reference* ref) { |
- AccessReference(ref, CodeGenState::INIT_CONST); |
+ // 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); |
} |
- void ToBoolean(Label* true_target, Label* false_target); |
+ // 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 InitConst(Reference* ref) { |
+ ASSERT(!has_cc()); |
+ ASSERT(!ref->is_illegal()); |
+ ref->expression()->GenerateStoreCode(masm_, scope_, ref, true); |
+ } |
+ // 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); |
- // Access property from the reference (must be at the TOS). |
- void AccessReferenceProperty(Expression* key, |
- CodeGenState::AccessType access); |
+ // 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); |
+ |
+ void ToBoolean(Label* true_target, Label* false_target); |
+ |
void GenericBinaryOperation(Token::Value op); |
void Comparison(Condition cc, bool strict = false); |
@@ -297,6 +331,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; |
}; |
@@ -599,7 +638,10 @@ |
} |
-MemOperand ArmCodeGenerator::SlotOperand(Slot* slot, Register tmp) { |
+MemOperand ArmCodeGenerator::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). |
@@ -612,11 +654,11 @@ |
int index = slot->index(); |
switch (slot->type()) { |
case Slot::PARAMETER: |
- return ParameterOperand(index); |
+ return ParameterOperand(scope, index); |
case Slot::LOCAL: { |
ASSERT(0 <= index && |
- index < scope_->num_stack_slots() && |
+ index < scope->num_stack_slots() && |
index >= 0); |
int local_offset = JavaScriptFrameConstants::kLocal0Offset - |
index * kPointerSize; |
@@ -627,15 +669,15 @@ |
// Follow the context chain if necessary. |
ASSERT(!tmp.is(cp)); // do not overwrite context register |
Register context = cp; |
- 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.) |
- __ ldr(tmp, ContextOperand(context, Context::CLOSURE_INDEX)); |
+ masm->ldr(tmp, ContextOperand(context, Context::CLOSURE_INDEX)); |
// Load the function context (which is the incoming, outer context). |
- __ ldr(tmp, FieldMemOperand(tmp, JSFunction::kContextOffset)); |
+ masm->ldr(tmp, FieldMemOperand(tmp, JSFunction::kContextOffset)); |
context = tmp; |
} |
// We may have a 'with' context now. Get the function context. |
@@ -645,7 +687,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...) |
- __ ldr(tmp, ContextOperand(context, Context::FCONTEXT_INDEX)); |
+ masm->ldr(tmp, ContextOperand(context, Context::FCONTEXT_INDEX)); |
return ContextOperand(tmp, index); |
} |
@@ -822,18 +864,128 @@ |
} |
-void ArmCodeGenerator::AccessReference(Reference* ref, |
- CodeGenState::AccessType access) { |
+void ArmCodeGenerator::GetValue(Reference* ref) { |
ASSERT(!has_cc()); |
- ASSERT(ref->type() != Reference::ILLEGAL); |
+ ASSERT(!ref->is_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()); |
+ ArmCodeGenerator::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()); |
+ } |
+ ArmCodeGenerator::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(cp); |
+ masm->mov(r0, Operand(var()->name())); |
+ masm->push(r0); |
+ |
+ 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(r0); |
+ |
+ } 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->ldr(r2, ArmCodeGenerator::SlotOperand(masm, scope, this, r2)); |
+ masm->cmp(r2, Operand(Factory::the_hole_value())); |
+ masm->b(ne, &exit); |
+ } |
+ |
+ // We must execute the store. |
+ // r2 may be loaded with context; used below in RecordWrite. |
+ // Storing a variable must keep the (new) value on the stack. This is |
+ // necessary for compiling assignment expressions. |
+ // |
+ // Note: We will reach here even with 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. r2 may be |
+ // loaded with context; used below in RecordWrite. |
+ masm->pop(r0); |
+ masm->str(r0, ArmCodeGenerator::SlotOperand(masm, scope, this, r2)); |
+ masm->push(r0); |
+ |
+ if (type() == Slot::CONTEXT) { |
+ // Skip write barrier if the written value is a smi. |
+ masm->tst(r0, Operand(kSmiTagMask)); |
+ masm->b(eq, &exit); |
+ // r2 is loaded with context when calling SlotOperand above. |
+ int offset = FixedArray::kHeaderSize + index() * kPointerSize; |
+ masm->mov(r3, Operand(offset)); |
+ masm->RecordWrite(r2, r3, r1); |
+ } |
+ masm->bind(&exit); |
+ } |
+} |
+ |
+ |
// ECMA-262, section 9.2, page 30: ToBoolean(). Convert the given |
// register to a boolean in the condition code register. The code |
// may jump to 'false_target' in case the register converts to 'false'. |
@@ -1836,42 +1988,29 @@ |
#define __ masm_-> |
-void ArmCodeGenerator::AccessReferenceProperty( |
- Expression* key, |
- CodeGenState::AccessType access) { |
+void ArmCodeGenerator::GetReferenceProperty(Expression* key) { |
Reference::Type type = ref()->type(); |
- ASSERT(type != Reference::ILLEGAL); |
+ ASSERT(!ref()->is_illegal()); |
- // 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) { |
- // Setup the name register. |
- __ mov(r2, Operand(name)); |
- Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
- Variable* var = ref()->expression()->AsVariableProxy()->AsVariable(); |
- if (var != NULL) { |
- ASSERT(var->is_global()); |
- __ Call(ic, code_target_context); |
- } else { |
- __ Call(ic, code_target); |
- } |
- |
+ // Setup the name register. |
+ __ mov(r2, Operand(name)); |
+ Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
+ Variable* var = ref()->expression()->AsVariableProxy()->AsVariable(); |
+ if (var != NULL) { |
+ ASSERT(var->is_global()); |
+ __ Call(ic, code_target_context); |
} else { |
- __ pop(r0); // value |
- // Setup the name register. |
- __ mov(r2, Operand(name)); |
- Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
__ Call(ic, code_target); |
} |
@@ -1879,21 +2018,44 @@ |
// Access keyed property. |
ASSERT(type == Reference::KEYED); |
- if (is_load) { |
- // TODO(1224671): Implement inline caching for keyed loads as on ia32. |
- GetPropertyStub stub; |
- __ CallStub(&stub); |
- |
- } else { |
- __ pop(r0); // value |
- SetPropertyStub stub; |
- __ CallStub(&stub); |
- } |
+ // TODO(1224671): Implement inline caching for keyed loads as on ia32. |
+ GetPropertyStub stub; |
+ __ CallStub(&stub); |
} |
__ push(r0); |
} |
+void ArmCodeGenerator::SetReferenceProperty(MacroAssembler* masm, |
+ Reference* ref, |
+ Expression* key) { |
+ Reference::Type type = ref->type(); |
+ ASSERT(!ref->is_illegal()); |
iposva
2008/09/10 18:01:44
Nit: Don't you want to assert before accessing any
Kevin Millikin (Chromium)
2008/09/11 07:15:55
Changed. Illegal references have a type, so it's
|
+ |
+ 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. |
+ masm->pop(r0); // value |
+ // Setup the name register. |
+ masm->mov(r2, Operand(name)); |
+ Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
+ masm->Call(ic, code_target); |
+ |
+ } else { |
+ // Access keyed property. |
+ ASSERT(type == Reference::KEYED); |
+ |
+ masm->pop(r0); // value |
+ SetPropertyStub stub; |
+ masm->CallStub(&stub); |
+ } |
+ masm->push(r0); |
+} |
+ |
+ |
void ArmCodeGenerator::GenericBinaryOperation(Token::Value op) { |
// sp[0] : y |
// sp[1] : x |
@@ -3116,6 +3278,7 @@ |
void ArmCodeGenerator::VisitSlot(Slot* node) { |
+ ASSERT(access() != CodeGenState::UNDEFINED); |
Comment cmnt(masm_, "[ Slot"); |
if (node->type() == Slot::LOOKUP) { |
@@ -3126,161 +3289,54 @@ |
__ mov(r0, Operand(node->var()->name())); |
__ push(r0); |
- switch (access()) { |
- case CodeGenState::UNDEFINED: |
- UNREACHABLE(); |
- break; |
- |
- case CodeGenState::LOAD: |
- __ CallRuntime(Runtime::kLoadContextSlot, 2); |
- __ push(r0); |
- break; |
- |
- case CodeGenState::LOAD_TYPEOF_EXPR: |
- __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); |
- __ push(r0); |
- 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(r0); |
- // 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(r0); |
- break; |
+ if (access() == CodeGenState::LOAD) { |
+ __ CallRuntime(Runtime::kLoadContextSlot, 2); |
+ } else { |
+ // CodeGenState::LOAD_TYPEOF_EXPR. |
iposva
2008/09/10 18:01:44
Please assert that the CodeGenState is LOAD_TYPEOF
Kevin Millikin (Chromium)
2008/09/11 07:15:55
Done. Earlier assert already ruled out UNDEFINED,
|
+ __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); |
} |
+ __ push(r0); |
} 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: |
- // Special handling for locals allocated in registers. |
- __ ldr(r0, SlotOperand(node, r2)); |
- __ push(r0); |
- 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_, "[ Unhole const"); |
- __ pop(r0); |
- __ cmp(r0, Operand(Factory::the_hole_value())); |
- __ mov(r0, Operand(Factory::undefined_value()), LeaveCC, eq); |
- __ push(r0); |
- } |
- 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; |
- __ ldr(r2, SlotOperand(node, r2)); |
- __ cmp(r2, Operand(Factory::the_hole_value())); |
- __ b(ne, &L); |
- // We must execute the store. |
- // r2 may be loaded with context; used below in RecordWrite. |
- __ ldr(r0, MemOperand(sp, 0)); |
- __ str(r0, SlotOperand(node, r2)); |
- if (node->type() == Slot::CONTEXT) { |
- // Skip write barrier if the written value is a smi. |
- Label exit; |
- __ tst(r0, Operand(kSmiTagMask)); |
- __ b(eq, &exit); |
- // r2 is loaded with context when calling SlotOperand above. |
- int offset = FixedArray::kHeaderSize + node->index() * kPointerSize; |
- __ mov(r3, Operand(offset)); |
- __ RecordWrite(r2, r3, r1); |
- __ bind(&exit); |
- } |
- __ bind(&L); |
- } |
- break; |
- } |
- |
- case CodeGenState::STORE: { |
- // Storing a variable must keep the (new) value on the stack. This |
- // is necessary for compiling assignment expressions. |
- // Special handling for locals allocated in registers. |
- // |
- // 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. |
- // r2 may be loaded with context; used below in RecordWrite. |
- __ pop(r0); |
- __ str(r0, SlotOperand(node, r2)); |
- __ push(r0); |
- if (node->type() == Slot::CONTEXT) { |
- // Skip write barrier if the written value is a smi. |
- Label exit; |
- __ tst(r0, Operand(kSmiTagMask)); |
- __ b(eq, &exit); |
- // r2 is loaded with context when calling SlotOperand above. |
- int offset = FixedArray::kHeaderSize + node->index() * kPointerSize; |
- __ mov(r3, Operand(offset)); |
- __ RecordWrite(r2, r3, r1); |
- __ bind(&exit); |
- } |
- break; |
- } |
+ // Special handling for locals allocated in registers. |
+ __ ldr(r0, SlotOperand(node, r2)); |
+ __ push(r0); |
+ 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_, "[ Unhole const"); |
+ __ pop(r0); |
+ __ cmp(r0, Operand(Factory::the_hole_value())); |
+ __ mov(r0, Operand(Factory::undefined_value()), LeaveCC, eq); |
+ __ push(r0); |
} |
} |
} |
-void ArmCodeGenerator::VisitVariableProxy(VariableProxy* proxy_node) { |
+void ArmCodeGenerator::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); |
} |
} |
@@ -3541,13 +3597,11 @@ |
void ArmCodeGenerator::VisitProperty(Property* node) { |
Comment cmnt(masm_, "[ Property"); |
+ |
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); |