| 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);
|
| }
|
|
|