Remove some unnecessary binding initialization checks.
authorkeuchel@chromium.org <keuchel@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 3 Nov 2011 11:59:51 +0000 (11:59 +0000)
committerkeuchel@chromium.org <keuchel@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 3 Nov 2011 11:59:51 +0000 (11:59 +0000)
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

15 files changed:
src/arm/full-codegen-arm.cc
src/contexts.cc
src/ia32/full-codegen-ia32.cc
src/mips/full-codegen-mips.cc
src/objects.h
src/parser.cc
src/runtime.cc
src/scopeinfo.cc
src/scopeinfo.h
src/scopes.cc
src/scopes.h
src/v8globals.h
src/variables.cc
src/variables.h
src/x64/full-codegen-x64.cc

index d0c663b4081d77fd0a191727e9ff075dba49cedb..adc1b26c6f8f35c64e2455549f2e99dd3d2eca34 100644 (file)
@@ -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);
index 0e7ef5f607f8ec81c8ca8a05b2ff8d0e5d3add12..aee963b2bc33511054b6bc09b2c71bfbde9b2f45 100644 (file)
@@ -146,7 +146,8 @@ Handle<Object> Context::Lookup(Handle<String> 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<Object> Context::Lookup(Handle<String> 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<String> name) {
     // Check non-parameter locals.
     Handle<ScopeInfo> 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;
 
index 0af30f079fbb7935f94d7f24789df12370c3ee3c..e8108fc7cb3aa2d4f151482aff1f3a52578bf682 100644 (file)
@@ -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);
index 5bb9b3598ba234716cc1486f087b74d304d0e5d0..53e39c1fb7bb51416984af41c5d259e960d0b316 100644 (file)
@@ -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);
index 1805f63dc59fb9309fcd8d8db0062764330e346e..03ed0b3885c97d826ea92d2ce1e3d7e68bd053a6 100644 (file)
@@ -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<bool,                 4, 1> {};
   class FunctionVariableField: public BitField<FunctionVariableInfo, 5, 2> {};
   class FunctionVariableMode:  public BitField<VariableMode,         7, 3> {};
+
+  // BitFields representing the encoded information for context locals in the
+  // ContextLocalInfoEntries part.
+  class ContextLocalMode:      public BitField<VariableMode,         0, 3> {};
+  class ContextLocalInitFlag:  public BitField<InitializationFlag,   3, 1> {};
 };
 
 
index 21acb83c6c258d0b5a9d114478dbf42719bc9f88..3e85c7a6ab4e32fc2b0a178859a1eb42468e319c 100644 (file)
@@ -1385,7 +1385,9 @@ VariableProxy* Parser::Declare(Handle<String> 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<String> 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);
index f15fbba37ea92c683f66c3a4908a53044fdb87aa..ef8ff83476fd2164d39610e64bf2058c1a9fd6ff 100644 (file)
@@ -10794,9 +10794,10 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
     for (; i < scope_info->LocalCount(); ++i) {
       Handle<String> 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<Object> 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<Object>(function_context->get(index), isolate);
     }
index 16f6b3ce68739467401b1f6e2a03a22e2489682d..5b652e13d4d102f6c6ec99d7b0690d7b1078ff47 100644 (file)
@@ -148,10 +148,13 @@ Handle<ScopeInfo> 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<VariableMode>(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);
   }
 }
index 4c199d4785946bf1f402b79862ec4fb610cfb32b..93734f5a16c2b4842915cc83b46a0c8a77f25eb3 100644 (file)
@@ -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<VariableMode, 0, 3> {};
-    class IndexField: public BitField<int,          3, 32-3> {};
+    class ModeField:  public BitField<VariableMode,       0, 3> {};
+    class InitField:  public BitField<InitializationFlag, 3, 1> {};
+    class IndexField: public BitField<int,                4, 32-4> {};
+
    private:
     uint32_t value_;
   };
index 13745f2abdef37cf1ebdc500914007e2038226e8..464ea42206880f8b2ff5d6315211a5318c6c79f8 100644 (file)
@@ -80,16 +80,23 @@ VariableMap::VariableMap() : HashMap(Match, &LocalsMapAllocator, 8) {}
 VariableMap::~VariableMap() {}
 
 
-Variable* VariableMap::Declare(Scope* scope,
-                               Handle<String> name,
-                               VariableMode mode,
-                               bool is_valid_lhs,
-                               Variable::Kind kind) {
+Variable* VariableMap::Declare(
+    Scope* scope,
+    Handle<String> 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<Variable*>(p->value);
 }
@@ -162,7 +169,8 @@ Scope::Scope(Scope* inner_scope, Handle<String> 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<String> 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<String> 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<String> name) {
 
 Variable* Scope::DeclareFunctionVar(Handle<String> 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<String> name, VariableMode mode) {
 void Scope::DeclareParameter(Handle<String> 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<String> name, VariableMode mode) {
+Variable* Scope::DeclareLocal(Handle<String> 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<String> 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<String> 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<String> name) {
                                name,
                                TEMPORARY,
                                true,
-                               Variable::NORMAL);
+                               Variable::NORMAL,
+                               kCreatedInitialized);
   temps_.Add(var);
   return var;
 }
@@ -784,7 +808,14 @@ Variable* Scope::NonLocal(Handle<String> 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);
   }
index c255debd5ad451c9a80220931c71188f742c39d4..c95def3b294eedba6a857324507f6efb30fcd0d0 100644 (file)
@@ -48,7 +48,8 @@ class VariableMap: public HashMap {
                     Handle<String> name,
                     VariableMode mode,
                     bool is_valid_lhs,
-                    Variable::Kind kind);
+                    Variable::Kind kind,
+                    InitializationFlag initialization_flag);
 
   Variable* Lookup(Handle<String> 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<String> name, VariableMode mode);
+  Variable* DeclareLocal(Handle<String> 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
index 7179454b43cefa9ed45b3ffc473cd40f87202787..560e36874c19102bb8a8be9343efe28d561820f1 100644 (file)
@@ -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
index d85e1b270ab30d452a3db4f84811a73458521c3b..2e52a728adcc40c4814ffa3b91070c61ef3bac60 100644 (file)
@@ -58,7 +58,8 @@ Variable::Variable(Scope* scope,
                    Handle<String> 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));
 }
 
 
index e23e00bd38081da8a1805955230859e52644615f..be897a6ff5e87de3acf7c58e9954468990edc0f6 100644 (file)
@@ -77,7 +77,8 @@ class Variable: public ZoneObject {
            Handle<String> 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_;
 };
 
 
index e8fdef21f95f396beaec1e556cf4518c047da4aa..a80a8b792e8dd8fe66d17c9846472bf15aad7e60 100644 (file)
@@ -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);