Remove CONST_LEGACY VariableMode

The only remaining use of this VariableMode is for the names of sloppy
named function expressions. This patch instead uses CONST for such
bindings (just as we do in strict mode) and instead marks those
Variables specially. During code generation a new helper method,
Variable::throw_on_const_assignment(), is called to decide whether
to throw or silently ignore the assignment.

Review-Url: https://codereview.chromium.org/2233673003
Cr-Commit-Position: refs/heads/master@{#39052}
This commit is contained in:
adamk 2016-08-31 11:49:49 -07:00 committed by Commit bot
parent e1cb562224
commit 7516fe1eaa
22 changed files with 102 additions and 195 deletions

View File

@ -605,8 +605,10 @@ AsmType* AsmTyper::ValidateModule(FunctionLiteral* fun) {
if (estatement != nullptr) { if (estatement != nullptr) {
Assignment* assignment = estatement->expression()->AsAssignment(); Assignment* assignment = estatement->expression()->AsAssignment();
if (assignment != nullptr && assignment->target()->IsVariableProxy() && if (assignment != nullptr && assignment->target()->IsVariableProxy() &&
assignment->target()->AsVariableProxy()->var()->mode() == assignment->target()
CONST_LEGACY) { ->AsVariableProxy()
->var()
->is_sloppy_function_name()) {
use_asm_directive = iter.Next(); use_asm_directive = iter.Next();
} }
} }

View File

@ -833,7 +833,7 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
// Skip extra assignment inserted by the parser when in this form: // Skip extra assignment inserted by the parser when in this form:
// (function Module(a, b, c) {... }) // (function Module(a, b, c) {... })
if (expr->target()->IsVariableProxy() && if (expr->target()->IsVariableProxy() &&
expr->target()->AsVariableProxy()->var()->mode() == CONST_LEGACY) { expr->target()->AsVariableProxy()->var()->is_sloppy_function_name()) {
return; return;
} }
Property* prop = expr->value()->AsProperty(); Property* prop = expr->value()->AsProperty();

View File

@ -76,7 +76,6 @@ Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate, Zone* zone,
// Determine use and location of the function variable if it is present. // Determine use and location of the function variable if it is present.
VariableAllocationInfo function_name_info; VariableAllocationInfo function_name_info;
VariableMode function_variable_mode;
if (scope->is_function_scope() && if (scope->is_function_scope() &&
scope->AsDeclarationScope()->function_var() != nullptr) { scope->AsDeclarationScope()->function_var() != nullptr) {
Variable* var = scope->AsDeclarationScope()->function_var(); Variable* var = scope->AsDeclarationScope()->function_var();
@ -88,10 +87,8 @@ Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate, Zone* zone,
DCHECK(var->IsStackLocal()); DCHECK(var->IsStackLocal());
function_name_info = STACK; function_name_info = STACK;
} }
function_variable_mode = var->mode();
} else { } else {
function_name_info = NONE; function_name_info = NONE;
function_variable_mode = VAR;
} }
const bool has_function_name = function_name_info != NONE; const bool has_function_name = function_name_info != NONE;
@ -127,7 +124,6 @@ Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate, Zone* zone,
ReceiverVariableField::encode(receiver_info) | ReceiverVariableField::encode(receiver_info) |
HasNewTargetField::encode(has_new_target) | HasNewTargetField::encode(has_new_target) |
FunctionVariableField::encode(function_name_info) | FunctionVariableField::encode(function_name_info) |
FunctionVariableMode::encode(function_variable_mode) |
AsmModuleField::encode(asm_module) | AsmModuleField::encode(asm_module) |
AsmFunctionField::encode(asm_function) | AsmFunctionField::encode(asm_function) |
HasSimpleParametersField::encode(has_simple_parameters) | HasSimpleParametersField::encode(has_simple_parameters) |
@ -254,7 +250,6 @@ Handle<ScopeInfo> ScopeInfo::CreateGlobalThisBinding(Isolate* isolate) {
const bool has_simple_parameters = true; const bool has_simple_parameters = true;
const VariableAllocationInfo receiver_info = CONTEXT; const VariableAllocationInfo receiver_info = CONTEXT;
const VariableAllocationInfo function_name_info = NONE; const VariableAllocationInfo function_name_info = NONE;
const VariableMode function_variable_mode = VAR;
const bool has_function_name = false; const bool has_function_name = false;
const bool has_receiver = true; const bool has_receiver = true;
const int parameter_count = 0; const int parameter_count = 0;
@ -272,7 +267,6 @@ Handle<ScopeInfo> ScopeInfo::CreateGlobalThisBinding(Isolate* isolate) {
DeclarationScopeField::encode(true) | DeclarationScopeField::encode(true) |
ReceiverVariableField::encode(receiver_info) | ReceiverVariableField::encode(receiver_info) |
FunctionVariableField::encode(function_name_info) | FunctionVariableField::encode(function_name_info) |
FunctionVariableMode::encode(function_variable_mode) |
AsmModuleField::encode(false) | AsmFunctionField::encode(false) | AsmModuleField::encode(false) | AsmFunctionField::encode(false) |
HasSimpleParametersField::encode(has_simple_parameters) | HasSimpleParametersField::encode(has_simple_parameters) |
FunctionKindField::encode(FunctionKind::kNormalFunction); FunctionKindField::encode(FunctionKind::kNormalFunction);
@ -625,14 +619,11 @@ int ScopeInfo::ReceiverContextSlotIndex() {
return -1; return -1;
} }
int ScopeInfo::FunctionContextSlotIndex(String* name) {
int ScopeInfo::FunctionContextSlotIndex(String* name, VariableMode* mode) {
DCHECK(name->IsInternalizedString()); DCHECK(name->IsInternalizedString());
DCHECK_NOT_NULL(mode);
if (length() > 0) { if (length() > 0) {
if (FunctionVariableField::decode(Flags()) == CONTEXT && if (FunctionVariableField::decode(Flags()) == CONTEXT &&
FunctionName() == name) { FunctionName() == name) {
*mode = FunctionVariableMode::decode(Flags());
return Smi::cast(get(FunctionNameEntryIndex() + 1))->value(); return Smi::cast(get(FunctionNameEntryIndex() + 1))->value();
} }
} }

View File

@ -415,11 +415,9 @@ void Scope::DeserializeScopeInfo(Isolate* isolate,
if (scope_info_->HasFunctionName()) { if (scope_info_->HasFunctionName()) {
Handle<String> name_handle(scope_info_->FunctionName(), isolate); Handle<String> name_handle(scope_info_->FunctionName(), isolate);
const AstRawString* name = ast_value_factory->GetString(name_handle); const AstRawString* name = ast_value_factory->GetString(name_handle);
VariableMode mode; int index = scope_info_->FunctionContextSlotIndex(*name_handle);
int index = scope_info_->FunctionContextSlotIndex(*name_handle, &mode);
if (index >= 0) { if (index >= 0) {
Variable* result = AsDeclarationScope()->DeclareFunctionVar(name); Variable* result = AsDeclarationScope()->DeclareFunctionVar(name);
DCHECK_EQ(mode, result->mode());
result->AllocateTo(VariableLocation::CONTEXT, index); result->AllocateTo(VariableLocation::CONTEXT, index);
} }
} }
@ -518,9 +516,11 @@ void DeclarationScope::DeclareDefaultFunctionVariables(
Variable* DeclarationScope::DeclareFunctionVar(const AstRawString* name) { Variable* DeclarationScope::DeclareFunctionVar(const AstRawString* name) {
DCHECK(is_function_scope()); DCHECK(is_function_scope());
DCHECK_NULL(function_); DCHECK_NULL(function_);
VariableMode mode = is_strict(language_mode()) ? CONST : CONST_LEGACY; Variable::Kind kind = is_sloppy(language_mode())
function_ = new (zone()) ? Variable::SLOPPY_FUNCTION_NAME
Variable(this, name, mode, Variable::NORMAL, kCreatedInitialized); : Variable::NORMAL;
function_ =
new (zone()) Variable(this, name, CONST, kind, kCreatedInitialized);
return function_; return function_;
} }
@ -682,11 +682,9 @@ Variable* DeclarationScope::LookupFunctionVar(const AstRawString* name) {
return function_; return function_;
} else if (!scope_info_.is_null()) { } else if (!scope_info_.is_null()) {
// If we are backed by a scope info, try to lookup the variable there. // If we are backed by a scope info, try to lookup the variable there.
VariableMode mode; int index = scope_info_->FunctionContextSlotIndex(*(name->string()));
int index = scope_info_->FunctionContextSlotIndex(*(name->string()), &mode);
if (index < 0) return nullptr; if (index < 0) return nullptr;
Variable* var = DeclareFunctionVar(name); Variable* var = DeclareFunctionVar(name);
DCHECK_EQ(mode, var->mode());
var->AllocateTo(VariableLocation::CONTEXT, index); var->AllocateTo(VariableLocation::CONTEXT, index);
return var; return var;
} else { } else {
@ -748,7 +746,7 @@ Variable* Scope::DeclareVariable(
Declaration* declaration, VariableMode mode, InitializationFlag init, Declaration* declaration, VariableMode mode, InitializationFlag init,
bool allow_harmony_restrictive_generators, bool allow_harmony_restrictive_generators,
bool* sloppy_mode_block_scope_function_redefinition, bool* ok) { bool* sloppy_mode_block_scope_function_redefinition, bool* ok) {
DCHECK(IsDeclaredVariableMode(mode) && mode != CONST_LEGACY); DCHECK(IsDeclaredVariableMode(mode));
DCHECK(!already_resolved_); DCHECK(!already_resolved_);
if (mode == VAR && !is_declaration_scope()) { if (mode == VAR && !is_declaration_scope()) {

View File

@ -16,7 +16,6 @@ namespace internal {
const char* Variable::Mode2String(VariableMode mode) { const char* Variable::Mode2String(VariableMode mode) {
switch (mode) { switch (mode) {
case VAR: return "VAR"; case VAR: return "VAR";
case CONST_LEGACY: return "CONST_LEGACY";
case LET: return "LET"; case LET: return "LET";
case CONST: return "CONST"; case CONST: return "CONST";
case DYNAMIC: return "DYNAMIC"; case DYNAMIC: return "DYNAMIC";

View File

@ -22,7 +22,8 @@ class Variable final : public ZoneObject {
FUNCTION, FUNCTION,
THIS, THIS,
ARGUMENTS, ARGUMENTS,
kLastKind = ARGUMENTS SLOPPY_FUNCTION_NAME,
kLastKind = SLOPPY_FUNCTION_NAME
}; };
Variable(Scope* scope, const AstRawString* name, VariableMode mode, Kind kind, Variable(Scope* scope, const AstRawString* name, VariableMode mode, Kind kind,
@ -77,16 +78,21 @@ class Variable final : public ZoneObject {
bool IsStaticGlobalObjectProperty() const; bool IsStaticGlobalObjectProperty() const;
bool is_dynamic() const { return IsDynamicVariableMode(mode()); } bool is_dynamic() const { return IsDynamicVariableMode(mode()); }
bool is_const_mode() const { return IsImmutableVariableMode(mode()); }
bool binding_needs_init() const { bool binding_needs_init() const {
DCHECK(initialization_flag() != kNeedsInitialization || DCHECK(initialization_flag() != kNeedsInitialization ||
IsLexicalVariableMode(mode())); IsLexicalVariableMode(mode()));
return initialization_flag() == kNeedsInitialization; return initialization_flag() == kNeedsInitialization;
} }
bool throw_on_const_assignment(LanguageMode language_mode) const {
return kind() != SLOPPY_FUNCTION_NAME || is_strict(language_mode);
}
bool is_function() const { return kind() == FUNCTION; } bool is_function() const { return kind() == FUNCTION; }
bool is_this() const { return kind() == THIS; } bool is_this() const { return kind() == THIS; }
bool is_arguments() const { return kind() == ARGUMENTS; } bool is_arguments() const { return kind() == ARGUMENTS; }
bool is_sloppy_function_name() const {
return kind() == SLOPPY_FUNCTION_NAME;
}
Variable* local_if_not_shadowed() const { Variable* local_if_not_shadowed() const {
DCHECK(mode() == DYNAMIC_LOCAL && local_if_not_shadowed_ != NULL); DCHECK(mode() == DYNAMIC_LOCAL && local_if_not_shadowed_ != NULL);
@ -129,7 +135,7 @@ class Variable final : public ZoneObject {
uint16_t bit_field_; uint16_t bit_field_;
class VariableModeField : public BitField16<VariableMode, 0, 3> {}; class VariableModeField : public BitField16<VariableMode, 0, 3> {};
class KindField : public BitField16<Kind, VariableModeField::kNext, 2> {}; class KindField : public BitField16<Kind, VariableModeField::kNext, 3> {};
class LocationField class LocationField
: public BitField16<VariableLocation, KindField::kNext, 3> {}; : public BitField16<VariableLocation, KindField::kNext, 3> {};
class ForceContextAllocationField class ForceContextAllocationField

View File

@ -242,10 +242,6 @@ namespace internal {
V(kUnexpectedTypeForRegExpDataFixedArrayExpected, \ V(kUnexpectedTypeForRegExpDataFixedArrayExpected, \
"Unexpected type for RegExp data, FixedArray expected") \ "Unexpected type for RegExp data, FixedArray expected") \
V(kUnexpectedValue, "Unexpected value") \ V(kUnexpectedValue, "Unexpected value") \
V(kUnsupportedConstCompoundAssignment, \
"Unsupported const compound assignment") \
V(kUnsupportedCountOperationWithConst, \
"Unsupported count operation with const") \
V(kUnsupportedDoubleImmediate, "Unsupported double immediate") \ V(kUnsupportedDoubleImmediate, "Unsupported double immediate") \
V(kUnsupportedLetCompoundAssignment, "Unsupported let compound assignment") \ V(kUnsupportedLetCompoundAssignment, "Unsupported let compound assignment") \
V(kUnsupportedLookupSlotInDeclaration, \ V(kUnsupportedLookupSlotInDeclaration, \

View File

@ -536,7 +536,7 @@ bool AstGraphBuilder::CreateGraph(bool stack_check) {
// TODO(mstarzinger): For now we cannot assume that the {this} parameter is // TODO(mstarzinger): For now we cannot assume that the {this} parameter is
// not {the_hole}, because for derived classes {this} has a TDZ and the // not {the_hole}, because for derived classes {this} has a TDZ and the
// JSConstructStubForDerived magically passes {the_hole} as a receiver. // JSConstructStubForDerived magically passes {the_hole} as a receiver.
if (scope->has_this_declaration() && scope->receiver()->is_const_mode()) { if (scope->has_this_declaration() && scope->receiver()->mode() == CONST) {
env.RawParameterBind(0, jsgraph()->TheHoleConstant()); env.RawParameterBind(0, jsgraph()->TheHoleConstant());
} }
@ -3442,15 +3442,7 @@ Node* AstGraphBuilder::BuildVariableAssignment(
case VariableLocation::PARAMETER: case VariableLocation::PARAMETER:
case VariableLocation::LOCAL: case VariableLocation::LOCAL:
// Local var, const, or let variable. // Local var, const, or let variable.
if (mode == CONST_LEGACY && op != Token::INIT) { if (mode == LET && op == Token::INIT) {
// Non-initializing assignment to legacy const is
// - exception in strict mode.
// - ignored in sloppy mode.
if (is_strict(language_mode())) {
return BuildThrowConstAssignError(bailout_id);
}
return value;
} else if (mode == LET && op == Token::INIT) {
// No initialization check needed because scoping guarantees it. Note // No initialization check needed because scoping guarantees it. Note
// that we still perform a lookup to keep the variable live, because // that we still perform a lookup to keep the variable live, because
// baseline code might contain debug code that inspects the variable. // baseline code might contain debug code that inspects the variable.
@ -3473,6 +3465,16 @@ Node* AstGraphBuilder::BuildVariableAssignment(
if (current->op() != the_hole->op() && variable->is_this()) { if (current->op() != the_hole->op() && variable->is_this()) {
value = BuildHoleCheckElseThrow(current, variable, value, bailout_id); value = BuildHoleCheckElseThrow(current, variable, value, bailout_id);
} }
} else if (mode == CONST && op != Token::INIT &&
variable->is_sloppy_function_name()) {
// Non-initializing assignment to sloppy function names is
// - exception in strict mode.
// - ignored in sloppy mode.
DCHECK(!variable->binding_needs_init());
if (variable->throw_on_const_assignment(language_mode())) {
return BuildThrowConstAssignError(bailout_id);
}
return value;
} else if (mode == CONST && op != Token::INIT) { } else if (mode == CONST && op != Token::INIT) {
if (variable->binding_needs_init()) { if (variable->binding_needs_init()) {
Node* current = environment()->Lookup(variable); Node* current = environment()->Lookup(variable);
@ -3490,16 +3492,7 @@ Node* AstGraphBuilder::BuildVariableAssignment(
case VariableLocation::CONTEXT: { case VariableLocation::CONTEXT: {
// Context variable (potentially up the context chain). // Context variable (potentially up the context chain).
int depth = current_scope()->ContextChainLength(variable->scope()); int depth = current_scope()->ContextChainLength(variable->scope());
if (mode == CONST_LEGACY && op != Token::INIT) { if (mode == LET && op != Token::INIT && variable->binding_needs_init()) {
// Non-initializing assignment to legacy const is
// - exception in strict mode.
// - ignored in sloppy mode.
if (is_strict(language_mode())) {
return BuildThrowConstAssignError(bailout_id);
}
return value;
} else if (mode == LET && op != Token::INIT &&
variable->binding_needs_init()) {
// Perform an initialization check for let declared variables. // Perform an initialization check for let declared variables.
const Operator* op = const Operator* op =
javascript()->LoadContext(depth, variable->index(), false); javascript()->LoadContext(depth, variable->index(), false);
@ -3515,6 +3508,16 @@ Node* AstGraphBuilder::BuildVariableAssignment(
Node* current = NewNode(op, current_context()); Node* current = NewNode(op, current_context());
value = BuildHoleCheckElseThrow(current, variable, value, bailout_id); value = BuildHoleCheckElseThrow(current, variable, value, bailout_id);
} }
} else if (mode == CONST && op != Token::INIT &&
variable->is_sloppy_function_name()) {
// Non-initializing assignment to sloppy function names is
// - exception in strict mode.
// - ignored in sloppy mode.
DCHECK(!variable->binding_needs_init());
if (variable->throw_on_const_assignment(language_mode())) {
return BuildThrowConstAssignError(bailout_id);
}
return value;
} else if (mode == CONST && op != Token::INIT) { } else if (mode == CONST && op != Token::INIT) {
if (variable->binding_needs_init()) { if (variable->binding_needs_init()) {
const Operator* op = const Operator* op =

View File

@ -247,7 +247,7 @@ bool JSGlobalObjectSpecialization::LookupInScriptContextTable(
Handle<Context> script_context = ScriptContextTable::GetContext( Handle<Context> script_context = ScriptContextTable::GetContext(
script_context_table, lookup_result.context_index); script_context_table, lookup_result.context_index);
result->context = script_context; result->context = script_context;
result->immutable = IsImmutableVariableMode(lookup_result.mode); result->immutable = lookup_result.mode == CONST;
result->index = lookup_result.slot_index; result->index = lookup_result.slot_index;
return true; return true;
} }

View File

@ -178,7 +178,7 @@ static Maybe<bool> UnscopableLookup(LookupIterator* it) {
static PropertyAttributes GetAttributesForMode(VariableMode mode) { static PropertyAttributes GetAttributesForMode(VariableMode mode) {
DCHECK(IsDeclaredVariableMode(mode)); DCHECK(IsDeclaredVariableMode(mode));
return IsImmutableVariableMode(mode) ? READ_ONLY : NONE; return mode == CONST ? READ_ONLY : NONE;
} }
Handle<Object> Context::Lookup(Handle<String> name, ContextLookupFlags flags, Handle<Object> Context::Lookup(Handle<String> name, ContextLookupFlags flags,
@ -307,10 +307,11 @@ Handle<Object> Context::Lookup(Handle<String> name, ContextLookupFlags flags,
} }
// Check the slot corresponding to the intermediate context holding // Check the slot corresponding to the intermediate context holding
// only the function name variable. // only the function name variable. It's conceptually (and spec-wise)
if (follow_context_chain && context->IsFunctionContext()) { // in an outer scope of the function's declaration scope.
VariableMode mode; if (follow_context_chain && (flags & STOP_AT_DECLARATION_SCOPE) == 0 &&
int function_index = scope_info->FunctionContextSlotIndex(*name, &mode); context->IsFunctionContext()) {
int function_index = scope_info->FunctionContextSlotIndex(*name);
if (function_index >= 0) { if (function_index >= 0) {
if (FLAG_trace_contexts) { if (FLAG_trace_contexts) {
PrintF("=> found intermediate function in context slot %d\n", PrintF("=> found intermediate function in context slot %d\n",
@ -318,9 +319,8 @@ Handle<Object> Context::Lookup(Handle<String> name, ContextLookupFlags flags,
} }
*index = function_index; *index = function_index;
*attributes = READ_ONLY; *attributes = READ_ONLY;
DCHECK(mode == CONST_LEGACY || mode == CONST);
*init_flag = kCreatedInitialized; *init_flag = kCreatedInitialized;
*variable_mode = mode; *variable_mode = CONST;
return context; return context;
} }
} }

View File

@ -6956,9 +6956,6 @@ void HOptimizedGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
case VariableLocation::PARAMETER: case VariableLocation::PARAMETER:
case VariableLocation::LOCAL: case VariableLocation::LOCAL:
if (var->mode() == CONST_LEGACY) {
return Bailout(kUnsupportedConstCompoundAssignment);
}
if (var->mode() == CONST) { if (var->mode() == CONST) {
return Bailout(kNonInitializerAssignmentToConst); return Bailout(kNonInitializerAssignmentToConst);
} }
@ -6988,9 +6985,7 @@ void HOptimizedGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
mode = HStoreContextSlot::kCheckDeoptimize; mode = HStoreContextSlot::kCheckDeoptimize;
break; break;
case CONST: case CONST:
return Bailout(kNonInitializerAssignmentToConst); if (var->throw_on_const_assignment(function_language_mode())) {
case CONST_LEGACY:
if (is_strict(function_language_mode())) {
return Bailout(kNonInitializerAssignmentToConst); return Bailout(kNonInitializerAssignmentToConst);
} else { } else {
return ast_context()->ReturnValue(Pop()); return ast_context()->ReturnValue(Pop());
@ -7062,26 +7057,13 @@ void HOptimizedGraphBuilder::VisitAssignment(Assignment* expr) {
if (var->mode() == CONST) { if (var->mode() == CONST) {
if (expr->op() != Token::INIT) { if (expr->op() != Token::INIT) {
return Bailout(kNonInitializerAssignmentToConst); if (var->throw_on_const_assignment(function_language_mode())) {
}
} else if (var->mode() == CONST_LEGACY) {
if (expr->op() != Token::INIT) {
if (is_strict(function_language_mode())) {
return Bailout(kNonInitializerAssignmentToConst); return Bailout(kNonInitializerAssignmentToConst);
} else { } else {
CHECK_ALIVE(VisitForValue(expr->value())); CHECK_ALIVE(VisitForValue(expr->value()));
return ast_context()->ReturnValue(Pop()); return ast_context()->ReturnValue(Pop());
} }
} }
// TODO(adamk): Is this required? Legacy const variables are always
// initialized before use.
if (var->IsStackAllocated()) {
// We insert a use of the old value to detect unsupported uses of const
// variables (e.g. initialization inside a loop).
HValue* old_value = environment()->Lookup(var);
Add<HUseConst>(old_value);
}
} }
if (var->is_arguments()) return Bailout(kAssignmentToArguments); if (var->is_arguments()) return Bailout(kAssignmentToArguments);
@ -7137,10 +7119,10 @@ void HOptimizedGraphBuilder::VisitAssignment(Assignment* expr) {
mode = HStoreContextSlot::kCheckDeoptimize; mode = HStoreContextSlot::kCheckDeoptimize;
break; break;
case CONST: case CONST:
// This case is checked statically so no need to // If we reached this point, the only possibility
// perform checks here // is a sloppy assignment to a function name.
UNREACHABLE(); DCHECK(function_language_mode() == SLOPPY &&
case CONST_LEGACY: !var->throw_on_const_assignment(SLOPPY));
return ast_context()->ReturnValue(Pop()); return ast_context()->ReturnValue(Pop());
default: default:
mode = HStoreContextSlot::kNoCheck; mode = HStoreContextSlot::kNoCheck;
@ -10751,9 +10733,6 @@ void HOptimizedGraphBuilder::VisitCountOperation(CountOperation* expr) {
if (proxy != NULL) { if (proxy != NULL) {
Variable* var = proxy->var(); Variable* var = proxy->var();
if (var->mode() == CONST_LEGACY) {
return Bailout(kUnsupportedCountOperationWithConst);
}
if (var->mode() == CONST) { if (var->mode() == CONST) {
return Bailout(kNonInitializerAssignmentToConst); return Bailout(kNonInitializerAssignmentToConst);
} }

View File

@ -2169,10 +2169,10 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
__ CallRuntime(Runtime::kThrowReferenceError); __ CallRuntime(Runtime::kThrowReferenceError);
__ bind(&assign); __ bind(&assign);
} }
if (var->mode() == CONST) { if (var->mode() != CONST) {
__ CallRuntime(Runtime::kThrowConstAssignError);
} else {
EmitStoreToStackLocalOrContextSlot(var, location); EmitStoreToStackLocalOrContextSlot(var, location);
} else if (var->throw_on_const_assignment(language_mode())) {
__ CallRuntime(Runtime::kThrowConstAssignError);
} }
} else if (var->is_this() && var->mode() == CONST && op == Token::INIT) { } else if (var->is_this() && var->mode() == CONST && op == Token::INIT) {
// Initializing assignment to const {this} needs a write barrier. // Initializing assignment to const {this} needs a write barrier.
@ -2188,7 +2188,8 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
__ bind(&uninitialized_this); __ bind(&uninitialized_this);
EmitStoreToStackLocalOrContextSlot(var, location); EmitStoreToStackLocalOrContextSlot(var, location);
} else if (!var->is_const_mode() || op == Token::INIT) { } else {
DCHECK(var->mode() != CONST || op == Token::INIT);
if (var->IsLookupSlot()) { if (var->IsLookupSlot()) {
// Assignment to var. // Assignment to var.
__ Push(var->name()); __ Push(var->name());
@ -2209,13 +2210,6 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
} }
EmitStoreToStackLocalOrContextSlot(var, location); EmitStoreToStackLocalOrContextSlot(var, location);
} }
} else {
DCHECK(var->mode() == CONST_LEGACY && op != Token::INIT);
if (is_strict(language_mode())) {
__ CallRuntime(Runtime::kThrowConstAssignError);
}
// Silently ignore store in sloppy mode.
} }
} }

View File

@ -2062,10 +2062,10 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
__ CallRuntime(Runtime::kThrowReferenceError); __ CallRuntime(Runtime::kThrowReferenceError);
__ Bind(&assign); __ Bind(&assign);
} }
if (var->mode() == CONST) { if (var->mode() != CONST) {
__ CallRuntime(Runtime::kThrowConstAssignError);
} else {
EmitStoreToStackLocalOrContextSlot(var, location); EmitStoreToStackLocalOrContextSlot(var, location);
} else if (var->throw_on_const_assignment(language_mode())) {
__ CallRuntime(Runtime::kThrowConstAssignError);
} }
} else if (var->is_this() && var->mode() == CONST && op == Token::INIT) { } else if (var->is_this() && var->mode() == CONST && op == Token::INIT) {
// Initializing assignment to const {this} needs a write barrier. // Initializing assignment to const {this} needs a write barrier.
@ -2080,7 +2080,8 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
__ bind(&uninitialized_this); __ bind(&uninitialized_this);
EmitStoreToStackLocalOrContextSlot(var, location); EmitStoreToStackLocalOrContextSlot(var, location);
} else if (!var->is_const_mode() || op == Token::INIT) { } else {
DCHECK(var->mode() != CONST || op == Token::INIT);
if (var->IsLookupSlot()) { if (var->IsLookupSlot()) {
// Assignment to var. // Assignment to var.
__ Push(var->name()); __ Push(var->name());
@ -2100,13 +2101,6 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
} }
EmitStoreToStackLocalOrContextSlot(var, location); EmitStoreToStackLocalOrContextSlot(var, location);
} }
} else {
DCHECK(var->mode() == CONST_LEGACY && op != Token::INIT);
if (is_strict(language_mode())) {
__ CallRuntime(Runtime::kThrowConstAssignError);
}
// Silently ignore store in sloppy mode.
} }
} }

View File

@ -2075,10 +2075,10 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
__ CallRuntime(Runtime::kThrowReferenceError); __ CallRuntime(Runtime::kThrowReferenceError);
__ bind(&assign); __ bind(&assign);
} }
if (var->mode() == CONST) { if (var->mode() != CONST) {
__ CallRuntime(Runtime::kThrowConstAssignError);
} else {
EmitStoreToStackLocalOrContextSlot(var, location); EmitStoreToStackLocalOrContextSlot(var, location);
} else if (var->throw_on_const_assignment(language_mode())) {
__ CallRuntime(Runtime::kThrowConstAssignError);
} }
} else if (var->is_this() && var->mode() == CONST && op == Token::INIT) { } else if (var->is_this() && var->mode() == CONST && op == Token::INIT) {
// Initializing assignment to const {this} needs a write barrier. // Initializing assignment to const {this} needs a write barrier.
@ -2093,7 +2093,8 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
__ bind(&uninitialized_this); __ bind(&uninitialized_this);
EmitStoreToStackLocalOrContextSlot(var, location); EmitStoreToStackLocalOrContextSlot(var, location);
} else if (!var->is_const_mode() || op == Token::INIT) { } else {
DCHECK(var->mode() != CONST || op == Token::INIT);
if (var->IsLookupSlot()) { if (var->IsLookupSlot()) {
// Assignment to var. // Assignment to var.
__ Push(Immediate(var->name())); __ Push(Immediate(var->name()));
@ -2114,13 +2115,6 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
} }
EmitStoreToStackLocalOrContextSlot(var, location); EmitStoreToStackLocalOrContextSlot(var, location);
} }
} else {
DCHECK(var->mode() == CONST_LEGACY && op != Token::INIT);
if (is_strict(language_mode())) {
__ CallRuntime(Runtime::kThrowConstAssignError);
}
// Silently ignore store in sloppy mode.
} }
} }

View File

@ -2174,10 +2174,10 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
__ CallRuntime(Runtime::kThrowReferenceError); __ CallRuntime(Runtime::kThrowReferenceError);
__ bind(&assign); __ bind(&assign);
} }
if (var->mode() == CONST) { if (var->mode() != CONST) {
__ CallRuntime(Runtime::kThrowConstAssignError);
} else {
EmitStoreToStackLocalOrContextSlot(var, location); EmitStoreToStackLocalOrContextSlot(var, location);
} else if (var->throw_on_const_assignment(language_mode())) {
__ CallRuntime(Runtime::kThrowConstAssignError);
} }
} else if (var->is_this() && var->mode() == CONST && op == Token::INIT) { } else if (var->is_this() && var->mode() == CONST && op == Token::INIT) {
// Initializing assignment to const {this} needs a write barrier. // Initializing assignment to const {this} needs a write barrier.
@ -2193,7 +2193,8 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
__ bind(&uninitialized_this); __ bind(&uninitialized_this);
EmitStoreToStackLocalOrContextSlot(var, location); EmitStoreToStackLocalOrContextSlot(var, location);
} else if (!var->is_const_mode() || op == Token::INIT) { } else {
DCHECK(var->mode() != CONST || op == Token::INIT);
if (var->IsLookupSlot()) { if (var->IsLookupSlot()) {
// Assignment to var. // Assignment to var.
__ Push(var->name()); __ Push(var->name());
@ -2214,13 +2215,6 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
} }
EmitStoreToStackLocalOrContextSlot(var, location); EmitStoreToStackLocalOrContextSlot(var, location);
} }
} else {
DCHECK(var->mode() == CONST_LEGACY && op != Token::INIT);
if (is_strict(language_mode())) {
__ CallRuntime(Runtime::kThrowConstAssignError);
}
// Silently ignore store in sloppy mode.
} }
} }

View File

@ -2174,10 +2174,10 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
__ CallRuntime(Runtime::kThrowReferenceError); __ CallRuntime(Runtime::kThrowReferenceError);
__ bind(&assign); __ bind(&assign);
} }
if (var->mode() == CONST) { if (var->mode() != CONST) {
__ CallRuntime(Runtime::kThrowConstAssignError);
} else {
EmitStoreToStackLocalOrContextSlot(var, location); EmitStoreToStackLocalOrContextSlot(var, location);
} else if (var->throw_on_const_assignment(language_mode())) {
__ CallRuntime(Runtime::kThrowConstAssignError);
} }
} else if (var->is_this() && var->mode() == CONST && op == Token::INIT) { } else if (var->is_this() && var->mode() == CONST && op == Token::INIT) {
// Initializing assignment to const {this} needs a write barrier. // Initializing assignment to const {this} needs a write barrier.
@ -2193,7 +2193,8 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
__ bind(&uninitialized_this); __ bind(&uninitialized_this);
EmitStoreToStackLocalOrContextSlot(var, location); EmitStoreToStackLocalOrContextSlot(var, location);
} else if (!var->is_const_mode() || op == Token::INIT) { } else {
DCHECK(var->mode() != CONST || op == Token::INIT);
if (var->IsLookupSlot()) { if (var->IsLookupSlot()) {
__ Push(var->name()); __ Push(var->name());
__ Push(v0); __ Push(v0);
@ -2213,13 +2214,6 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
} }
EmitStoreToStackLocalOrContextSlot(var, location); EmitStoreToStackLocalOrContextSlot(var, location);
} }
} else {
DCHECK(var->mode() == CONST_LEGACY && op != Token::INIT);
if (is_strict(language_mode())) {
__ CallRuntime(Runtime::kThrowConstAssignError);
}
// Silently ignore store in sloppy mode.
} }
} }

View File

@ -2066,10 +2066,10 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
__ CallRuntime(Runtime::kThrowReferenceError); __ CallRuntime(Runtime::kThrowReferenceError);
__ bind(&assign); __ bind(&assign);
} }
if (var->mode() == CONST) { if (var->mode() != CONST) {
__ CallRuntime(Runtime::kThrowConstAssignError);
} else {
EmitStoreToStackLocalOrContextSlot(var, location); EmitStoreToStackLocalOrContextSlot(var, location);
} else if (var->throw_on_const_assignment(language_mode())) {
__ CallRuntime(Runtime::kThrowConstAssignError);
} }
} else if (var->is_this() && var->mode() == CONST && op == Token::INIT) { } else if (var->is_this() && var->mode() == CONST && op == Token::INIT) {
@ -2085,7 +2085,8 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
__ bind(&uninitialized_this); __ bind(&uninitialized_this);
EmitStoreToStackLocalOrContextSlot(var, location); EmitStoreToStackLocalOrContextSlot(var, location);
} else if (!var->is_const_mode() || op == Token::INIT) { } else {
DCHECK(var->mode() != CONST || op == Token::INIT);
if (var->IsLookupSlot()) { if (var->IsLookupSlot()) {
// Assignment to var. // Assignment to var.
__ Push(var->name()); __ Push(var->name());
@ -2106,13 +2107,6 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
} }
EmitStoreToStackLocalOrContextSlot(var, location); EmitStoreToStackLocalOrContextSlot(var, location);
} }
} else {
DCHECK(var->mode() == CONST_LEGACY && op != Token::INIT);
if (is_strict(language_mode())) {
__ CallRuntime(Runtime::kThrowConstAssignError);
}
// Silently ignore store in sloppy mode.
} }
} }

