Index: src/arm/full-codegen-arm.cc |
diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc |
index 30e8ea673b9ce2a3c9d28019ec1b772733ce578f..93ba94c060bd2775f2c796283434710d680ffac9 100644 |
--- a/src/arm/full-codegen-arm.cc |
+++ b/src/arm/full-codegen-arm.cc |
@@ -269,7 +269,10 @@ void FullCodeGenerator::Generate(CompilationInfo* info) { |
// constant. |
if (scope()->is_function_scope() && scope()->function() != NULL) { |
int ignored = 0; |
- EmitDeclaration(scope()->function(), CONST, NULL, &ignored); |
+ VariableProxy* proxy = scope()->function(); |
+ ASSERT(proxy->var()->mode() == CONST || |
+ proxy->var()->mode() == CONST_HARMONY); |
+ EmitDeclaration(proxy, proxy->var()->mode(), NULL, &ignored); |
} |
VisitDeclarations(scope()->declarations()); |
} |
@@ -718,6 +721,8 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, |
// need to "declare" it at runtime to make sure it actually exists in the |
// local context. |
Variable* variable = proxy->var(); |
+ bool binding_needs_init = |
+ mode == CONST || mode == CONST_HARMONY || mode == LET; |
switch (variable->location()) { |
case Variable::UNALLOCATED: |
++(*global_count); |
@@ -729,7 +734,7 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, |
Comment cmnt(masm_, "[ Declaration"); |
VisitForAccumulatorValue(function); |
__ str(result_register(), StackOperand(variable)); |
- } else if (mode == CONST || mode == LET) { |
+ } else if (binding_needs_init) { |
Comment cmnt(masm_, "[ Declaration"); |
__ LoadRoot(ip, Heap::kTheHoleValueRootIndex); |
__ str(ip, StackOperand(variable)); |
@@ -763,7 +768,7 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, |
EMIT_REMEMBERED_SET, |
OMIT_SMI_CHECK); |
PrepareForBailoutForId(proxy->id(), NO_REGISTERS); |
- } else if (mode == CONST || mode == LET) { |
+ } else if (binding_needs_init) { |
Comment cmnt(masm_, "[ Declaration"); |
__ LoadRoot(ip, Heap::kTheHoleValueRootIndex); |
__ str(ip, ContextOperand(cp, variable->index())); |
@@ -775,9 +780,13 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, |
case Variable::LOOKUP: { |
Comment cmnt(masm_, "[ Declaration"); |
__ mov(r2, Operand(variable->name())); |
- // Declaration nodes are always introduced in one of three modes. |
- ASSERT(mode == VAR || mode == CONST || mode == LET); |
- PropertyAttributes attr = (mode == CONST) ? READ_ONLY : NONE; |
+ // Declaration nodes are always introduced in one of four modes. |
+ ASSERT(mode == VAR || |
+ mode == CONST || |
+ mode == CONST_HARMONY || |
+ mode == LET); |
+ PropertyAttributes attr = (mode == CONST || mode == CONST_HARMONY) |
+ ? READ_ONLY : NONE; |
__ mov(r1, Operand(Smi::FromInt(attr))); |
// Push initial value, if any. |
// Note: For variables we must not push an initial value (such as |
@@ -787,7 +796,7 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, |
__ Push(cp, r2, r1); |
// Push initial value for function declaration. |
VisitForStackValue(function); |
- } else if (mode == CONST || mode == LET) { |
+ } else if (binding_needs_init) { |
__ LoadRoot(r0, Heap::kTheHoleValueRootIndex); |
__ Push(cp, r2, r1, r0); |
} else { |
@@ -1224,11 +1233,12 @@ void FullCodeGenerator::EmitDynamicLookupFastCase(Variable* var, |
Variable* local = var->local_if_not_shadowed(); |
__ ldr(r0, ContextSlotOperandCheckExtensions(local, slow)); |
if (local->mode() == CONST || |
+ local->mode() == CONST_HARMONY || |
local->mode() == LET) { |
__ CompareRoot(r0, Heap::kTheHoleValueRootIndex); |
if (local->mode() == CONST) { |
__ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq); |
- } else { // LET |
+ } else { // LET || CONST_HARMONY |
__ b(ne, done); |
__ mov(r0, Operand(var->name())); |
__ push(r0); |
@@ -1266,13 +1276,15 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) { |
Comment cmnt(masm_, var->IsContextSlot() |
? "Context variable" |
: "Stack variable"); |
- if (var->mode() != LET && var->mode() != CONST) { |
+ if (!var->binding_needs_init()) { |
context()->Plug(var); |
} else { |
// Let and const need a read barrier. |
GetVar(r0, var); |
__ CompareRoot(r0, Heap::kTheHoleValueRootIndex); |
- if (var->mode() == LET) { |
+ if (var->mode() == LET || var->mode() == CONST_HARMONY) { |
+ // Throw a reference error when using an uninitialized let/const |
+ // binding in harmony mode. |
Label done; |
__ b(ne, &done); |
__ mov(r0, Operand(var->name())); |
@@ -1280,6 +1292,8 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) { |
__ CallRuntime(Runtime::kThrowReferenceError, 1); |
__ bind(&done); |
} else { |
+ // Uninitalized const bindings outside of harmony mode are unholed. |
+ ASSERT(var->mode() == CONST); |
__ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq); |
} |
context()->Plug(r0); |
@@ -1947,8 +1961,9 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, |
} |
} |
- } else if (var->mode() != CONST) { |
- // Assignment to var or initializing assignment to let. |
+ } else if (!var->is_const_mode() || op == Token::INIT_CONST_HARMONY) { |
+ // Assignment to var or initializing assignment to let/const |
+ // in harmony mode. |
if (var->IsStackAllocated() || var->IsContextSlot()) { |
MemOperand location = VarOperand(var, r1); |
if (FLAG_debug_code && op == Token::INIT_LET) { |