Index: src/crankshaft/hydrogen.cc |
diff --git a/src/crankshaft/hydrogen.cc b/src/crankshaft/hydrogen.cc |
index bcc50c5a844be54e9bc11afe985a78056574d984..d039b0682073a1cfd86d507a3e8f76ebcc367373 100644 |
--- a/src/crankshaft/hydrogen.cc |
+++ b/src/crankshaft/hydrogen.cc |
@@ -4243,7 +4243,8 @@ void HOptimizedGraphBuilder::VisitBlock(Block* stmt) { |
if (declaration_scope->is_script_scope() || |
declaration_scope->is_eval_scope()) { |
function = new (zone()) |
- HLoadContextSlot(outer_context, Context::CLOSURE_INDEX); |
+ HLoadContextSlot(outer_context, Context::CLOSURE_INDEX, |
+ HLoadContextSlot::kNoCheck); |
} else { |
function = New<HThisFunction>(); |
} |
@@ -5235,9 +5236,12 @@ void HOptimizedGraphBuilder::VisitVariableProxy(VariableProxy* expr) { |
DCHECK(current_block() != NULL); |
DCHECK(current_block()->HasPredecessor()); |
Variable* variable = expr->var(); |
- DCHECK(!variable->binding_needs_init()); |
switch (variable->location()) { |
case VariableLocation::UNALLOCATED: { |
+ if (IsLexicalVariableMode(variable->mode())) { |
+ // TODO(rossberg): should this be an DCHECK? |
+ return Bailout(kReferenceToGlobalLexicalVariable); |
+ } |
// Handle known global constants like 'undefined' specially to avoid a |
// load from a global cell for them. |
Handle<Object> constant_value = |
@@ -5299,13 +5303,28 @@ void HOptimizedGraphBuilder::VisitVariableProxy(VariableProxy* expr) { |
case VariableLocation::PARAMETER: |
case VariableLocation::LOCAL: { |
HValue* value = LookupAndMakeLive(variable); |
+ if (value == graph()->GetConstantHole()) { |
+ DCHECK(IsDeclaredVariableMode(variable->mode()) && |
+ variable->mode() != VAR); |
+ return Bailout(kReferenceToUninitializedVariable); |
+ } |
return ast_context()->ReturnValue(value); |
} |
case VariableLocation::CONTEXT: { |
HValue* context = BuildContextChainWalk(variable); |
+ HLoadContextSlot::Mode mode; |
+ switch (variable->mode()) { |
+ case LET: |
+ case CONST: |
+ mode = HLoadContextSlot::kCheckDeoptimize; |
+ break; |
+ default: |
+ mode = HLoadContextSlot::kNoCheck; |
+ break; |
+ } |
HLoadContextSlot* instr = |
- new (zone()) HLoadContextSlot(context, variable->index()); |
+ new(zone()) HLoadContextSlot(context, variable->index(), mode); |
return ast_context()->ReturnInstruction(instr, expr->id()); |
} |
@@ -6526,7 +6545,9 @@ void HOptimizedGraphBuilder::HandleCompoundAssignment(Assignment* expr) { |
if (proxy != NULL) { |
Variable* var = proxy->var(); |
- DCHECK(!var->binding_needs_init()); |
+ if (var->mode() == LET) { |
+ return Bailout(kUnsupportedLetCompoundAssignment); |
+ } |
CHECK_ALIVE(VisitForValue(operation)); |
@@ -6560,17 +6581,25 @@ void HOptimizedGraphBuilder::HandleCompoundAssignment(Assignment* expr) { |
} |
} |
- if (var->mode() == CONST) { |
- if (var->throw_on_const_assignment(function_language_mode())) { |
- return Bailout(kNonInitializerAssignmentToConst); |
- } else { |
- return ast_context()->ReturnValue(Pop()); |
- } |
+ HStoreContextSlot::Mode mode; |
+ |
+ switch (var->mode()) { |
+ case LET: |
+ mode = HStoreContextSlot::kCheckDeoptimize; |
+ break; |
+ case CONST: |
+ if (var->throw_on_const_assignment(function_language_mode())) { |
+ return Bailout(kNonInitializerAssignmentToConst); |
+ } else { |
+ return ast_context()->ReturnValue(Pop()); |
+ } |
+ default: |
+ mode = HStoreContextSlot::kNoCheck; |
} |
HValue* context = BuildContextChainWalk(var); |
- HStoreContextSlot* instr = |
- Add<HStoreContextSlot>(context, var->index(), Top()); |
+ HStoreContextSlot* instr = Add<HStoreContextSlot>( |
+ context, var->index(), mode, Top()); |
if (instr->HasObservableSideEffects()) { |
Add<HSimulate>(expr->AssignmentId(), REMOVABLE_SIMULATE); |
} |
@@ -6628,14 +6657,15 @@ void HOptimizedGraphBuilder::VisitAssignment(Assignment* expr) { |
HandlePropertyAssignment(expr); |
} else if (proxy != NULL) { |
Variable* var = proxy->var(); |
- DCHECK(!var->binding_needs_init()); |
- if (var->mode() == CONST && expr->op() != Token::INIT) { |
- if (var->throw_on_const_assignment(function_language_mode())) { |
- return Bailout(kNonInitializerAssignmentToConst); |
- } else { |
- CHECK_ALIVE(VisitForValue(expr->value())); |
- return ast_context()->ReturnValue(Pop()); |
+ if (var->mode() == CONST) { |
+ if (expr->op() != Token::INIT) { |
+ if (var->throw_on_const_assignment(function_language_mode())) { |
+ return Bailout(kNonInitializerAssignmentToConst); |
+ } else { |
+ CHECK_ALIVE(VisitForValue(expr->value())); |
+ return ast_context()->ReturnValue(Pop()); |
+ } |
} |
} |
@@ -6649,6 +6679,14 @@ void HOptimizedGraphBuilder::VisitAssignment(Assignment* expr) { |
case VariableLocation::PARAMETER: |
case VariableLocation::LOCAL: { |
+ // Perform an initialization check for let declared variables |
+ // or parameters. |
+ if (var->mode() == LET && expr->op() == Token::ASSIGN) { |
+ HValue* env_value = environment()->Lookup(var); |
+ if (env_value == graph()->GetConstantHole()) { |
+ return Bailout(kAssignmentToLetVariableBeforeInitialization); |
+ } |
+ } |
// We do not allow the arguments object to occur in a context where it |
// may escape, but assignments to stack-allocated locals are |
// permitted. |
@@ -6674,9 +6712,29 @@ void HOptimizedGraphBuilder::VisitAssignment(Assignment* expr) { |
} |
CHECK_ALIVE(VisitForValue(expr->value())); |
+ HStoreContextSlot::Mode mode; |
+ if (expr->op() == Token::ASSIGN) { |
+ switch (var->mode()) { |
+ case LET: |
+ mode = HStoreContextSlot::kCheckDeoptimize; |
+ break; |
+ case CONST: |
+ // If we reached this point, the only possibility |
+ // is a sloppy assignment to a function name. |
+ DCHECK(function_language_mode() == SLOPPY && |
+ !var->throw_on_const_assignment(SLOPPY)); |
+ return ast_context()->ReturnValue(Pop()); |
+ default: |
+ mode = HStoreContextSlot::kNoCheck; |
+ } |
+ } else { |
+ DCHECK_EQ(Token::INIT, expr->op()); |
+ mode = HStoreContextSlot::kNoCheck; |
+ } |
+ |
HValue* context = BuildContextChainWalk(var); |
- HStoreContextSlot* instr = |
- Add<HStoreContextSlot>(context, var->index(), Top()); |
+ HStoreContextSlot* instr = Add<HStoreContextSlot>( |
+ context, var->index(), mode, Top()); |
if (instr->HasObservableSideEffects()) { |
Add<HSimulate>(expr->AssignmentId(), REMOVABLE_SIMULATE); |
} |
@@ -10372,7 +10430,6 @@ void HOptimizedGraphBuilder::VisitCountOperation(CountOperation* expr) { |
if (proxy != NULL) { |
Variable* var = proxy->var(); |
- DCHECK(!var->binding_needs_init()); |
if (var->mode() == CONST) { |
return Bailout(kNonInitializerAssignmentToConst); |
} |
@@ -10397,8 +10454,10 @@ void HOptimizedGraphBuilder::VisitCountOperation(CountOperation* expr) { |
case VariableLocation::CONTEXT: { |
HValue* context = BuildContextChainWalk(var); |
- HStoreContextSlot* instr = |
- Add<HStoreContextSlot>(context, var->index(), after); |
+ HStoreContextSlot::Mode mode = IsLexicalVariableMode(var->mode()) |
+ ? HStoreContextSlot::kCheckDeoptimize : HStoreContextSlot::kNoCheck; |
+ HStoreContextSlot* instr = Add<HStoreContextSlot>(context, var->index(), |
+ mode, after); |
if (instr->HasObservableSideEffects()) { |
Add<HSimulate>(expr->AssignmentId(), REMOVABLE_SIMULATE); |
} |
@@ -11781,9 +11840,9 @@ void HOptimizedGraphBuilder::VisitVariableDeclaration( |
VariableDeclaration* declaration) { |
VariableProxy* proxy = declaration->proxy(); |
Variable* variable = proxy->var(); |
- DCHECK(!variable->binding_needs_init()); |
switch (variable->location()) { |
case VariableLocation::UNALLOCATED: { |
+ DCHECK(!variable->binding_needs_init()); |
globals_.Add(variable->name(), zone()); |
FeedbackVectorSlot slot = proxy->VariableFeedbackSlot(); |
DCHECK(!slot.IsInvalid()); |
@@ -11793,7 +11852,21 @@ void HOptimizedGraphBuilder::VisitVariableDeclaration( |
} |
case VariableLocation::PARAMETER: |
case VariableLocation::LOCAL: |
+ if (variable->binding_needs_init()) { |
+ HValue* value = graph()->GetConstantHole(); |
+ environment()->Bind(variable, value); |
+ } |
+ break; |
case VariableLocation::CONTEXT: |
+ if (variable->binding_needs_init()) { |
+ HValue* value = graph()->GetConstantHole(); |
+ HValue* context = environment()->context(); |
+ HStoreContextSlot* store = Add<HStoreContextSlot>( |
+ context, variable->index(), HStoreContextSlot::kNoCheck, value); |
+ if (store->HasObservableSideEffects()) { |
+ Add<HSimulate>(proxy->id(), REMOVABLE_SIMULATE); |
+ } |
+ } |
break; |
case VariableLocation::LOOKUP: |
return Bailout(kUnsupportedLookupSlotInDeclaration); |
@@ -11831,8 +11904,8 @@ void HOptimizedGraphBuilder::VisitFunctionDeclaration( |
CHECK_ALIVE(VisitForValue(declaration->fun())); |
HValue* value = Pop(); |
HValue* context = environment()->context(); |
- HStoreContextSlot* store = |
- Add<HStoreContextSlot>(context, variable->index(), value); |
+ HStoreContextSlot* store = Add<HStoreContextSlot>( |
+ context, variable->index(), HStoreContextSlot::kNoCheck, value); |
if (store->HasObservableSideEffects()) { |
Add<HSimulate>(proxy->id(), REMOVABLE_SIMULATE); |
} |