From: keuchel@chromium.org Date: Thu, 3 Nov 2011 11:59:51 +0000 (+0000) Subject: Remove some unnecessary binding initialization checks. X-Git-Tag: upstream/4.7.83~18012 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=58123bff567a55472ac95fa0826092a4a519a4f4;p=platform%2Fupstream%2Fv8.git Remove some unnecessary binding initialization checks. This depends on http://codereview.chromium.org/8352039/ . Review URL: http://codereview.chromium.org/8423005 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@9869 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc index d0c663b40..adc1b26c6 100644 --- a/src/arm/full-codegen-arm.cc +++ b/src/arm/full-codegen-arm.cc @@ -710,8 +710,8 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, // need to "declare" it at runtime to make sure it actually exists in the // local context. Variable* variable = proxy->var(); - bool binding_needs_init = - mode == CONST || mode == CONST_HARMONY || mode == LET; + bool binding_needs_init = (function == NULL) && + (mode == CONST || mode == CONST_HARMONY || mode == LET); switch (variable->location()) { case Variable::UNALLOCATED: ++(*global_count); diff --git a/src/contexts.cc b/src/contexts.cc index 0e7ef5f60..aee963b2b 100644 --- a/src/contexts.cc +++ b/src/contexts.cc @@ -146,7 +146,8 @@ Handle Context::Lookup(Handle name, ScopeInfo::cast(context->extension()), isolate); } VariableMode mode; - int slot_index = scope_info->ContextSlotIndex(*name, &mode); + InitializationFlag init_flag; + int slot_index = scope_info->ContextSlotIndex(*name, &mode, &init_flag); ASSERT(slot_index < 0 || slot_index >= MIN_CONTEXT_SLOTS); if (slot_index >= 0) { if (FLAG_trace_contexts) { @@ -168,15 +169,19 @@ Handle Context::Lookup(Handle name, break; case LET: *attributes = NONE; - *binding_flags = MUTABLE_CHECK_INITIALIZED; + *binding_flags = (init_flag == kNeedsInitialization) + ? MUTABLE_CHECK_INITIALIZED : MUTABLE_IS_INITIALIZED; break; case CONST: *attributes = READ_ONLY; - *binding_flags = IMMUTABLE_CHECK_INITIALIZED; + *binding_flags = (init_flag == kNeedsInitialization) + ? IMMUTABLE_CHECK_INITIALIZED : IMMUTABLE_IS_INITIALIZED; break; case CONST_HARMONY: *attributes = READ_ONLY; - *binding_flags = IMMUTABLE_CHECK_INITIALIZED_HARMONY; + *binding_flags = (init_flag == kNeedsInitialization) + ? IMMUTABLE_CHECK_INITIALIZED_HARMONY : + IMMUTABLE_IS_INITIALIZED_HARMONY; break; case DYNAMIC: case DYNAMIC_GLOBAL: @@ -252,7 +257,8 @@ bool Context::GlobalIfNotShadowedByEval(Handle name) { // Check non-parameter locals. Handle scope_info(context->closure()->shared()->scope_info()); VariableMode mode; - int index = scope_info->ContextSlotIndex(*name, &mode); + InitializationFlag init_flag; + int index = scope_info->ContextSlotIndex(*name, &mode, &init_flag); ASSERT(index < 0 || index >= MIN_CONTEXT_SLOTS); if (index >= 0) return false; diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc index 0af30f079..e8108fc7c 100644 --- a/src/ia32/full-codegen-ia32.cc +++ b/src/ia32/full-codegen-ia32.cc @@ -681,8 +681,8 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, // need to "declare" it at runtime to make sure it actually exists in the // local context. Variable* variable = proxy->var(); - bool binding_needs_init = - mode == CONST || mode == CONST_HARMONY || mode == LET; + bool binding_needs_init = (function == NULL) && + (mode == CONST || mode == CONST_HARMONY || mode == LET); switch (variable->location()) { case Variable::UNALLOCATED: ++(*global_count); diff --git a/src/mips/full-codegen-mips.cc b/src/mips/full-codegen-mips.cc index 5bb9b3598..53e39c1fb 100644 --- a/src/mips/full-codegen-mips.cc +++ b/src/mips/full-codegen-mips.cc @@ -720,8 +720,8 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, // need to "declare" it at runtime to make sure it actually exists in the // local context. Variable* variable = proxy->var(); - bool binding_needs_init = - mode == CONST || mode == CONST_HARMONY || mode == LET; + bool binding_needs_init = (function == NULL) && + (mode == CONST || mode == CONST_HARMONY || mode == LET); switch (variable->location()) { case Variable::UNALLOCATED: ++(*global_count); diff --git a/src/objects.h b/src/objects.h index 1805f63dc..03ed0b388 100644 --- a/src/objects.h +++ b/src/objects.h @@ -3169,6 +3169,9 @@ class ScopeInfo : public FixedArray { // Return the mode of the given context local. VariableMode ContextLocalMode(int var); + // Return the initialization flag of the given context local. + InitializationFlag ContextLocalInitFlag(int var); + // Lookup support for serialized scope info. Returns the // the stack slot index for a given slot name if the slot is // present; otherwise returns a value < 0. The name must be a symbol @@ -3180,7 +3183,9 @@ class ScopeInfo : public FixedArray { // returns a value < 0. The name must be a symbol (canonicalized). // If the slot is present and mode != NULL, sets *mode to the corresponding // mode for that variable. - int ContextSlotIndex(String* name, VariableMode* mode); + int ContextSlotIndex(String* name, + VariableMode* mode, + InitializationFlag* init_flag); // Lookup support for serialized scope info. Returns the // parameter index for a given parameter name if the parameter is present; @@ -3256,10 +3261,11 @@ class ScopeInfo : public FixedArray { // index starting with Context::MIN_CONTEXT_SLOTS. One slot is used per // context local, so in total this part occupies ContextLocalCount() slots // in the array. - // 4. ContextLocalModeEntries: - // Contains the variable modes corresponding to the context locals in - // ContextLocalNameEntries. One slot is used per context local, so in total - // this part occupies ContextLocalCount() slots in the array. + // 4. ContextLocalInfoEntries: + // Contains the variable modes and initialization flags corresponding to + // the context locals in ContextLocalNameEntries. One slot is used per + // context local, so in total this part occupies ContextLocalCount() + // slots in the array. // 5. FunctionNameEntryIndex: // If the scope belongs to a named function expression this part contains // information about the function variable. It always occupies two array @@ -3268,7 +3274,7 @@ class ScopeInfo : public FixedArray { int ParameterEntriesIndex(); int StackLocalEntriesIndex(); int ContextLocalNameEntriesIndex(); - int ContextLocalModeEntriesIndex(); + int ContextLocalInfoEntriesIndex(); int FunctionNameEntryIndex(); // Location of the function variable for named function expressions. @@ -3285,6 +3291,11 @@ class ScopeInfo : public FixedArray { class StrictModeField: public BitField {}; class FunctionVariableField: public BitField {}; class FunctionVariableMode: public BitField {}; + + // BitFields representing the encoded information for context locals in the + // ContextLocalInfoEntries part. + class ContextLocalMode: public BitField {}; + class ContextLocalInitFlag: public BitField {}; }; diff --git a/src/parser.cc b/src/parser.cc index 21acb83c6..3e85c7a6a 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -1385,7 +1385,9 @@ VariableProxy* Parser::Declare(Handle name, var = declaration_scope->LocalLookup(name); if (var == NULL) { // Declare the name. - var = declaration_scope->DeclareLocal(name, mode); + InitializationFlag init_flag = (fun != NULL || mode == VAR) + ? kCreatedInitialized : kNeedsInitialization; + var = declaration_scope->DeclareLocal(name, mode, init_flag); } else { // The name was declared in this scope before; check for conflicting // re-declarations. We have a conflict if either of the declarations is @@ -1452,7 +1454,12 @@ VariableProxy* Parser::Declare(Handle name, declaration_scope->is_global_scope()) { ASSERT(resolve); // should be set by all callers Variable::Kind kind = Variable::NORMAL; - var = new(zone()) Variable(declaration_scope, name, CONST, true, kind); + var = new(zone()) Variable(declaration_scope, + name, + CONST, + true, + kind, + kNeedsInitialization); } // If requested and we have a local variable, bind the proxy to the variable @@ -2283,7 +2290,8 @@ TryStatement* Parser::ParseTryStatement(bool* ok) { if (peek() == Token::LBRACE) { Target target(&this->target_stack_, &catch_collector); VariableMode mode = harmony_scoping_ ? LET : VAR; - catch_variable = catch_scope->DeclareLocal(name, mode); + catch_variable = + catch_scope->DeclareLocal(name, mode, kCreatedInitialized); SaveScope save_scope(this, catch_scope); catch_block = ParseBlock(NULL, CHECK_OK); diff --git a/src/runtime.cc b/src/runtime.cc index f15fbba37..ef8ff8347 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -10794,9 +10794,10 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) { for (; i < scope_info->LocalCount(); ++i) { Handle name(scope_info->LocalName(i)); VariableMode mode; + InitializationFlag init_flag; locals->set(i * 2, *name); - locals->set(i * 2 + 1, - context->get(scope_info->ContextSlotIndex(*name, &mode))); + locals->set(i * 2 + 1, context->get( + scope_info->ContextSlotIndex(*name, &mode, &init_flag))); } } @@ -10970,8 +10971,9 @@ static bool CopyContextLocalsToScopeObject( // Fill all context locals to the context extension. for (int i = 0; i < scope_info->ContextLocalCount(); i++) { VariableMode mode; + InitializationFlag init_flag; int context_index = scope_info->ContextSlotIndex( - scope_info->ContextLocalName(i), &mode); + scope_info->ContextLocalName(i), &mode, &init_flag); RETURN_IF_EMPTY_HANDLE_VALUE( isolate, @@ -11941,8 +11943,9 @@ static Handle GetArgumentsObject(Isolate* isolate, if (scope_info->HasHeapAllocatedLocals()) { VariableMode mode; + InitializationFlag init_flag; index = scope_info->ContextSlotIndex( - isolate->heap()->arguments_symbol(), &mode); + isolate->heap()->arguments_symbol(), &mode, &init_flag); if (index != -1) { return Handle(function_context->get(index), isolate); } diff --git a/src/scopeinfo.cc b/src/scopeinfo.cc index 16f6b3ce6..5b652e13d 100644 --- a/src/scopeinfo.cc +++ b/src/scopeinfo.cc @@ -148,10 +148,13 @@ Handle ScopeInfo::Create(Scope* scope) { scope_info->set(index++, *context_locals[i]->name()); } - // Add context locals' modes. - ASSERT(index == scope_info->ContextLocalModeEntriesIndex()); + // Add context locals' info. + ASSERT(index == scope_info->ContextLocalInfoEntriesIndex()); for (int i = 0; i < context_local_count; ++i) { - scope_info->set(index++, Smi::FromInt(context_locals[i]->mode())); + Variable* var = context_locals[i]; + uint32_t value = ContextLocalMode::encode(var->mode()) | + ContextLocalInitFlag::encode(var->initialization_flag()); + scope_info->set(index++, Smi::FromInt(value)); } // If present, add the function variable name and its index. @@ -294,8 +297,17 @@ String* ScopeInfo::ContextLocalName(int var) { VariableMode ScopeInfo::ContextLocalMode(int var) { ASSERT(0 <= var && var < ContextLocalCount()); - int info_index = ContextLocalModeEntriesIndex() + var; - return static_cast(Smi::cast(get(info_index))->value()); + int info_index = ContextLocalInfoEntriesIndex() + var; + int value = Smi::cast(get(info_index))->value(); + return ContextLocalMode::decode(value); +} + + +InitializationFlag ScopeInfo::ContextLocalInitFlag(int var) { + ASSERT(0 <= var && var < ContextLocalCount()); + int info_index = ContextLocalInfoEntriesIndex() + var; + int value = Smi::cast(get(info_index))->value(); + return ContextLocalInitFlag::decode(value); } @@ -314,12 +326,15 @@ int ScopeInfo::StackSlotIndex(String* name) { } -int ScopeInfo::ContextSlotIndex(String* name, VariableMode* mode) { +int ScopeInfo::ContextSlotIndex(String* name, + VariableMode* mode, + InitializationFlag* init_flag) { ASSERT(name->IsSymbol()); ASSERT(mode != NULL); + ASSERT(init_flag != NULL); if (length() > 0) { ContextSlotCache* context_slot_cache = GetIsolate()->context_slot_cache(); - int result = context_slot_cache->Lookup(this, name, mode); + int result = context_slot_cache->Lookup(this, name, mode, init_flag); if (result != ContextSlotCache::kNotFound) { ASSERT(result < ContextLength()); return result; @@ -331,13 +346,14 @@ int ScopeInfo::ContextSlotIndex(String* name, VariableMode* mode) { if (name == get(i)) { int var = i - start; *mode = ContextLocalMode(var); + *init_flag = ContextLocalInitFlag(var); result = Context::MIN_CONTEXT_SLOTS + var; - context_slot_cache->Update(this, name, *mode, result); + context_slot_cache->Update(this, name, *mode, *init_flag, result); ASSERT(result < ContextLength()); return result; } } - context_slot_cache->Update(this, name, INTERNAL, -1); + context_slot_cache->Update(this, name, INTERNAL, kNeedsInitialization, -1); } return -1; } @@ -393,13 +409,13 @@ int ScopeInfo::ContextLocalNameEntriesIndex() { } -int ScopeInfo::ContextLocalModeEntriesIndex() { +int ScopeInfo::ContextLocalInfoEntriesIndex() { return ContextLocalNameEntriesIndex() + ContextLocalCount(); } int ScopeInfo::FunctionNameEntryIndex() { - return ContextLocalModeEntriesIndex() + ContextLocalCount(); + return ContextLocalInfoEntriesIndex() + ContextLocalCount(); } @@ -413,12 +429,14 @@ int ContextSlotCache::Hash(Object* data, String* name) { int ContextSlotCache::Lookup(Object* data, String* name, - VariableMode* mode) { + VariableMode* mode, + InitializationFlag* init_flag) { int index = Hash(data, name); Key& key = keys_[index]; if ((key.data == data) && key.name->Equals(name)) { Value result(values_[index]); if (mode != NULL) *mode = result.mode(); + if (init_flag != NULL) *init_flag = result.initialization_flag(); return result.index() + kNotFound; } return kNotFound; @@ -428,6 +446,7 @@ int ContextSlotCache::Lookup(Object* data, void ContextSlotCache::Update(Object* data, String* name, VariableMode mode, + InitializationFlag init_flag, int slot_index) { String* symbol; ASSERT(slot_index > kNotFound); @@ -437,9 +456,9 @@ void ContextSlotCache::Update(Object* data, key.data = data; key.name = symbol; // Please note value only takes a uint as index. - values_[index] = Value(mode, slot_index - kNotFound).raw(); + values_[index] = Value(mode, init_flag, slot_index - kNotFound).raw(); #ifdef DEBUG - ValidateEntry(data, name, mode, slot_index); + ValidateEntry(data, name, mode, init_flag, slot_index); #endif } } @@ -455,6 +474,7 @@ void ContextSlotCache::Clear() { void ContextSlotCache::ValidateEntry(Object* data, String* name, VariableMode mode, + InitializationFlag init_flag, int slot_index) { String* symbol; if (HEAP->LookupSymbolIfExists(name, &symbol)) { @@ -464,6 +484,7 @@ void ContextSlotCache::ValidateEntry(Object* data, ASSERT(key.name->Equals(name)); Value result(values_[index]); ASSERT(result.mode() == mode); + ASSERT(result.initialization_flag() == init_flag); ASSERT(result.index() + kNotFound == slot_index); } } diff --git a/src/scopeinfo.h b/src/scopeinfo.h index 4c199d478..93734f5a1 100644 --- a/src/scopeinfo.h +++ b/src/scopeinfo.h @@ -45,12 +45,14 @@ class ContextSlotCache { // If absent, kNotFound is returned. int Lookup(Object* data, String* name, - VariableMode* mode); + VariableMode* mode, + InitializationFlag* init_flag); // Update an element in the cache. void Update(Object* data, String* name, VariableMode mode, + InitializationFlag init_flag, int slot_index); // Clear the cache. @@ -73,6 +75,7 @@ class ContextSlotCache { void ValidateEntry(Object* data, String* name, VariableMode mode, + InitializationFlag init_flag, int slot_index); #endif @@ -83,11 +86,17 @@ class ContextSlotCache { }; struct Value { - Value(VariableMode mode, int index) { + Value(VariableMode mode, + InitializationFlag init_flag, + int index) { ASSERT(ModeField::is_valid(mode)); + ASSERT(InitField::is_valid(init_flag)); ASSERT(IndexField::is_valid(index)); - value_ = ModeField::encode(mode) | IndexField::encode(index); + value_ = ModeField::encode(mode) | + IndexField::encode(index) | + InitField::encode(init_flag); ASSERT(mode == this->mode()); + ASSERT(init_flag == this->initialization_flag()); ASSERT(index == this->index()); } @@ -97,12 +106,18 @@ class ContextSlotCache { VariableMode mode() { return ModeField::decode(value_); } + InitializationFlag initialization_flag() { + return InitField::decode(value_); + } + int index() { return IndexField::decode(value_); } // Bit fields in value_ (type, shift, size). Must be public so the // constants can be embedded in generated code. - class ModeField: public BitField {}; - class IndexField: public BitField {}; + class ModeField: public BitField {}; + class InitField: public BitField {}; + class IndexField: public BitField {}; + private: uint32_t value_; }; diff --git a/src/scopes.cc b/src/scopes.cc index 13745f2ab..464ea4220 100644 --- a/src/scopes.cc +++ b/src/scopes.cc @@ -80,16 +80,23 @@ VariableMap::VariableMap() : HashMap(Match, &LocalsMapAllocator, 8) {} VariableMap::~VariableMap() {} -Variable* VariableMap::Declare(Scope* scope, - Handle name, - VariableMode mode, - bool is_valid_lhs, - Variable::Kind kind) { +Variable* VariableMap::Declare( + Scope* scope, + Handle name, + VariableMode mode, + bool is_valid_lhs, + Variable::Kind kind, + InitializationFlag initialization_flag) { HashMap::Entry* p = HashMap::Lookup(name.location(), name->Hash(), true); if (p->value == NULL) { // The variable has not been declared yet -> insert it. ASSERT(p->key == name.location()); - p->value = new Variable(scope, name, mode, is_valid_lhs, kind); + p->value = new Variable(scope, + name, + mode, + is_valid_lhs, + kind, + initialization_flag); } return reinterpret_cast(p->value); } @@ -162,7 +169,8 @@ Scope::Scope(Scope* inner_scope, Handle catch_variable_name) catch_variable_name, VAR, true, // Valid left-hand side. - Variable::NORMAL); + Variable::NORMAL, + kCreatedInitialized); AllocateHeapSlot(variable); } @@ -290,7 +298,8 @@ void Scope::Initialize() { isolate_->factory()->this_symbol(), VAR, false, - Variable::THIS); + Variable::THIS, + kCreatedInitialized); var->AllocateTo(Variable::PARAMETER, -1); receiver_ = var; } else { @@ -306,7 +315,8 @@ void Scope::Initialize() { isolate_->factory()->arguments_symbol(), VAR, true, - Variable::ARGUMENTS); + Variable::ARGUMENTS, + kCreatedInitialized); } } @@ -355,10 +365,12 @@ Variable* Scope::LocalLookup(Handle name) { // Check context slot lookup. VariableMode mode; - int index = scope_info_->ContextSlotIndex(*name, &mode); + InitializationFlag init_flag; + int index = scope_info_->ContextSlotIndex(*name, &mode, &init_flag); if (index < 0) { // Check parameters. mode = VAR; + init_flag = kCreatedInitialized; index = scope_info_->ParameterIndex(*name); if (index < 0) { // Check the function name. @@ -368,7 +380,12 @@ Variable* Scope::LocalLookup(Handle name) { } Variable* var = - variables_.Declare(this, name, mode, true, Variable::NORMAL); + variables_.Declare(this, + name, + mode, + true, + Variable::NORMAL, + init_flag); var->AllocateTo(Variable::CONTEXT, index); return var; } @@ -387,8 +404,8 @@ Variable* Scope::Lookup(Handle name) { Variable* Scope::DeclareFunctionVar(Handle name, VariableMode mode) { ASSERT(is_function_scope() && function_ == NULL); - Variable* function_var = - new Variable(this, name, mode, true, Variable::NORMAL); + Variable* function_var = new Variable( + this, name, mode, true, Variable::NORMAL, kCreatedInitialized); function_ = new(isolate_->zone()) VariableProxy(isolate_, function_var); return function_var; } @@ -397,13 +414,15 @@ Variable* Scope::DeclareFunctionVar(Handle name, VariableMode mode) { void Scope::DeclareParameter(Handle name, VariableMode mode) { ASSERT(!already_resolved()); ASSERT(is_function_scope()); - Variable* var = - variables_.Declare(this, name, mode, true, Variable::NORMAL); + Variable* var = variables_.Declare( + this, name, mode, true, Variable::NORMAL, kCreatedInitialized); params_.Add(var); } -Variable* Scope::DeclareLocal(Handle name, VariableMode mode) { +Variable* Scope::DeclareLocal(Handle name, + VariableMode mode, + InitializationFlag init_flag) { ASSERT(!already_resolved()); // This function handles VAR and CONST modes. DYNAMIC variables are // introduces during variable allocation, INTERNAL variables are allocated @@ -413,15 +432,19 @@ Variable* Scope::DeclareLocal(Handle name, VariableMode mode) { mode == CONST_HARMONY || mode == LET); ++num_var_or_const_; - return variables_.Declare(this, name, mode, true, Variable::NORMAL); + return + variables_.Declare(this, name, mode, true, Variable::NORMAL, init_flag); } Variable* Scope::DeclareGlobal(Handle name) { ASSERT(is_global_scope()); - return variables_.Declare(this, name, DYNAMIC_GLOBAL, + return variables_.Declare(this, + name, + DYNAMIC_GLOBAL, true, - Variable::NORMAL); + Variable::NORMAL, + kCreatedInitialized); } @@ -455,7 +478,8 @@ Variable* Scope::NewTemporary(Handle name) { name, TEMPORARY, true, - Variable::NORMAL); + Variable::NORMAL, + kCreatedInitialized); temps_.Add(var); return var; } @@ -784,7 +808,14 @@ Variable* Scope::NonLocal(Handle name, VariableMode mode) { Variable* var = map->Lookup(name); if (var == NULL) { // Declare a new non-local. - var = map->Declare(NULL, name, mode, true, Variable::NORMAL); + InitializationFlag init_flag = (mode == VAR) + ? kCreatedInitialized : kNeedsInitialization; + var = map->Declare(NULL, + name, + mode, + true, + Variable::NORMAL, + init_flag); // Allocate it by giving it a dynamic lookup. var->AllocateTo(Variable::LOOKUP, -1); } diff --git a/src/scopes.h b/src/scopes.h index c255debd5..c95def3b2 100644 --- a/src/scopes.h +++ b/src/scopes.h @@ -48,7 +48,8 @@ class VariableMap: public HashMap { Handle name, VariableMode mode, bool is_valid_lhs, - Variable::Kind kind); + Variable::Kind kind, + InitializationFlag initialization_flag); Variable* Lookup(Handle name); }; @@ -127,7 +128,9 @@ class Scope: public ZoneObject { // Declare a local variable in this scope. If the variable has been // declared before, the previously declared variable is returned. - Variable* DeclareLocal(Handle name, VariableMode mode); + Variable* DeclareLocal(Handle name, + VariableMode mode, + InitializationFlag init_flag); // Declare an implicit global variable in this scope which must be a // global scope. The variable was introduced (possibly from an inner diff --git a/src/v8globals.h b/src/v8globals.h index 7179454b4..560e36874 100644 --- a/src/v8globals.h +++ b/src/v8globals.h @@ -549,6 +549,43 @@ enum VariableMode { }; +// ES6 Draft Rev3 10.2 specifies declarative environment records with mutable +// and immutable bindings that can be in two states: initialized and +// uninitialized. In ES5 only immutable bindings have these two states. When +// accessing a binding, it needs to be checked for initialization. However in +// the following cases the binding is initialized immediately after creation +// so the initialization check can always be skipped: +// 1. Var declared local variables. +// var foo; +// 2. A local variable introduced by a function declaration. +// function foo() {} +// 3. Parameters +// function x(foo) {} +// 4. Catch bound variables. +// try {} catch (foo) {} +// 6. Function variables of named function expressions. +// var x = function foo() {} +// 7. Implicit binding of 'this'. +// 8. Implicit binding of 'arguments' in functions. +// +// ES5 specified object environment records which are introduced by ES elements +// such as Program and WithStatement that associate identifier bindings with the +// properties of some object. In the specification only mutable bindings exist +// (which may be non-writable) and have no distinct initialization step. However +// V8 allows const declarations in global code with distinct creation and +// initialization steps which are represented by non-writable properties in the +// global object. As a result also these bindings need to be checked for +// initialization. +// +// The following enum specifies a flag that indicates if the binding needs a +// distinct initialization step (kNeedsInitialization) or if the binding is +// immediately initialized upon creation (kCreatedInitialized). +enum InitializationFlag { + kNeedsInitialization, + kCreatedInitialized +}; + + enum ClearExceptionFlag { KEEP_EXCEPTION, CLEAR_EXCEPTION diff --git a/src/variables.cc b/src/variables.cc index d85e1b270..2e52a728a 100644 --- a/src/variables.cc +++ b/src/variables.cc @@ -58,7 +58,8 @@ Variable::Variable(Scope* scope, Handle name, VariableMode mode, bool is_valid_LHS, - Kind kind) + Kind kind, + InitializationFlag initialization_flag) : scope_(scope), name_(name), mode_(mode), @@ -68,9 +69,12 @@ Variable::Variable(Scope* scope, local_if_not_shadowed_(NULL), is_valid_LHS_(is_valid_LHS), is_accessed_from_inner_scope_(false), - is_used_(false) { - // names must be canonicalized for fast equality checks + is_used_(false), + initialization_flag_(initialization_flag) { + // Names must be canonicalized for fast equality checks. ASSERT(name->IsSymbol()); + // Var declared variables never need initialization. + ASSERT(!(mode == VAR && initialization_flag == kNeedsInitialization)); } diff --git a/src/variables.h b/src/variables.h index e23e00bd3..be897a6ff 100644 --- a/src/variables.h +++ b/src/variables.h @@ -77,7 +77,8 @@ class Variable: public ZoneObject { Handle name, VariableMode mode, bool is_valid_lhs, - Kind kind); + Kind kind, + InitializationFlag initialization_flag); // Printing support static const char* Mode2String(VariableMode mode); @@ -123,9 +124,7 @@ class Variable: public ZoneObject { mode_ == CONST_HARMONY); } bool binding_needs_init() const { - return (mode_ == LET || - mode_ == CONST || - mode_ == CONST_HARMONY); + return initialization_flag_ == kNeedsInitialization; } bool is_global() const; @@ -148,6 +147,9 @@ class Variable: public ZoneObject { Location location() const { return location_; } int index() const { return index_; } + InitializationFlag initialization_flag() const { + return initialization_flag_; + } void AllocateTo(Location location, int index) { location_ = location; @@ -174,6 +176,7 @@ class Variable: public ZoneObject { // Usage info. bool is_accessed_from_inner_scope_; // set by variable resolver bool is_used_; + InitializationFlag initialization_flag_; }; diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc index e8fdef21f..a80a8b792 100644 --- a/src/x64/full-codegen-x64.cc +++ b/src/x64/full-codegen-x64.cc @@ -676,8 +676,8 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, // need to "declare" it at runtime to make sure it actually exists in the // local context. Variable* variable = proxy->var(); - bool binding_needs_init = - mode == CONST || mode == CONST_HARMONY || mode == LET; + bool binding_needs_init = (function == NULL) && + (mode == CONST || mode == CONST_HARMONY || mode == LET); switch (variable->location()) { case Variable::UNALLOCATED: ++(*global_count);