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:
parent
e1cb562224
commit
7516fe1eaa
@ -605,8 +605,10 @@ AsmType* AsmTyper::ValidateModule(FunctionLiteral* fun) {
|
||||
if (estatement != nullptr) {
|
||||
Assignment* assignment = estatement->expression()->AsAssignment();
|
||||
if (assignment != nullptr && assignment->target()->IsVariableProxy() &&
|
||||
assignment->target()->AsVariableProxy()->var()->mode() ==
|
||||
CONST_LEGACY) {
|
||||
assignment->target()
|
||||
->AsVariableProxy()
|
||||
->var()
|
||||
->is_sloppy_function_name()) {
|
||||
use_asm_directive = iter.Next();
|
||||
}
|
||||
}
|
||||
|
@ -833,7 +833,7 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
|
||||
// Skip extra assignment inserted by the parser when in this form:
|
||||
// (function Module(a, b, c) {... })
|
||||
if (expr->target()->IsVariableProxy() &&
|
||||
expr->target()->AsVariableProxy()->var()->mode() == CONST_LEGACY) {
|
||||
expr->target()->AsVariableProxy()->var()->is_sloppy_function_name()) {
|
||||
return;
|
||||
}
|
||||
Property* prop = expr->value()->AsProperty();
|
||||
|
@ -76,7 +76,6 @@ Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate, Zone* zone,
|
||||
|
||||
// Determine use and location of the function variable if it is present.
|
||||
VariableAllocationInfo function_name_info;
|
||||
VariableMode function_variable_mode;
|
||||
if (scope->is_function_scope() &&
|
||||
scope->AsDeclarationScope()->function_var() != nullptr) {
|
||||
Variable* var = scope->AsDeclarationScope()->function_var();
|
||||
@ -88,10 +87,8 @@ Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate, Zone* zone,
|
||||
DCHECK(var->IsStackLocal());
|
||||
function_name_info = STACK;
|
||||
}
|
||||
function_variable_mode = var->mode();
|
||||
} else {
|
||||
function_name_info = NONE;
|
||||
function_variable_mode = VAR;
|
||||
}
|
||||
|
||||
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) |
|
||||
HasNewTargetField::encode(has_new_target) |
|
||||
FunctionVariableField::encode(function_name_info) |
|
||||
FunctionVariableMode::encode(function_variable_mode) |
|
||||
AsmModuleField::encode(asm_module) |
|
||||
AsmFunctionField::encode(asm_function) |
|
||||
HasSimpleParametersField::encode(has_simple_parameters) |
|
||||
@ -254,7 +250,6 @@ Handle<ScopeInfo> ScopeInfo::CreateGlobalThisBinding(Isolate* isolate) {
|
||||
const bool has_simple_parameters = true;
|
||||
const VariableAllocationInfo receiver_info = CONTEXT;
|
||||
const VariableAllocationInfo function_name_info = NONE;
|
||||
const VariableMode function_variable_mode = VAR;
|
||||
const bool has_function_name = false;
|
||||
const bool has_receiver = true;
|
||||
const int parameter_count = 0;
|
||||
@ -272,7 +267,6 @@ Handle<ScopeInfo> ScopeInfo::CreateGlobalThisBinding(Isolate* isolate) {
|
||||
DeclarationScopeField::encode(true) |
|
||||
ReceiverVariableField::encode(receiver_info) |
|
||||
FunctionVariableField::encode(function_name_info) |
|
||||
FunctionVariableMode::encode(function_variable_mode) |
|
||||
AsmModuleField::encode(false) | AsmFunctionField::encode(false) |
|
||||
HasSimpleParametersField::encode(has_simple_parameters) |
|
||||
FunctionKindField::encode(FunctionKind::kNormalFunction);
|
||||
@ -625,14 +619,11 @@ int ScopeInfo::ReceiverContextSlotIndex() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int ScopeInfo::FunctionContextSlotIndex(String* name, VariableMode* mode) {
|
||||
int ScopeInfo::FunctionContextSlotIndex(String* name) {
|
||||
DCHECK(name->IsInternalizedString());
|
||||
DCHECK_NOT_NULL(mode);
|
||||
if (length() > 0) {
|
||||
if (FunctionVariableField::decode(Flags()) == CONTEXT &&
|
||||
FunctionName() == name) {
|
||||
*mode = FunctionVariableMode::decode(Flags());
|
||||
return Smi::cast(get(FunctionNameEntryIndex() + 1))->value();
|
||||
}
|
||||
}
|
||||
|
@ -415,11 +415,9 @@ void Scope::DeserializeScopeInfo(Isolate* isolate,
|
||||
if (scope_info_->HasFunctionName()) {
|
||||
Handle<String> name_handle(scope_info_->FunctionName(), isolate);
|
||||
const AstRawString* name = ast_value_factory->GetString(name_handle);
|
||||
VariableMode mode;
|
||||
int index = scope_info_->FunctionContextSlotIndex(*name_handle, &mode);
|
||||
int index = scope_info_->FunctionContextSlotIndex(*name_handle);
|
||||
if (index >= 0) {
|
||||
Variable* result = AsDeclarationScope()->DeclareFunctionVar(name);
|
||||
DCHECK_EQ(mode, result->mode());
|
||||
result->AllocateTo(VariableLocation::CONTEXT, index);
|
||||
}
|
||||
}
|
||||
@ -518,9 +516,11 @@ void DeclarationScope::DeclareDefaultFunctionVariables(
|
||||
Variable* DeclarationScope::DeclareFunctionVar(const AstRawString* name) {
|
||||
DCHECK(is_function_scope());
|
||||
DCHECK_NULL(function_);
|
||||
VariableMode mode = is_strict(language_mode()) ? CONST : CONST_LEGACY;
|
||||
function_ = new (zone())
|
||||
Variable(this, name, mode, Variable::NORMAL, kCreatedInitialized);
|
||||
Variable::Kind kind = is_sloppy(language_mode())
|
||||
? Variable::SLOPPY_FUNCTION_NAME
|
||||
: Variable::NORMAL;
|
||||
function_ =
|
||||
new (zone()) Variable(this, name, CONST, kind, kCreatedInitialized);
|
||||
return function_;
|
||||
}
|
||||
|
||||
@ -682,11 +682,9 @@ Variable* DeclarationScope::LookupFunctionVar(const AstRawString* name) {
|
||||
return function_;
|
||||
} else if (!scope_info_.is_null()) {
|
||||
// If we are backed by a scope info, try to lookup the variable there.
|
||||
VariableMode mode;
|
||||
int index = scope_info_->FunctionContextSlotIndex(*(name->string()), &mode);
|
||||
int index = scope_info_->FunctionContextSlotIndex(*(name->string()));
|
||||
if (index < 0) return nullptr;
|
||||
Variable* var = DeclareFunctionVar(name);
|
||||
DCHECK_EQ(mode, var->mode());
|
||||
var->AllocateTo(VariableLocation::CONTEXT, index);
|
||||
return var;
|
||||
} else {
|
||||
@ -748,7 +746,7 @@ Variable* Scope::DeclareVariable(
|
||||
Declaration* declaration, VariableMode mode, InitializationFlag init,
|
||||
bool allow_harmony_restrictive_generators,
|
||||
bool* sloppy_mode_block_scope_function_redefinition, bool* ok) {
|
||||
DCHECK(IsDeclaredVariableMode(mode) && mode != CONST_LEGACY);
|
||||
DCHECK(IsDeclaredVariableMode(mode));
|
||||
DCHECK(!already_resolved_);
|
||||
|
||||
if (mode == VAR && !is_declaration_scope()) {
|
||||
|
@ -16,7 +16,6 @@ namespace internal {
|
||||
const char* Variable::Mode2String(VariableMode mode) {
|
||||
switch (mode) {
|
||||
case VAR: return "VAR";
|
||||
case CONST_LEGACY: return "CONST_LEGACY";
|
||||
case LET: return "LET";
|
||||
case CONST: return "CONST";
|
||||
case DYNAMIC: return "DYNAMIC";
|
||||
|
@ -22,7 +22,8 @@ class Variable final : public ZoneObject {
|
||||
FUNCTION,
|
||||
THIS,
|
||||
ARGUMENTS,
|
||||
kLastKind = ARGUMENTS
|
||||
SLOPPY_FUNCTION_NAME,
|
||||
kLastKind = SLOPPY_FUNCTION_NAME
|
||||
};
|
||||
|
||||
Variable(Scope* scope, const AstRawString* name, VariableMode mode, Kind kind,
|
||||
@ -77,16 +78,21 @@ class Variable final : public ZoneObject {
|
||||
bool IsStaticGlobalObjectProperty() const;
|
||||
|
||||
bool is_dynamic() const { return IsDynamicVariableMode(mode()); }
|
||||
bool is_const_mode() const { return IsImmutableVariableMode(mode()); }
|
||||
bool binding_needs_init() const {
|
||||
DCHECK(initialization_flag() != kNeedsInitialization ||
|
||||
IsLexicalVariableMode(mode()));
|
||||
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_this() const { return kind() == THIS; }
|
||||
bool is_arguments() const { return kind() == ARGUMENTS; }
|
||||
bool is_sloppy_function_name() const {
|
||||
return kind() == SLOPPY_FUNCTION_NAME;
|
||||
}
|
||||
|
||||
Variable* local_if_not_shadowed() const {
|
||||
DCHECK(mode() == DYNAMIC_LOCAL && local_if_not_shadowed_ != NULL);
|
||||
@ -129,7 +135,7 @@ class Variable final : public ZoneObject {
|
||||
uint16_t bit_field_;
|
||||
|
||||
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
|
||||
: public BitField16<VariableLocation, KindField::kNext, 3> {};
|
||||
class ForceContextAllocationField
|
||||
|
@ -242,10 +242,6 @@ namespace internal {
|
||||
V(kUnexpectedTypeForRegExpDataFixedArrayExpected, \
|
||||
"Unexpected type for RegExp data, FixedArray expected") \
|
||||
V(kUnexpectedValue, "Unexpected value") \
|
||||
V(kUnsupportedConstCompoundAssignment, \
|
||||
"Unsupported const compound assignment") \
|
||||
V(kUnsupportedCountOperationWithConst, \
|
||||
"Unsupported count operation with const") \
|
||||
V(kUnsupportedDoubleImmediate, "Unsupported double immediate") \
|
||||
V(kUnsupportedLetCompoundAssignment, "Unsupported let compound assignment") \
|
||||
V(kUnsupportedLookupSlotInDeclaration, \
|
||||
|
@ -536,7 +536,7 @@ bool AstGraphBuilder::CreateGraph(bool stack_check) {
|
||||
// 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
|
||||
// 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());
|
||||
}
|
||||
|
||||
@ -3442,15 +3442,7 @@ Node* AstGraphBuilder::BuildVariableAssignment(
|
||||
case VariableLocation::PARAMETER:
|
||||
case VariableLocation::LOCAL:
|
||||
// Local var, const, or let variable.
|
||||
if (mode == CONST_LEGACY && 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) {
|
||||
if (mode == LET && op == Token::INIT) {
|
||||
// No initialization check needed because scoping guarantees it. Note
|
||||
// that we still perform a lookup to keep the variable live, because
|
||||
// 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()) {
|
||||
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) {
|
||||
if (variable->binding_needs_init()) {
|
||||
Node* current = environment()->Lookup(variable);
|
||||
@ -3490,16 +3492,7 @@ Node* AstGraphBuilder::BuildVariableAssignment(
|
||||
case VariableLocation::CONTEXT: {
|
||||
// Context variable (potentially up the context chain).
|
||||
int depth = current_scope()->ContextChainLength(variable->scope());
|
||||
if (mode == CONST_LEGACY && 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 &&
|
||||
variable->binding_needs_init()) {
|
||||
if (mode == LET && op != Token::INIT && variable->binding_needs_init()) {
|
||||
// Perform an initialization check for let declared variables.
|
||||
const Operator* op =
|
||||
javascript()->LoadContext(depth, variable->index(), false);
|
||||
@ -3515,6 +3508,16 @@ Node* AstGraphBuilder::BuildVariableAssignment(
|
||||
Node* current = NewNode(op, current_context());
|
||||
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) {
|
||||
if (variable->binding_needs_init()) {
|
||||
const Operator* op =
|
||||
|
@ -247,7 +247,7 @@ bool JSGlobalObjectSpecialization::LookupInScriptContextTable(
|
||||
Handle<Context> script_context = ScriptContextTable::GetContext(
|
||||
script_context_table, lookup_result.context_index);
|
||||
result->context = script_context;
|
||||
result->immutable = IsImmutableVariableMode(lookup_result.mode);
|
||||
result->immutable = lookup_result.mode == CONST;
|
||||
result->index = lookup_result.slot_index;
|
||||
return true;
|
||||
}
|
||||
|
@ -178,7 +178,7 @@ static Maybe<bool> UnscopableLookup(LookupIterator* it) {
|
||||
|
||||
static PropertyAttributes GetAttributesForMode(VariableMode 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,
|
||||
@ -307,10 +307,11 @@ Handle<Object> Context::Lookup(Handle<String> name, ContextLookupFlags flags,
|
||||
}
|
||||
|
||||
// Check the slot corresponding to the intermediate context holding
|
||||
// only the function name variable.
|
||||
if (follow_context_chain && context->IsFunctionContext()) {
|
||||
VariableMode mode;
|
||||
int function_index = scope_info->FunctionContextSlotIndex(*name, &mode);
|
||||
// only the function name variable. It's conceptually (and spec-wise)
|
||||
// in an outer scope of the function's declaration scope.
|
||||
if (follow_context_chain && (flags & STOP_AT_DECLARATION_SCOPE) == 0 &&
|
||||
context->IsFunctionContext()) {
|
||||
int function_index = scope_info->FunctionContextSlotIndex(*name);
|
||||
if (function_index >= 0) {
|
||||
if (FLAG_trace_contexts) {
|
||||
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;
|
||||
*attributes = READ_ONLY;
|
||||
DCHECK(mode == CONST_LEGACY || mode == CONST);
|
||||
*init_flag = kCreatedInitialized;
|
||||
*variable_mode = mode;
|
||||
*variable_mode = CONST;
|
||||
return context;
|
||||
}
|
||||
}
|
||||
|
@ -6956,9 +6956,6 @@ void HOptimizedGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
|
||||
|
||||
case VariableLocation::PARAMETER:
|
||||
case VariableLocation::LOCAL:
|
||||
if (var->mode() == CONST_LEGACY) {
|
||||
return Bailout(kUnsupportedConstCompoundAssignment);
|
||||
}
|
||||
if (var->mode() == CONST) {
|
||||
return Bailout(kNonInitializerAssignmentToConst);
|
||||
}
|
||||
@ -6988,9 +6985,7 @@ void HOptimizedGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
|
||||
mode = HStoreContextSlot::kCheckDeoptimize;
|
||||
break;
|
||||
case CONST:
|
||||
return Bailout(kNonInitializerAssignmentToConst);
|
||||
case CONST_LEGACY:
|
||||
if (is_strict(function_language_mode())) {
|
||||
if (var->throw_on_const_assignment(function_language_mode())) {
|
||||
return Bailout(kNonInitializerAssignmentToConst);
|
||||
} else {
|
||||
return ast_context()->ReturnValue(Pop());
|
||||
@ -7062,26 +7057,13 @@ void HOptimizedGraphBuilder::VisitAssignment(Assignment* expr) {
|
||||
|
||||
if (var->mode() == CONST) {
|
||||
if (expr->op() != Token::INIT) {
|
||||
return Bailout(kNonInitializerAssignmentToConst);
|
||||
}
|
||||
} else if (var->mode() == CONST_LEGACY) {
|
||||
if (expr->op() != Token::INIT) {
|
||||
if (is_strict(function_language_mode())) {
|
||||
if (var->throw_on_const_assignment(function_language_mode())) {
|
||||
return Bailout(kNonInitializerAssignmentToConst);
|
||||
} else {
|
||||
CHECK_ALIVE(VisitForValue(expr->value()));
|
||||
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);
|
||||
@ -7137,10 +7119,10 @@ void HOptimizedGraphBuilder::VisitAssignment(Assignment* expr) {
|
||||
mode = HStoreContextSlot::kCheckDeoptimize;
|
||||
break;
|
||||
case CONST:
|
||||
// This case is checked statically so no need to
|
||||
// perform checks here
|
||||
UNREACHABLE();
|
||||
case CONST_LEGACY:
|
||||
// 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;
|
||||
@ -10751,9 +10733,6 @@ void HOptimizedGraphBuilder::VisitCountOperation(CountOperation* expr) {
|
||||
|
||||
if (proxy != NULL) {
|
||||
Variable* var = proxy->var();
|
||||
if (var->mode() == CONST_LEGACY) {
|
||||
return Bailout(kUnsupportedCountOperationWithConst);
|
||||
}
|
||||
if (var->mode() == CONST) {
|
||||
return Bailout(kNonInitializerAssignmentToConst);
|
||||
}
|
||||
|
@ -2169,10 +2169,10 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
|
||||
__ CallRuntime(Runtime::kThrowReferenceError);
|
||||
__ bind(&assign);
|
||||
}
|
||||
if (var->mode() == CONST) {
|
||||
__ CallRuntime(Runtime::kThrowConstAssignError);
|
||||
} else {
|
||||
if (var->mode() != CONST) {
|
||||
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) {
|
||||
// Initializing assignment to const {this} needs a write barrier.
|
||||
@ -2188,7 +2188,8 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
|
||||
__ bind(&uninitialized_this);
|
||||
EmitStoreToStackLocalOrContextSlot(var, location);
|
||||
|
||||
} else if (!var->is_const_mode() || op == Token::INIT) {
|
||||
} else {
|
||||
DCHECK(var->mode() != CONST || op == Token::INIT);
|
||||
if (var->IsLookupSlot()) {
|
||||
// Assignment to var.
|
||||
__ Push(var->name());
|
||||
@ -2209,13 +2210,6 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
|
||||
}
|
||||
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.
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2062,10 +2062,10 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
|
||||
__ CallRuntime(Runtime::kThrowReferenceError);
|
||||
__ Bind(&assign);
|
||||
}
|
||||
if (var->mode() == CONST) {
|
||||
__ CallRuntime(Runtime::kThrowConstAssignError);
|
||||
} else {
|
||||
if (var->mode() != CONST) {
|
||||
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) {
|
||||
// Initializing assignment to const {this} needs a write barrier.
|
||||
@ -2080,7 +2080,8 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
|
||||
__ bind(&uninitialized_this);
|
||||
EmitStoreToStackLocalOrContextSlot(var, location);
|
||||
|
||||
} else if (!var->is_const_mode() || op == Token::INIT) {
|
||||
} else {
|
||||
DCHECK(var->mode() != CONST || op == Token::INIT);
|
||||
if (var->IsLookupSlot()) {
|
||||
// Assignment to var.
|
||||
__ Push(var->name());
|
||||
@ -2100,13 +2101,6 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
|
||||
}
|
||||
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.
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2075,10 +2075,10 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
|
||||
__ CallRuntime(Runtime::kThrowReferenceError);
|
||||
__ bind(&assign);
|
||||
}
|
||||
if (var->mode() == CONST) {
|
||||
__ CallRuntime(Runtime::kThrowConstAssignError);
|
||||
} else {
|
||||
if (var->mode() != CONST) {
|
||||
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) {
|
||||
// Initializing assignment to const {this} needs a write barrier.
|
||||
@ -2093,7 +2093,8 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
|
||||
__ bind(&uninitialized_this);
|
||||
EmitStoreToStackLocalOrContextSlot(var, location);
|
||||
|
||||
} else if (!var->is_const_mode() || op == Token::INIT) {
|
||||
} else {
|
||||
DCHECK(var->mode() != CONST || op == Token::INIT);
|
||||
if (var->IsLookupSlot()) {
|
||||
// Assignment to var.
|
||||
__ Push(Immediate(var->name()));
|
||||
@ -2114,13 +2115,6 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
|
||||
}
|
||||
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.
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2174,10 +2174,10 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
|
||||
__ CallRuntime(Runtime::kThrowReferenceError);
|
||||
__ bind(&assign);
|
||||
}
|
||||
if (var->mode() == CONST) {
|
||||
__ CallRuntime(Runtime::kThrowConstAssignError);
|
||||
} else {
|
||||
if (var->mode() != CONST) {
|
||||
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) {
|
||||
// Initializing assignment to const {this} needs a write barrier.
|
||||
@ -2193,7 +2193,8 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
|
||||
__ bind(&uninitialized_this);
|
||||
EmitStoreToStackLocalOrContextSlot(var, location);
|
||||
|
||||
} else if (!var->is_const_mode() || op == Token::INIT) {
|
||||
} else {
|
||||
DCHECK(var->mode() != CONST || op == Token::INIT);
|
||||
if (var->IsLookupSlot()) {
|
||||
// Assignment to var.
|
||||
__ Push(var->name());
|
||||
@ -2214,13 +2215,6 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
|
||||
}
|
||||
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.
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2174,10 +2174,10 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
|
||||
__ CallRuntime(Runtime::kThrowReferenceError);
|
||||
__ bind(&assign);
|
||||
}
|
||||
if (var->mode() == CONST) {
|
||||
__ CallRuntime(Runtime::kThrowConstAssignError);
|
||||
} else {
|
||||
if (var->mode() != CONST) {
|
||||
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) {
|
||||
// Initializing assignment to const {this} needs a write barrier.
|
||||
@ -2193,7 +2193,8 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
|
||||
__ bind(&uninitialized_this);
|
||||
EmitStoreToStackLocalOrContextSlot(var, location);
|
||||
|
||||
} else if (!var->is_const_mode() || op == Token::INIT) {
|
||||
} else {
|
||||
DCHECK(var->mode() != CONST || op == Token::INIT);
|
||||
if (var->IsLookupSlot()) {
|
||||
__ Push(var->name());
|
||||
__ Push(v0);
|
||||
@ -2213,13 +2214,6 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
|
||||
}
|
||||
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.
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2066,10 +2066,10 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
|
||||
__ CallRuntime(Runtime::kThrowReferenceError);
|
||||
__ bind(&assign);
|
||||
}
|
||||
if (var->mode() == CONST) {
|
||||
__ CallRuntime(Runtime::kThrowConstAssignError);
|
||||
} else {
|
||||
if (var->mode() != CONST) {
|
||||
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) {
|
||||
@ -2085,7 +2085,8 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
|
||||
__ bind(&uninitialized_this);
|
||||
EmitStoreToStackLocalOrContextSlot(var, location);
|
||||
|
||||
} else if (!var->is_const_mode() || op == Token::INIT) {
|
||||
} else {
|
||||
DCHECK(var->mode() != CONST || op == Token::INIT);
|
||||
if (var->IsLookupSlot()) {
|
||||
// Assignment to var.
|
||||
__ Push(var->name());
|
||||
@ -2106,13 +2107,6 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
|
||||
}
|
||||
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.
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -884,8 +884,6 @@ enum VariableMode : uint8_t {
|
||||
// User declared variables:
|
||||
VAR, // declared via 'var', and 'function' declarations
|
||||
|
||||
CONST_LEGACY, // declared via legacy 'const' declarations
|
||||
|
||||
LET, // declared via 'let' declarations (first lexical)
|
||||
|
||||
CONST, // declared via 'const' declarations (last lexical)
|
||||
@ -924,11 +922,6 @@ inline bool IsLexicalVariableMode(VariableMode mode) {
|
||||
return mode >= LET && mode <= CONST;
|
||||
}
|
||||
|
||||
|
||||
inline bool IsImmutableVariableMode(VariableMode mode) {
|
||||
return mode == CONST || mode == CONST_LEGACY;
|
||||
}
|
||||
|
||||
enum VariableLocation : uint8_t {
|
||||
// Before and during variable allocation, a variable whose location is
|
||||
// not yet determined. After allocation, a variable looked up as a
|
||||
|
@ -2083,7 +2083,6 @@ void BytecodeGenerator::BuildThrowIfNotHole(Handle<String> name) {
|
||||
|
||||
void BytecodeGenerator::BuildHoleCheckForVariableAssignment(Variable* variable,
|
||||
Token::Value op) {
|
||||
DCHECK(variable->mode() != CONST_LEGACY);
|
||||
if (op != Token::INIT) {
|
||||
// Perform an initialization check for let/const declared variables.
|
||||
// E.g. let x = (x = 20); is not allowed.
|
||||
@ -2128,17 +2127,11 @@ void BytecodeGenerator::VisitVariableAssignment(Variable* variable,
|
||||
builder()->LoadAccumulatorWithRegister(value_temp);
|
||||
}
|
||||
|
||||
if ((mode == CONST || mode == CONST_LEGACY) && op != Token::INIT) {
|
||||
if (mode == CONST || is_strict(language_mode())) {
|
||||
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;
|
||||
if (mode != CONST || op == Token::INIT) {
|
||||
builder()->StoreAccumulatorInRegister(destination);
|
||||
} else if (variable->throw_on_const_assignment(language_mode())) {
|
||||
builder()->CallRuntime(Runtime::kThrowConstAssignError, Register(), 0);
|
||||
}
|
||||
|
||||
builder()->StoreAccumulatorInRegister(destination);
|
||||
break;
|
||||
}
|
||||
case VariableLocation::GLOBAL:
|
||||
@ -2185,21 +2178,14 @@ void BytecodeGenerator::VisitVariableAssignment(Variable* variable,
|
||||
builder()->LoadAccumulatorWithRegister(value_temp);
|
||||
}
|
||||
|
||||
if ((mode == CONST || mode == CONST_LEGACY) && op != Token::INIT) {
|
||||
if (mode == CONST || is_strict(language_mode())) {
|
||||
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;
|
||||
if (mode != CONST || op == Token::INIT) {
|
||||
builder()->StoreContextSlot(context_reg, variable->index());
|
||||
} else if (variable->throw_on_const_assignment(language_mode())) {
|
||||
builder()->CallRuntime(Runtime::kThrowConstAssignError, Register(), 0);
|
||||
}
|
||||
|
||||
builder()->StoreContextSlot(context_reg, variable->index());
|
||||
break;
|
||||
}
|
||||
case VariableLocation::LOOKUP: {
|
||||
DCHECK_NE(CONST_LEGACY, variable->mode());
|
||||
builder()->StoreLookupSlot(variable->name(), language_mode());
|
||||
break;
|
||||
}
|
||||
|
@ -4384,7 +4384,7 @@ class ScopeInfo : public FixedArray {
|
||||
// slot index if the function name is present and context-allocated (named
|
||||
// function expressions, only), otherwise returns a value < 0. The name
|
||||
// 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
|
||||
// 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> {};
|
||||
class FunctionVariableField
|
||||
: public BitField<VariableAllocationInfo, HasNewTargetField::kNext, 2> {};
|
||||
class FunctionVariableMode
|
||||
: public BitField<VariableMode, FunctionVariableField::kNext, 3> {};
|
||||
class AsmModuleField : public BitField<bool, FunctionVariableMode::kNext, 1> {
|
||||
};
|
||||
class AsmModuleField
|
||||
: public BitField<bool, FunctionVariableField::kNext, 1> {};
|
||||
class AsmFunctionField : public BitField<bool, AsmModuleField::kNext, 1> {};
|
||||
class HasSimpleParametersField
|
||||
: public BitField<bool, AsmFunctionField::kNext, 1> {};
|
||||
|
@ -140,13 +140,6 @@ void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) {
|
||||
// which the variable or constant is declared. Only function variables have
|
||||
// an initial value in the declaration (because they are initialized upon
|
||||
// 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();
|
||||
VariableProxy* proxy = descriptor_->scope->NewUnresolved(
|
||||
factory(), name, parser_->scanner()->location().beg_pos,
|
||||
|
@ -1216,8 +1216,7 @@ void V8HeapExplorer::ExtractContextReferences(int entry, Context* context) {
|
||||
}
|
||||
if (scope_info->HasFunctionName()) {
|
||||
String* name = scope_info->FunctionName();
|
||||
VariableMode mode;
|
||||
int idx = scope_info->FunctionContextSlotIndex(name, &mode);
|
||||
int idx = scope_info->FunctionContextSlotIndex(name);
|
||||
if (idx >= 0) {
|
||||
SetContextReference(context, entry, name, context->get(idx),
|
||||
Context::OffsetOfElementAt(idx));
|
||||
|
Loading…
Reference in New Issue
Block a user