Commit 9ab8bfba authored by rossberg's avatar rossberg Committed by Commit bot

[es6] Make sure temporaries are not allocated in block scope

While at it, remove the notion of INTERNAL variables.

@caitp: Took some parts from your CL, since I was blocked on the temp scope bug.

R=mstarzinger@chromium.org
BUG=512574
LOG=N

Review URL: https://codereview.chromium.org/1250513004

Cr-Commit-Position: refs/heads/master@{#29812}
parent bc8041dc
...@@ -140,7 +140,6 @@ static void GetAttributesAndBindingFlags(VariableMode mode, ...@@ -140,7 +140,6 @@ static void GetAttributesAndBindingFlags(VariableMode mode,
PropertyAttributes* attributes, PropertyAttributes* attributes,
BindingFlags* binding_flags) { BindingFlags* binding_flags) {
switch (mode) { switch (mode) {
case INTERNAL: // Fall through.
case VAR: case VAR:
*attributes = NONE; *attributes = NONE;
*binding_flags = MUTABLE_IS_INITIALIZED; *binding_flags = MUTABLE_IS_INITIALIZED;
......
...@@ -810,9 +810,6 @@ enum VariableMode { ...@@ -810,9 +810,6 @@ enum VariableMode {
IMPORT, // declared via 'import' declarations (last lexical) IMPORT, // declared via 'import' declarations (last lexical)
// Variables introduced by the compiler: // Variables introduced by the compiler:
INTERNAL, // like VAR, but not user-visible (may or may not
// be in a context)
TEMPORARY, // temporary variables (not user-visible), stack-allocated TEMPORARY, // temporary variables (not user-visible), stack-allocated
// unless the scope as a whole has forced context allocation // unless the scope as a whole has forced context allocation
......
...@@ -2827,7 +2827,7 @@ Statement* Parser::ParseReturnStatement(bool* ok) { ...@@ -2827,7 +2827,7 @@ Statement* Parser::ParseReturnStatement(bool* ok) {
// //
// return (temp = expr) === undefined ? this : // return (temp = expr) === undefined ? this :
// %_IsSpecObject(temp) ? temp : throw new TypeError(...); // %_IsSpecObject(temp) ? temp : throw new TypeError(...);
Variable* temp = scope_->DeclarationScope()->NewTemporary( Variable* temp = scope_->NewTemporary(
ast_value_factory()->empty_string()); ast_value_factory()->empty_string());
Assignment* assign = factory()->NewAssignment( Assignment* assign = factory()->NewAssignment(
Token::ASSIGN, factory()->NewVariableProxy(temp), return_value, pos); Token::ASSIGN, factory()->NewVariableProxy(temp), return_value, pos);
...@@ -3181,9 +3181,9 @@ void Parser::InitializeForEachStatement(ForEachStatement* stmt, ...@@ -3181,9 +3181,9 @@ void Parser::InitializeForEachStatement(ForEachStatement* stmt,
ForOfStatement* for_of = stmt->AsForOfStatement(); ForOfStatement* for_of = stmt->AsForOfStatement();
if (for_of != NULL) { if (for_of != NULL) {
Variable* iterator = scope_->DeclarationScope()->NewTemporary( Variable* iterator = scope_->NewTemporary(
ast_value_factory()->dot_iterator_string()); ast_value_factory()->dot_iterator_string());
Variable* result = scope_->DeclarationScope()->NewTemporary( Variable* result = scope_->NewTemporary(
ast_value_factory()->dot_result_string()); ast_value_factory()->dot_result_string());
Expression* assign_iterator; Expression* assign_iterator;
...@@ -3299,7 +3299,7 @@ Statement* Parser::DesugarLexicalBindingsInForStatement( ...@@ -3299,7 +3299,7 @@ Statement* Parser::DesugarLexicalBindingsInForStatement(
// make statement: temp_x = x. // make statement: temp_x = x.
for (int i = 0; i < names->length(); i++) { for (int i = 0; i < names->length(); i++) {
VariableProxy* proxy = NewUnresolved(names->at(i), LET); VariableProxy* proxy = NewUnresolved(names->at(i), LET);
Variable* temp = scope_->DeclarationScope()->NewTemporary(temp_name); Variable* temp = scope_->NewTemporary(temp_name);
VariableProxy* temp_proxy = factory()->NewVariableProxy(temp); VariableProxy* temp_proxy = factory()->NewVariableProxy(temp);
Assignment* assignment = factory()->NewAssignment( Assignment* assignment = factory()->NewAssignment(
Token::ASSIGN, temp_proxy, proxy, RelocInfo::kNoPosition); Token::ASSIGN, temp_proxy, proxy, RelocInfo::kNoPosition);
...@@ -3312,7 +3312,7 @@ Statement* Parser::DesugarLexicalBindingsInForStatement( ...@@ -3312,7 +3312,7 @@ Statement* Parser::DesugarLexicalBindingsInForStatement(
Variable* first = NULL; Variable* first = NULL;
// Make statement: first = 1. // Make statement: first = 1.
if (next) { if (next) {
first = scope_->DeclarationScope()->NewTemporary(temp_name); first = scope_->NewTemporary(temp_name);
VariableProxy* first_proxy = factory()->NewVariableProxy(first); VariableProxy* first_proxy = factory()->NewVariableProxy(first);
Expression* const1 = factory()->NewSmiLiteral(1, RelocInfo::kNoPosition); Expression* const1 = factory()->NewSmiLiteral(1, RelocInfo::kNoPosition);
Assignment* assignment = factory()->NewAssignment( Assignment* assignment = factory()->NewAssignment(
...@@ -3392,7 +3392,7 @@ Statement* Parser::DesugarLexicalBindingsInForStatement( ...@@ -3392,7 +3392,7 @@ Statement* Parser::DesugarLexicalBindingsInForStatement(
ignore_completion_block->AddStatement(clear_first_or_next, zone()); ignore_completion_block->AddStatement(clear_first_or_next, zone());
} }
Variable* flag = scope_->DeclarationScope()->NewTemporary(temp_name); Variable* flag = scope_->NewTemporary(temp_name);
// Make statement: flag = 1. // Make statement: flag = 1.
{ {
VariableProxy* flag_proxy = factory()->NewVariableProxy(flag); VariableProxy* flag_proxy = factory()->NewVariableProxy(flag);
...@@ -3578,7 +3578,7 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels, ...@@ -3578,7 +3578,7 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
// let x; // for TDZ // let x; // for TDZ
// } // }
Variable* temp = scope_->DeclarationScope()->NewTemporary( Variable* temp = scope_->NewTemporary(
ast_value_factory()->dot_for_string()); ast_value_factory()->dot_for_string());
ForEachStatement* loop = ForEachStatement* loop =
factory()->NewForEachStatement(mode, labels, stmt_pos); factory()->NewForEachStatement(mode, labels, stmt_pos);
...@@ -4007,7 +4007,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral( ...@@ -4007,7 +4007,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
// Calling a generator returns a generator object. That object is stored // Calling a generator returns a generator object. That object is stored
// in a temporary variable, a definition that is used by "yield" // in a temporary variable, a definition that is used by "yield"
// expressions. This also marks the FunctionState as a generator. // expressions. This also marks the FunctionState as a generator.
Variable* temp = scope_->DeclarationScope()->NewTemporary( Variable* temp = scope_->NewTemporary(
ast_value_factory()->dot_generator_object_string()); ast_value_factory()->dot_generator_object_string());
function_state.set_generator_object_variable(temp); function_state.set_generator_object_variable(temp);
} }
......
...@@ -214,8 +214,8 @@ void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) { ...@@ -214,8 +214,8 @@ void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) {
Variable* Parser::PatternRewriter::CreateTempVar(Expression* value) { Variable* Parser::PatternRewriter::CreateTempVar(Expression* value) {
auto temp_scope = descriptor_->parser->scope_->DeclarationScope(); auto temp = descriptor_->parser->scope_->NewTemporary(
auto temp = temp_scope->NewTemporary(ast_value_factory()->empty_string()); ast_value_factory()->empty_string());
if (value != nullptr) { if (value != nullptr) {
auto assignment = factory()->NewAssignment( auto assignment = factory()->NewAssignment(
Token::ASSIGN, factory()->NewVariableProxy(temp), value, Token::ASSIGN, factory()->NewVariableProxy(temp), value,
......
...@@ -830,7 +830,6 @@ RUNTIME_FUNCTION(Runtime_DeclareModules) { ...@@ -830,7 +830,6 @@ RUNTIME_FUNCTION(Runtime_DeclareModules) {
USE(result); USE(result);
break; break;
} }
case INTERNAL:
case TEMPORARY: case TEMPORARY:
case DYNAMIC: case DYNAMIC:
case DYNAMIC_GLOBAL: case DYNAMIC_GLOBAL:
......
...@@ -564,7 +564,7 @@ int ScopeInfo::ContextSlotIndex(Handle<ScopeInfo> scope_info, ...@@ -564,7 +564,7 @@ int ScopeInfo::ContextSlotIndex(Handle<ScopeInfo> scope_info,
} }
// Cache as not found. Mode, location, init flag and maybe assigned flag // Cache as not found. Mode, location, init flag and maybe assigned flag
// don't matter. // don't matter.
context_slot_cache->Update(scope_info, name, INTERNAL, context_slot_cache->Update(scope_info, name, TEMPORARY,
VariableLocation::CONTEXT, kNeedsInitialization, VariableLocation::CONTEXT, kNeedsInitialization,
kNotAssigned, -1); kNotAssigned, -1);
} }
......
...@@ -527,26 +527,15 @@ void Scope::RemoveUnresolved(VariableProxy* var) { ...@@ -527,26 +527,15 @@ void Scope::RemoveUnresolved(VariableProxy* var) {
} }
Variable* Scope::NewInternal(const AstRawString* name) {
DCHECK(!already_resolved());
Variable* var = new(zone()) Variable(this,
name,
INTERNAL,
Variable::NORMAL,
kCreatedInitialized);
internals_.Add(var, zone());
return var;
}
Variable* Scope::NewTemporary(const AstRawString* name) { Variable* Scope::NewTemporary(const AstRawString* name) {
DCHECK(!already_resolved()); DCHECK(!already_resolved());
Variable* var = new(zone()) Variable(this, Scope* scope = this->TemporaryScope();
Variable* var = new(zone()) Variable(scope,
name, name,
TEMPORARY, TEMPORARY,
Variable::NORMAL, Variable::NORMAL,
kCreatedInitialized); kCreatedInitialized);
temps_.Add(var, zone()); scope->temps_.Add(var, zone());
return var; return var;
} }
...@@ -772,6 +761,15 @@ Scope* Scope::DeclarationScope() { ...@@ -772,6 +761,15 @@ Scope* Scope::DeclarationScope() {
} }
Scope* Scope::TemporaryScope() {
Scope* scope = this;
while (!scope->is_declaration_scope() || scope->is_block_scope()) {
scope = scope->outer_scope();
}
return scope;
}
Scope* Scope::ReceiverScope() { Scope* Scope::ReceiverScope() {
Scope* scope = this; Scope* scope = this;
while (!scope->is_script_scope() && while (!scope->is_script_scope() &&
...@@ -1354,7 +1352,6 @@ bool Scope::MustAllocateInContext(Variable* var) { ...@@ -1354,7 +1352,6 @@ bool Scope::MustAllocateInContext(Variable* var) {
// always context-allocated. // always context-allocated.
if (has_forced_context_allocation()) return true; if (has_forced_context_allocation()) return true;
if (var->mode() == TEMPORARY) return false; if (var->mode() == TEMPORARY) return false;
if (var->mode() == INTERNAL) return true;
if (is_catch_scope() || is_module_scope()) return true; if (is_catch_scope() || is_module_scope()) return true;
if (is_script_scope() && IsLexicalVariableMode(var->mode())) return true; if (is_script_scope() && IsLexicalVariableMode(var->mode())) return true;
return var->has_forced_context_allocation() || return var->has_forced_context_allocation() ||
...@@ -1609,7 +1606,8 @@ void Scope::AllocateModules() { ...@@ -1609,7 +1606,8 @@ void Scope::AllocateModules() {
DCHECK(!scope->already_resolved()); DCHECK(!scope->already_resolved());
DCHECK(scope->module_descriptor_->IsFrozen()); DCHECK(scope->module_descriptor_->IsFrozen());
DCHECK_NULL(scope->module_var_); DCHECK_NULL(scope->module_var_);
scope->module_var_ = NewInternal(ast_value_factory_->dot_module_string()); scope->module_var_ =
NewTemporary(ast_value_factory_->dot_module_string());
++num_modules_; ++num_modules_;
} }
} }
......
...@@ -168,16 +168,11 @@ class Scope: public ZoneObject { ...@@ -168,16 +168,11 @@ class Scope: public ZoneObject {
// such a variable again if it was added; otherwise this is a no-op. // such a variable again if it was added; otherwise this is a no-op.
void RemoveUnresolved(VariableProxy* var); void RemoveUnresolved(VariableProxy* var);
// Creates a new internal variable in this scope. The name is only used // Creates a new temporary variable in this scope's TemporaryScope. The
// for printing and cannot be used to find the variable. In particular, // name is only used for printing and cannot be used to find the variable.
// the only way to get hold of the temporary is by keeping the Variable* // In particular, the only way to get hold of the temporary is by keeping the
// around. // Variable* around. The name should not clash with a legitimate variable
Variable* NewInternal(const AstRawString* name); // names.
// Creates a new temporary variable in this scope. The name is only used
// for printing and cannot be used to find the variable. In particular,
// the only way to get hold of the temporary is by keeping the Variable*
// around. The name should not clash with a legitimate variable names.
Variable* NewTemporary(const AstRawString* name); Variable* NewTemporary(const AstRawString* name);
// Adds the specific declaration node to the list of declarations in // Adds the specific declaration node to the list of declarations in
...@@ -487,6 +482,11 @@ class Scope: public ZoneObject { ...@@ -487,6 +482,11 @@ class Scope: public ZoneObject {
// the scope where var declarations will be hoisted to in the implementation. // the scope where var declarations will be hoisted to in the implementation.
Scope* DeclarationScope(); Scope* DeclarationScope();
// Find the first non-block declaration scope. This should be either a script,
// function, or eval scope. Same as DeclarationScope(), but skips
// declaration "block" scopes. Used for declaring temporaries.
Scope* TemporaryScope();
// Find the first (non-arrow) function or script scope. This is where // Find the first (non-arrow) function or script scope. This is where
// 'this' is bound, and what determines the function kind. // 'this' is bound, and what determines the function kind.
Scope* ReceiverScope(); Scope* ReceiverScope();
......
...@@ -24,7 +24,6 @@ const char* Variable::Mode2String(VariableMode mode) { ...@@ -24,7 +24,6 @@ const char* Variable::Mode2String(VariableMode mode) {
case DYNAMIC: return "DYNAMIC"; case DYNAMIC: return "DYNAMIC";
case DYNAMIC_GLOBAL: return "DYNAMIC_GLOBAL"; case DYNAMIC_GLOBAL: return "DYNAMIC_GLOBAL";
case DYNAMIC_LOCAL: return "DYNAMIC_LOCAL"; case DYNAMIC_LOCAL: return "DYNAMIC_LOCAL";
case INTERNAL: return "INTERNAL";
case TEMPORARY: return "TEMPORARY"; case TEMPORARY: return "TEMPORARY";
} }
UNREACHABLE(); UNREACHABLE();
......
...@@ -5527,7 +5527,7 @@ TEST(ModuleParsingInternals) { ...@@ -5527,7 +5527,7 @@ TEST(ModuleParsingInternals) {
CHECK_EQ(1, outer_scope->num_modules()); CHECK_EQ(1, outer_scope->num_modules());
CHECK(module_scope->is_module_scope()); CHECK(module_scope->is_module_scope());
CHECK_NOT_NULL(module_scope->module_var()); CHECK_NOT_NULL(module_scope->module_var());
CHECK_EQ(i::INTERNAL, module_scope->module_var()->mode()); CHECK_EQ(i::TEMPORARY, module_scope->module_var()->mode());
i::ModuleDescriptor* descriptor = module_scope->module(); i::ModuleDescriptor* descriptor = module_scope->module();
CHECK_NOT_NULL(descriptor); CHECK_NOT_NULL(descriptor);
CHECK_EQ(1, descriptor->Length()); CHECK_EQ(1, descriptor->Length());
......
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --harmony-destructuring
function f({}) {
for (var v in []);
};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment