Index: src/codegen-arm.cc |
=================================================================== |
--- src/codegen-arm.cc (revision 448) |
+++ src/codegen-arm.cc (working copy) |
@@ -52,19 +52,23 @@ |
class Reference BASE_EMBEDDED { |
public: |
- enum Type { ILLEGAL = -1, EMPTY = 0, NAMED = 1, KEYED = 2 }; |
+ // The values of the types is important, see size(). |
+ enum Type { ILLEGAL = -1, SLOT = 0, NAMED = 1, KEYED = 2 }; |
Reference(ArmCodeGenerator* cgen, Expression* expression); |
~Reference(); |
- Expression* expression() const { return expression_; } |
- Type type() const { return type_; } |
+ Expression* expression() const { return expression_; } |
+ Type type() const { return type_; } |
void set_type(Type value) { |
ASSERT(type_ == ILLEGAL); |
type_ = value; |
} |
- int size() const { return type_; } |
+ // The size of the reference or -1 if the reference is illegal. |
+ int size() const { return type_; } |
- bool is_illegal() const { return type_ == ILLEGAL; } |
+ bool is_illegal() const { return type_ == ILLEGAL; } |
+ bool is_slot() const { return type_ == SLOT; } |
+ bool is_property() const { return type_ == NAMED || type_ == KEYED; } |
private: |
ArmCodeGenerator* cgen_; |
@@ -802,33 +806,37 @@ |
Variable* var = e->AsVariableProxy()->AsVariable(); |
if (property != NULL) { |
+ // The expression is either a property or a variable proxy that rewrites |
+ // to a property. |
Load(property->obj()); |
- // Used a named reference if the key is a literal symbol. |
- // We don't use a named reference if they key is a string that can be |
- // legally parsed as an integer. This is because, otherwise we don't |
- // get into the slow case code that handles [] on String objects. |
+ // We use a named reference if the key is a literal symbol, unless it is |
+ // a string that can be legally parsed as an integer. This is because |
+ // otherwise we will not get into the slow case code that handles [] on |
+ // String objects. |
Literal* literal = property->key()->AsLiteral(); |
uint32_t dummy; |
- if (literal != NULL && literal->handle()->IsSymbol() && |
- !String::cast(*(literal->handle()))->AsArrayIndex(&dummy)) { |
+ if (literal != NULL && |
+ literal->handle()->IsSymbol() && |
+ !String::cast(*(literal->handle()))->AsArrayIndex(&dummy)) { |
ref->set_type(Reference::NAMED); |
} else { |
Load(property->key()); |
ref->set_type(Reference::KEYED); |
} |
} else if (var != NULL) { |
+ // 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()) { |
- // global variable |
LoadGlobal(); |
ref->set_type(Reference::NAMED); |
} else { |
- // local variable |
- ref->set_type(Reference::EMPTY); |
+ ASSERT(var->slot() != NULL); |
+ ref->set_type(Reference::SLOT); |
} |
} else { |
+ // Anything else is a runtime error. |
Load(e); |
__ CallRuntime(Runtime::kThrowReferenceError, 1); |
- __ push(r0); |
} |
} |
@@ -971,14 +979,13 @@ |
void ArmCodeGenerator::GetReferenceProperty(Expression* key) { |
ASSERT(!ref()->is_illegal()); |
- Reference::Type type = ref()->type(); |
// 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) { |
+ if (ref()->type() == Reference::NAMED) { |
// Compute the name of the property. |
Literal* literal = key->AsLiteral(); |
Handle<String> name(String::cast(*literal->handle())); |
@@ -997,7 +1004,7 @@ |
} else { |
// Access keyed property. |
- ASSERT(type == Reference::KEYED); |
+ ASSERT(ref()->type() == Reference::KEYED); |
// TODO(1224671): Implement inline caching for keyed loads as on ia32. |
GetPropertyStub stub; |
@@ -1460,9 +1467,13 @@ |
if (val != NULL) { |
// Set initial value. |
Reference target(this, node->proxy()); |
+ ASSERT(target.is_slot()); |
Load(val); |
SetValue(&target); |
- // Get rid of the assigned value (declarations are statements). |
+ // Get rid of the assigned value (declarations are statements). It's |
+ // safe to pop the value lying on top of the reference before unloading |
+ // the reference itself (which preserves the top of stack) because we |
+ // know it is a zero-sized reference. |
__ pop(); |
} |
} |
@@ -1944,16 +1955,27 @@ |
{ Reference each(this, node->each()); |
if (!each.is_illegal()) { |
if (each.size() > 0) { |
+ // Reference's size is positive. |
__ ldr(r0, MemOperand(sp, kPointerSize * each.size())); |
__ push(r0); |
} |
+ // If the reference was to a slot we rely on the convenient property |
+ // that it doesn't matter whether a value (eg, r3 pushed above) is |
+ // right on top of or right underneath a zero-sized reference. |
SetValue(&each); |
if (each.size() > 0) { |
- __ pop(r0); // discard the value |
+ // It's safe to pop the value lying on top of the reference before |
+ // unloading the reference itself (which preserves the top of stack, |
+ // ie, now the topmost value of the non-zero sized reference), since |
+ // we will discard the top of stack after unloading the reference |
+ // anyway. |
+ __ pop(r0); |
} |
} |
} |
- __ pop(); // pop the i'th entry pushed above |
+ // Discard the i'th entry pushed above or else the remainder of the |
+ // reference, whichever is currently on top of the stack. |
+ __ pop(); |
CheckStack(); // TODO(1222600): ignore if body contains calls. |
__ jmp(&loop); |
@@ -1981,11 +2003,11 @@ |
// Store the caught exception in the catch variable. |
__ push(r0); |
{ Reference ref(this, node->catch_var()); |
- // Load the exception to the top of the stack. |
- __ ldr(r0, MemOperand(sp, ref.size() * kPointerSize)); |
- __ push(r0); |
+ ASSERT(ref.is_slot()); |
+ // Here we make use of the convenient property that it doesn't matter |
+ // whether a value is immediately on top of or underneath a zero-sized |
+ // reference. |
SetValue(&ref); |
- __ pop(r0); |
} |
// Remove the exception from the stack. |