Index: src/x64/full-codegen-x64.cc |
diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc |
index eda2e55781fbb574ac547f1b904808f7c5c5e615..1c00a9bfc40cb0af8920a29c64693220ef3dc5c2 100644 |
--- a/src/x64/full-codegen-x64.cc |
+++ b/src/x64/full-codegen-x64.cc |
@@ -254,7 +254,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()); |
} |
@@ -684,6 +687,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); |
@@ -695,7 +700,7 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, |
Comment cmnt(masm_, "[ Declaration"); |
VisitForAccumulatorValue(function); |
__ movq(StackOperand(variable), result_register()); |
- } else if (mode == CONST || mode == LET) { |
+ } else if (binding_needs_init) { |
Comment cmnt(masm_, "[ Declaration"); |
__ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); |
__ movq(StackOperand(variable), kScratchRegister); |
@@ -728,7 +733,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(kScratchRegister, Heap::kTheHoleValueRootIndex); |
__ movq(ContextOperand(rsi, variable->index()), kScratchRegister); |
@@ -741,9 +746,13 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, |
Comment cmnt(masm_, "[ Declaration"); |
__ push(rsi); |
__ Push(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; |
__ Push(Smi::FromInt(attr)); |
// Push initial value, if any. |
// Note: For variables we must not push an initial value (such as |
@@ -751,7 +760,7 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, |
// must not destroy the current value. |
if (function != NULL) { |
VisitForStackValue(function); |
- } else if (mode == CONST || mode == LET) { |
+ } else if (binding_needs_init) { |
__ PushRoot(Heap::kTheHoleValueRootIndex); |
} else { |
__ Push(Smi::FromInt(0)); // Indicates no initial value. |
@@ -1182,12 +1191,14 @@ void FullCodeGenerator::EmitDynamicLookupFastCase(Variable* var, |
} else if (var->mode() == DYNAMIC_LOCAL) { |
Variable* local = var->local_if_not_shadowed(); |
__ movq(rax, ContextSlotOperandCheckExtensions(local, slow)); |
- if (local->mode() == CONST || local->mode() == LET) { |
+ if (local->mode() == CONST || |
+ local->mode() == CONST_HARMONY || |
+ local->mode() == LET) { |
__ CompareRoot(rax, Heap::kTheHoleValueRootIndex); |
__ j(not_equal, done); |
if (local->mode() == CONST) { |
__ LoadRoot(rax, Heap::kUndefinedValueRootIndex); |
- } else { // LET |
+ } else { // LET || CONST_HARMONY |
__ Push(var->name()); |
__ CallRuntime(Runtime::kThrowReferenceError, 1); |
} |
@@ -1221,7 +1232,7 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) { |
case Variable::LOCAL: |
case Variable::CONTEXT: { |
Comment cmnt(masm_, var->IsContextSlot() ? "Context slot" : "Stack slot"); |
- if (var->mode() != LET && var->mode() != CONST) { |
+ if (!var->binding_needs_init()) { |
context()->Plug(var); |
} else { |
// Let and const need a read barrier. |
@@ -1229,10 +1240,14 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) { |
GetVar(rax, var); |
__ CompareRoot(rax, Heap::kTheHoleValueRootIndex); |
__ j(not_equal, &done, Label::kNear); |
- 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. |
__ Push(var->name()); |
__ CallRuntime(Runtime::kThrowReferenceError, 1); |
- } else { // CONST |
+ } else { |
+ // Uninitalized const bindings outside of harmony mode are unholed. |
+ ASSERT(var->mode() == CONST); |
__ LoadRoot(rax, Heap::kUndefinedValueRootIndex); |
} |
__ bind(&done); |
@@ -1854,8 +1869,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, rcx); |
if (FLAG_debug_code && op == Token::INIT_LET) { |