View File

@ -884,8 +884,6 @@ enum VariableMode : uint8_t {
// User declared variables: // User declared variables:
VAR, // declared via 'var', and 'function' declarations VAR, // declared via 'var', and 'function' declarations
CONST_LEGACY, // declared via legacy 'const' declarations
LET, // declared via 'let' declarations (first lexical) LET, // declared via 'let' declarations (first lexical)
CONST, // declared via 'const' declarations (last lexical) CONST, // declared via 'const' declarations (last lexical)
@ -924,11 +922,6 @@ inline bool IsLexicalVariableMode(VariableMode mode) {
return mode >= LET && mode <= CONST; return mode >= LET && mode <= CONST;
} }
inline bool IsImmutableVariableMode(VariableMode mode) {
return mode == CONST || mode == CONST_LEGACY;
}
enum VariableLocation : uint8_t { enum VariableLocation : uint8_t {
// Before and during variable allocation, a variable whose location is // Before and during variable allocation, a variable whose location is
// not yet determined. After allocation, a variable looked up as a // not yet determined. After allocation, a variable looked up as a

View File

@ -2083,7 +2083,6 @@ void BytecodeGenerator::BuildThrowIfNotHole(Handle<String> name) {
void BytecodeGenerator::BuildHoleCheckForVariableAssignment(Variable* variable, void BytecodeGenerator::BuildHoleCheckForVariableAssignment(Variable* variable,
Token::Value op) { Token::Value op) {
DCHECK(variable->mode() != CONST_LEGACY);
if (op != Token::INIT) { if (op != Token::INIT) {
// Perform an initialization check for let/const declared variables. // Perform an initialization check for let/const declared variables.
// E.g. let x = (x = 20); is not allowed. // E.g. let x = (x = 20); is not allowed.
@ -2128,17 +2127,11 @@ void BytecodeGenerator::VisitVariableAssignment(Variable* variable,
builder()->LoadAccumulatorWithRegister(value_temp); builder()->LoadAccumulatorWithRegister(value_temp);
} }
if ((mode == CONST || mode == CONST_LEGACY) && op != Token::INIT) { if (mode != CONST || op == Token::INIT) {
if (mode == CONST || is_strict(language_mode())) { builder()->StoreAccumulatorInRegister(destination);
builder()->CallRuntime(Runtime::kThrowConstAssignError, Register(), } else if (variable->throw_on_const_assignment(language_mode())) {
0); builder()->CallRuntime(Runtime::kThrowConstAssignError, Register(), 0);
}
// Non-initializing assignments to legacy constants are ignored
// in sloppy mode. Break here to avoid storing into variable.
break;
} }
builder()->StoreAccumulatorInRegister(destination);
break; break;
} }
case VariableLocation::GLOBAL: case VariableLocation::GLOBAL:
@ -2185,21 +2178,14 @@ void BytecodeGenerator::VisitVariableAssignment(Variable* variable,
builder()->LoadAccumulatorWithRegister(value_temp); builder()->LoadAccumulatorWithRegister(value_temp);
} }
if ((mode == CONST || mode == CONST_LEGACY) && op != Token::INIT) { if (mode != CONST || op == Token::INIT) {
if (mode == CONST || is_strict(language_mode())) { builder()->StoreContextSlot(context_reg, variable->index());
builder()->CallRuntime(Runtime::kThrowConstAssignError, Register(), } else if (variable->throw_on_const_assignment(language_mode())) {
0); builder()->CallRuntime(Runtime::kThrowConstAssignError, Register(), 0);
}
// Non-initializing assignments to legacy constants are ignored
// in sloppy mode. Break here to avoid storing into variable.
break;
} }
builder()->StoreContextSlot(context_reg, variable->index());
break; break;
} }
case VariableLocation::LOOKUP: { case VariableLocation::LOOKUP: {
DCHECK_NE(CONST_LEGACY, variable->mode());
builder()->StoreLookupSlot(variable->name(), language_mode()); builder()->StoreLookupSlot(variable->name(), language_mode());
break; break;
} }

View File

@ -4384,7 +4384,7 @@ class ScopeInfo : public FixedArray {
// slot index if the function name is present and context-allocated (named // slot index if the function name is present and context-allocated (named
// function expressions, only), otherwise returns a value < 0. The name // function expressions, only), otherwise returns a value < 0. The name
// must be an internalized string. // must be an internalized string.
int FunctionContextSlotIndex(String* name, VariableMode* mode); int FunctionContextSlotIndex(String* name);
// Lookup support for serialized scope info. Returns the receiver context // Lookup support for serialized scope info. Returns the receiver context
// slot index if scope has a "this" binding, and the binding is // slot index if scope has a "this" binding, and the binding is
@ -4502,10 +4502,8 @@ class ScopeInfo : public FixedArray {
: public BitField<bool, ReceiverVariableField::kNext, 1> {}; : public BitField<bool, ReceiverVariableField::kNext, 1> {};
class FunctionVariableField class FunctionVariableField
: public BitField<VariableAllocationInfo, HasNewTargetField::kNext, 2> {}; : public BitField<VariableAllocationInfo, HasNewTargetField::kNext, 2> {};
class FunctionVariableMode class AsmModuleField
: public BitField<VariableMode, FunctionVariableField::kNext, 3> {}; : public BitField<bool, FunctionVariableField::kNext, 1> {};
class AsmModuleField : public BitField<bool, FunctionVariableMode::kNext, 1> {
};
class AsmFunctionField : public BitField<bool, AsmModuleField::kNext, 1> {}; class AsmFunctionField : public BitField<bool, AsmModuleField::kNext, 1> {};
class HasSimpleParametersField class HasSimpleParametersField
: public BitField<bool, AsmFunctionField::kNext, 1> {}; : public BitField<bool, AsmFunctionField::kNext, 1> {};

View File

@ -140,13 +140,6 @@ void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) {
// which the variable or constant is declared. Only function variables have // which the variable or constant is declared. Only function variables have
// an initial value in the declaration (because they are initialized upon // an initial value in the declaration (because they are initialized upon
// entering the function). // entering the function).
//
// If we have a legacy const declaration, in an inner scope, the proxy
// is always bound to the declared variable (independent of possibly
// surrounding 'with' statements).
// For let/const declarations in harmony mode, we can also immediately
// pre-resolve the proxy because it resides in the same scope as the
// declaration.
const AstRawString* name = pattern->raw_name(); const AstRawString* name = pattern->raw_name();
VariableProxy* proxy = descriptor_->scope->NewUnresolved( VariableProxy* proxy = descriptor_->scope->NewUnresolved(
factory(), name, parser_->scanner()->location().beg_pos, factory(), name, parser_->scanner()->location().beg_pos,

View File

@ -1216,8 +1216,7 @@ void V8HeapExplorer::ExtractContextReferences(int entry, Context* context) {
} }
if (scope_info->HasFunctionName()) { if (scope_info->HasFunctionName()) {
String* name = scope_info->FunctionName(); String* name = scope_info->FunctionName();
VariableMode mode; int idx = scope_info->FunctionContextSlotIndex(name);
int idx = scope_info->FunctionContextSlotIndex(name, &mode);
if (idx >= 0) { if (idx >= 0) {
SetContextReference(context, entry, name, context->get(idx), SetContextReference(context, entry, name, context->get(idx),
Context::OffsetOfElementAt(idx)); Context::OffsetOfElementAt(idx));