Home | History | Annotate | Download | only in ast
      1 // Copyright 2011 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "src/ast/scopeinfo.h"
      6 
      7 #include <stdlib.h>
      8 
      9 #include "src/ast/scopes.h"
     10 #include "src/bootstrapper.h"
     11 
     12 namespace v8 {
     13 namespace internal {
     14 
     15 
     16 Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate, Zone* zone,
     17                                     Scope* scope) {
     18   // Collect stack and context locals.
     19   ZoneList<Variable*> stack_locals(scope->StackLocalCount(), zone);
     20   ZoneList<Variable*> context_locals(scope->ContextLocalCount(), zone);
     21   ZoneList<Variable*> context_globals(scope->ContextGlobalCount(), zone);
     22 
     23   scope->CollectStackAndContextLocals(&stack_locals, &context_locals,
     24                                       &context_globals);
     25   const int stack_local_count = stack_locals.length();
     26   const int context_local_count = context_locals.length();
     27   const int context_global_count = context_globals.length();
     28   // Make sure we allocate the correct amount.
     29   DCHECK_EQ(scope->ContextLocalCount(), context_local_count);
     30   DCHECK_EQ(scope->ContextGlobalCount(), context_global_count);
     31 
     32   // Determine use and location of the "this" binding if it is present.
     33   VariableAllocationInfo receiver_info;
     34   if (scope->has_this_declaration()) {
     35     Variable* var = scope->receiver();
     36     if (!var->is_used()) {
     37       receiver_info = UNUSED;
     38     } else if (var->IsContextSlot()) {
     39       receiver_info = CONTEXT;
     40     } else {
     41       DCHECK(var->IsParameter());
     42       receiver_info = STACK;
     43     }
     44   } else {
     45     receiver_info = NONE;
     46   }
     47 
     48   bool has_new_target = scope->new_target_var() != nullptr;
     49 
     50   // Determine use and location of the function variable if it is present.
     51   VariableAllocationInfo function_name_info;
     52   VariableMode function_variable_mode;
     53   if (scope->is_function_scope() && scope->function() != NULL) {
     54     Variable* var = scope->function()->proxy()->var();
     55     if (!var->is_used()) {
     56       function_name_info = UNUSED;
     57     } else if (var->IsContextSlot()) {
     58       function_name_info = CONTEXT;
     59     } else {
     60       DCHECK(var->IsStackLocal());
     61       function_name_info = STACK;
     62     }
     63     function_variable_mode = var->mode();
     64   } else {
     65     function_name_info = NONE;
     66     function_variable_mode = VAR;
     67   }
     68   DCHECK(context_global_count == 0 || scope->scope_type() == SCRIPT_SCOPE);
     69 
     70   const bool has_function_name = function_name_info != NONE;
     71   const bool has_receiver = receiver_info == STACK || receiver_info == CONTEXT;
     72   const int parameter_count = scope->num_parameters();
     73   const int length = kVariablePartIndex + parameter_count +
     74                      (1 + stack_local_count) + 2 * context_local_count +
     75                      2 * context_global_count +
     76                      (has_receiver ? 1 : 0) + (has_function_name ? 2 : 0);
     77 
     78   Factory* factory = isolate->factory();
     79   Handle<ScopeInfo> scope_info = factory->NewScopeInfo(length);
     80 
     81   bool has_simple_parameters =
     82       scope->is_function_scope() && scope->has_simple_parameters();
     83 
     84   // Encode the flags.
     85   int flags = ScopeTypeField::encode(scope->scope_type()) |
     86               CallsEvalField::encode(scope->calls_eval()) |
     87               LanguageModeField::encode(scope->language_mode()) |
     88               DeclarationScopeField::encode(scope->is_declaration_scope()) |
     89               ReceiverVariableField::encode(receiver_info) |
     90               HasNewTargetField::encode(has_new_target) |
     91               FunctionVariableField::encode(function_name_info) |
     92               FunctionVariableMode::encode(function_variable_mode) |
     93               AsmModuleField::encode(scope->asm_module()) |
     94               AsmFunctionField::encode(scope->asm_function()) |
     95               HasSimpleParametersField::encode(has_simple_parameters) |
     96               FunctionKindField::encode(scope->function_kind());
     97   scope_info->SetFlags(flags);
     98   scope_info->SetParameterCount(parameter_count);
     99   scope_info->SetStackLocalCount(stack_local_count);
    100   scope_info->SetContextLocalCount(context_local_count);
    101   scope_info->SetContextGlobalCount(context_global_count);
    102 
    103   int index = kVariablePartIndex;
    104   // Add parameters.
    105   DCHECK(index == scope_info->ParameterEntriesIndex());
    106   for (int i = 0; i < parameter_count; ++i) {
    107     scope_info->set(index++, *scope->parameter(i)->name());
    108   }
    109 
    110   // Add stack locals' names. We are assuming that the stack locals'
    111   // slots are allocated in increasing order, so we can simply add
    112   // them to the ScopeInfo object.
    113   int first_slot_index;
    114   if (stack_local_count > 0) {
    115     first_slot_index = stack_locals[0]->index();
    116   } else {
    117     first_slot_index = 0;
    118   }
    119   DCHECK(index == scope_info->StackLocalFirstSlotIndex());
    120   scope_info->set(index++, Smi::FromInt(first_slot_index));
    121   DCHECK(index == scope_info->StackLocalEntriesIndex());
    122   for (int i = 0; i < stack_local_count; ++i) {
    123     DCHECK(stack_locals[i]->index() == first_slot_index + i);
    124     scope_info->set(index++, *stack_locals[i]->name());
    125   }
    126 
    127   // Due to usage analysis, context-allocated locals are not necessarily in
    128   // increasing order: Some of them may be parameters which are allocated before
    129   // the non-parameter locals. When the non-parameter locals are sorted
    130   // according to usage, the allocated slot indices may not be in increasing
    131   // order with the variable list anymore. Thus, we first need to sort them by
    132   // context slot index before adding them to the ScopeInfo object.
    133   context_locals.Sort(&Variable::CompareIndex);
    134 
    135   // Add context locals' names.
    136   DCHECK(index == scope_info->ContextLocalNameEntriesIndex());
    137   for (int i = 0; i < context_local_count; ++i) {
    138     scope_info->set(index++, *context_locals[i]->name());
    139   }
    140 
    141   // Add context globals' names.
    142   DCHECK(index == scope_info->ContextGlobalNameEntriesIndex());
    143   for (int i = 0; i < context_global_count; ++i) {
    144     scope_info->set(index++, *context_globals[i]->name());
    145   }
    146 
    147   // Add context locals' info.
    148   DCHECK(index == scope_info->ContextLocalInfoEntriesIndex());
    149   for (int i = 0; i < context_local_count; ++i) {
    150     Variable* var = context_locals[i];
    151     uint32_t value =
    152         ContextLocalMode::encode(var->mode()) |
    153         ContextLocalInitFlag::encode(var->initialization_flag()) |
    154         ContextLocalMaybeAssignedFlag::encode(var->maybe_assigned());
    155     scope_info->set(index++, Smi::FromInt(value));
    156   }
    157 
    158   // Add context globals' info.
    159   DCHECK(index == scope_info->ContextGlobalInfoEntriesIndex());
    160   for (int i = 0; i < context_global_count; ++i) {
    161     Variable* var = context_globals[i];
    162     // TODO(ishell): do we need this kind of info for globals here?
    163     uint32_t value =
    164         ContextLocalMode::encode(var->mode()) |
    165         ContextLocalInitFlag::encode(var->initialization_flag()) |
    166         ContextLocalMaybeAssignedFlag::encode(var->maybe_assigned());
    167     scope_info->set(index++, Smi::FromInt(value));
    168   }
    169 
    170   // If the receiver is allocated, add its index.
    171   DCHECK(index == scope_info->ReceiverEntryIndex());
    172   if (has_receiver) {
    173     int var_index = scope->receiver()->index();
    174     scope_info->set(index++, Smi::FromInt(var_index));
    175     // ?? DCHECK(receiver_info != CONTEXT || var_index ==
    176     // scope_info->ContextLength() - 1);
    177   }
    178 
    179   // If present, add the function variable name and its index.
    180   DCHECK(index == scope_info->FunctionNameEntryIndex());
    181   if (has_function_name) {
    182     int var_index = scope->function()->proxy()->var()->index();
    183     scope_info->set(index++, *scope->function()->proxy()->name());
    184     scope_info->set(index++, Smi::FromInt(var_index));
    185     DCHECK(function_name_info != CONTEXT ||
    186            var_index == scope_info->ContextLength() - 1);
    187   }
    188 
    189   DCHECK(index == scope_info->length());
    190   DCHECK(scope->num_parameters() == scope_info->ParameterCount());
    191   DCHECK(scope->num_heap_slots() == scope_info->ContextLength() ||
    192          (scope->num_heap_slots() == kVariablePartIndex &&
    193           scope_info->ContextLength() == 0));
    194   return scope_info;
    195 }
    196 
    197 
    198 Handle<ScopeInfo> ScopeInfo::CreateGlobalThisBinding(Isolate* isolate) {
    199   DCHECK(isolate->bootstrapper()->IsActive());
    200 
    201   const int stack_local_count = 0;
    202   const int context_local_count = 1;
    203   const int context_global_count = 0;
    204   const bool has_simple_parameters = true;
    205   const VariableAllocationInfo receiver_info = CONTEXT;
    206   const VariableAllocationInfo function_name_info = NONE;
    207   const VariableMode function_variable_mode = VAR;
    208   const bool has_function_name = false;
    209   const bool has_receiver = true;
    210   const int parameter_count = 0;
    211   const int length = kVariablePartIndex + parameter_count +
    212                      (1 + stack_local_count) + 2 * context_local_count +
    213                      2 * context_global_count +
    214                      (has_receiver ? 1 : 0) + (has_function_name ? 2 : 0);
    215 
    216   Factory* factory = isolate->factory();
    217   Handle<ScopeInfo> scope_info = factory->NewScopeInfo(length);
    218 
    219   // Encode the flags.
    220   int flags = ScopeTypeField::encode(SCRIPT_SCOPE) |
    221               CallsEvalField::encode(false) |
    222               LanguageModeField::encode(SLOPPY) |
    223               DeclarationScopeField::encode(true) |
    224               ReceiverVariableField::encode(receiver_info) |
    225               FunctionVariableField::encode(function_name_info) |
    226               FunctionVariableMode::encode(function_variable_mode) |
    227               AsmModuleField::encode(false) | AsmFunctionField::encode(false) |
    228               HasSimpleParametersField::encode(has_simple_parameters) |
    229               FunctionKindField::encode(FunctionKind::kNormalFunction);
    230   scope_info->SetFlags(flags);
    231   scope_info->SetParameterCount(parameter_count);
    232   scope_info->SetStackLocalCount(stack_local_count);
    233   scope_info->SetContextLocalCount(context_local_count);
    234   scope_info->SetContextGlobalCount(context_global_count);
    235 
    236   int index = kVariablePartIndex;
    237   const int first_slot_index = 0;
    238   DCHECK(index == scope_info->StackLocalFirstSlotIndex());
    239   scope_info->set(index++, Smi::FromInt(first_slot_index));
    240   DCHECK(index == scope_info->StackLocalEntriesIndex());
    241 
    242   // Here we add info for context-allocated "this".
    243   DCHECK(index == scope_info->ContextLocalNameEntriesIndex());
    244   scope_info->set(index++, *isolate->factory()->this_string());
    245   DCHECK(index == scope_info->ContextLocalInfoEntriesIndex());
    246   const uint32_t value = ContextLocalMode::encode(CONST) |
    247                          ContextLocalInitFlag::encode(kCreatedInitialized) |
    248                          ContextLocalMaybeAssignedFlag::encode(kNotAssigned);
    249   scope_info->set(index++, Smi::FromInt(value));
    250 
    251   // And here we record that this scopeinfo binds a receiver.
    252   DCHECK(index == scope_info->ReceiverEntryIndex());
    253   const int receiver_index = Context::MIN_CONTEXT_SLOTS + 0;
    254   scope_info->set(index++, Smi::FromInt(receiver_index));
    255 
    256   DCHECK(index == scope_info->FunctionNameEntryIndex());
    257 
    258   DCHECK_EQ(index, scope_info->length());
    259   DCHECK_EQ(scope_info->ParameterCount(), 0);
    260   DCHECK_EQ(scope_info->ContextLength(), Context::MIN_CONTEXT_SLOTS + 1);
    261 
    262   return scope_info;
    263 }
    264 
    265 
    266 ScopeInfo* ScopeInfo::Empty(Isolate* isolate) {
    267   return reinterpret_cast<ScopeInfo*>(isolate->heap()->empty_fixed_array());
    268 }
    269 
    270 
    271 ScopeType ScopeInfo::scope_type() {
    272   DCHECK(length() > 0);
    273   return ScopeTypeField::decode(Flags());
    274 }
    275 
    276 
    277 bool ScopeInfo::CallsEval() {
    278   return length() > 0 && CallsEvalField::decode(Flags());
    279 }
    280 
    281 
    282 LanguageMode ScopeInfo::language_mode() {
    283   return length() > 0 ? LanguageModeField::decode(Flags()) : SLOPPY;
    284 }
    285 
    286 
    287 bool ScopeInfo::is_declaration_scope() {
    288   return DeclarationScopeField::decode(Flags());
    289 }
    290 
    291 
    292 int ScopeInfo::LocalCount() {
    293   return StackLocalCount() + ContextLocalCount();
    294 }
    295 
    296 
    297 int ScopeInfo::StackSlotCount() {
    298   if (length() > 0) {
    299     bool function_name_stack_slot =
    300         FunctionVariableField::decode(Flags()) == STACK;
    301     return StackLocalCount() + (function_name_stack_slot ? 1 : 0);
    302   }
    303   return 0;
    304 }
    305 
    306 
    307 int ScopeInfo::ContextLength() {
    308   if (length() > 0) {
    309     int context_locals = ContextLocalCount();
    310     int context_globals = ContextGlobalCount();
    311     bool function_name_context_slot =
    312         FunctionVariableField::decode(Flags()) == CONTEXT;
    313     bool has_context = context_locals > 0 || context_globals > 0 ||
    314                        function_name_context_slot ||
    315                        scope_type() == WITH_SCOPE ||
    316                        (scope_type() == BLOCK_SCOPE && CallsSloppyEval() &&
    317                            is_declaration_scope()) ||
    318                        (scope_type() == FUNCTION_SCOPE && CallsSloppyEval()) ||
    319                        scope_type() == MODULE_SCOPE;
    320 
    321     if (has_context) {
    322       return Context::MIN_CONTEXT_SLOTS + context_locals + context_globals +
    323              (function_name_context_slot ? 1 : 0);
    324     }
    325   }
    326   return 0;
    327 }
    328 
    329 
    330 bool ScopeInfo::HasReceiver() {
    331   if (length() > 0) {
    332     return NONE != ReceiverVariableField::decode(Flags());
    333   } else {
    334     return false;
    335   }
    336 }
    337 
    338 
    339 bool ScopeInfo::HasAllocatedReceiver() {
    340   if (length() > 0) {
    341     VariableAllocationInfo allocation = ReceiverVariableField::decode(Flags());
    342     return allocation == STACK || allocation == CONTEXT;
    343   } else {
    344     return false;
    345   }
    346 }
    347 
    348 
    349 bool ScopeInfo::HasNewTarget() { return HasNewTargetField::decode(Flags()); }
    350 
    351 
    352 bool ScopeInfo::HasFunctionName() {
    353   if (length() > 0) {
    354     return NONE != FunctionVariableField::decode(Flags());
    355   } else {
    356     return false;
    357   }
    358 }
    359 
    360 
    361 bool ScopeInfo::HasHeapAllocatedLocals() {
    362   if (length() > 0) {
    363     return ContextLocalCount() > 0;
    364   } else {
    365     return false;
    366   }
    367 }
    368 
    369 
    370 bool ScopeInfo::HasContext() {
    371   return ContextLength() > 0;
    372 }
    373 
    374 
    375 String* ScopeInfo::FunctionName() {
    376   DCHECK(HasFunctionName());
    377   return String::cast(get(FunctionNameEntryIndex()));
    378 }
    379 
    380 
    381 String* ScopeInfo::ParameterName(int var) {
    382   DCHECK(0 <= var && var < ParameterCount());
    383   int info_index = ParameterEntriesIndex() + var;
    384   return String::cast(get(info_index));
    385 }
    386 
    387 
    388 String* ScopeInfo::LocalName(int var) {
    389   DCHECK(0 <= var && var < LocalCount());
    390   DCHECK(StackLocalEntriesIndex() + StackLocalCount() ==
    391          ContextLocalNameEntriesIndex());
    392   int info_index = StackLocalEntriesIndex() + var;
    393   return String::cast(get(info_index));
    394 }
    395 
    396 
    397 String* ScopeInfo::StackLocalName(int var) {
    398   DCHECK(0 <= var && var < StackLocalCount());
    399   int info_index = StackLocalEntriesIndex() + var;
    400   return String::cast(get(info_index));
    401 }
    402 
    403 
    404 int ScopeInfo::StackLocalIndex(int var) {
    405   DCHECK(0 <= var && var < StackLocalCount());
    406   int first_slot_index = Smi::cast(get(StackLocalFirstSlotIndex()))->value();
    407   return first_slot_index + var;
    408 }
    409 
    410 
    411 String* ScopeInfo::ContextLocalName(int var) {
    412   DCHECK(0 <= var && var < ContextLocalCount() + ContextGlobalCount());
    413   int info_index = ContextLocalNameEntriesIndex() + var;
    414   return String::cast(get(info_index));
    415 }
    416 
    417 
    418 VariableMode ScopeInfo::ContextLocalMode(int var) {
    419   DCHECK(0 <= var && var < ContextLocalCount() + ContextGlobalCount());
    420   int info_index = ContextLocalInfoEntriesIndex() + var;
    421   int value = Smi::cast(get(info_index))->value();
    422   return ContextLocalMode::decode(value);
    423 }
    424 
    425 
    426 InitializationFlag ScopeInfo::ContextLocalInitFlag(int var) {
    427   DCHECK(0 <= var && var < ContextLocalCount() + ContextGlobalCount());
    428   int info_index = ContextLocalInfoEntriesIndex() + var;
    429   int value = Smi::cast(get(info_index))->value();
    430   return ContextLocalInitFlag::decode(value);
    431 }
    432 
    433 
    434 MaybeAssignedFlag ScopeInfo::ContextLocalMaybeAssignedFlag(int var) {
    435   DCHECK(0 <= var && var < ContextLocalCount() + ContextGlobalCount());
    436   int info_index = ContextLocalInfoEntriesIndex() + var;
    437   int value = Smi::cast(get(info_index))->value();
    438   return ContextLocalMaybeAssignedFlag::decode(value);
    439 }
    440 
    441 bool ScopeInfo::VariableIsSynthetic(String* name) {
    442   // There's currently no flag stored on the ScopeInfo to indicate that a
    443   // variable is a compiler-introduced temporary. However, to avoid conflict
    444   // with user declarations, the current temporaries like .generator_object and
    445   // .result start with a dot, so we can use that as a flag. It's a hack!
    446   return name->length() == 0 || name->Get(0) == '.' ||
    447          name->Equals(name->GetHeap()->this_string());
    448 }
    449 
    450 
    451 int ScopeInfo::StackSlotIndex(String* name) {
    452   DCHECK(name->IsInternalizedString());
    453   if (length() > 0) {
    454     int first_slot_index = Smi::cast(get(StackLocalFirstSlotIndex()))->value();
    455     int start = StackLocalEntriesIndex();
    456     int end = StackLocalEntriesIndex() + StackLocalCount();
    457     for (int i = start; i < end; ++i) {
    458       if (name == get(i)) {
    459         return i - start + first_slot_index;
    460       }
    461     }
    462   }
    463   return -1;
    464 }
    465 
    466 
    467 int ScopeInfo::ContextSlotIndex(Handle<ScopeInfo> scope_info,
    468                                 Handle<String> name, VariableMode* mode,
    469                                 InitializationFlag* init_flag,
    470                                 MaybeAssignedFlag* maybe_assigned_flag) {
    471   DCHECK(name->IsInternalizedString());
    472   DCHECK(mode != NULL);
    473   DCHECK(init_flag != NULL);
    474   if (scope_info->length() > 0) {
    475     ContextSlotCache* context_slot_cache =
    476         scope_info->GetIsolate()->context_slot_cache();
    477     int result = context_slot_cache->Lookup(*scope_info, *name, mode, init_flag,
    478                                             maybe_assigned_flag);
    479     if (result != ContextSlotCache::kNotFound) {
    480       DCHECK(result < scope_info->ContextLength());
    481       return result;
    482     }
    483 
    484     int start = scope_info->ContextLocalNameEntriesIndex();
    485     int end = scope_info->ContextLocalNameEntriesIndex() +
    486               scope_info->ContextLocalCount();
    487     for (int i = start; i < end; ++i) {
    488       if (*name == scope_info->get(i)) {
    489         int var = i - start;
    490         *mode = scope_info->ContextLocalMode(var);
    491         *init_flag = scope_info->ContextLocalInitFlag(var);
    492         *maybe_assigned_flag = scope_info->ContextLocalMaybeAssignedFlag(var);
    493         result = Context::MIN_CONTEXT_SLOTS + var;
    494 
    495         context_slot_cache->Update(scope_info, name, *mode, *init_flag,
    496                                    *maybe_assigned_flag, result);
    497         DCHECK(result < scope_info->ContextLength());
    498         return result;
    499       }
    500     }
    501     // Cache as not found. Mode, init flag and maybe assigned flag don't matter.
    502     context_slot_cache->Update(scope_info, name, TEMPORARY,
    503                                kNeedsInitialization, kNotAssigned, -1);
    504   }
    505   return -1;
    506 }
    507 
    508 
    509 int ScopeInfo::ContextGlobalSlotIndex(Handle<ScopeInfo> scope_info,
    510                                       Handle<String> name, VariableMode* mode,
    511                                       InitializationFlag* init_flag,
    512                                       MaybeAssignedFlag* maybe_assigned_flag) {
    513   DCHECK(name->IsInternalizedString());
    514   DCHECK(mode != NULL);
    515   DCHECK(init_flag != NULL);
    516   if (scope_info->length() > 0) {
    517     // This is to ensure that ContextLocalMode() and co. queries would work.
    518     DCHECK_EQ(scope_info->ContextGlobalNameEntriesIndex(),
    519               scope_info->ContextLocalNameEntriesIndex() +
    520                   scope_info->ContextLocalCount());
    521     int base = scope_info->ContextLocalNameEntriesIndex();
    522     int start = scope_info->ContextGlobalNameEntriesIndex();
    523     int end = scope_info->ContextGlobalNameEntriesIndex() +
    524               scope_info->ContextGlobalCount();
    525     for (int i = start; i < end; ++i) {
    526       if (*name == scope_info->get(i)) {
    527         int var = i - base;
    528         *mode = scope_info->ContextLocalMode(var);
    529         *init_flag = scope_info->ContextLocalInitFlag(var);
    530         *maybe_assigned_flag = scope_info->ContextLocalMaybeAssignedFlag(var);
    531         int result = Context::MIN_CONTEXT_SLOTS + var;
    532         DCHECK(result < scope_info->ContextLength());
    533         return result;
    534       }
    535     }
    536   }
    537   return -1;
    538 }
    539 
    540 
    541 String* ScopeInfo::ContextSlotName(int slot_index) {
    542   int const var = slot_index - Context::MIN_CONTEXT_SLOTS;
    543   DCHECK_LE(0, var);
    544   DCHECK_LT(var, ContextLocalCount() + ContextGlobalCount());
    545   return ContextLocalName(var);
    546 }
    547 
    548 
    549 int ScopeInfo::ParameterIndex(String* name) {
    550   DCHECK(name->IsInternalizedString());
    551   if (length() > 0) {
    552     // We must read parameters from the end since for
    553     // multiply declared parameters the value of the
    554     // last declaration of that parameter is used
    555     // inside a function (and thus we need to look
    556     // at the last index). Was bug# 1110337.
    557     int start = ParameterEntriesIndex();
    558     int end = ParameterEntriesIndex() + ParameterCount();
    559     for (int i = end - 1; i >= start; --i) {
    560       if (name == get(i)) {
    561         return i - start;
    562       }
    563     }
    564   }
    565   return -1;
    566 }
    567 
    568 
    569 int ScopeInfo::ReceiverContextSlotIndex() {
    570   if (length() > 0 && ReceiverVariableField::decode(Flags()) == CONTEXT)
    571     return Smi::cast(get(ReceiverEntryIndex()))->value();
    572   return -1;
    573 }
    574 
    575 
    576 int ScopeInfo::FunctionContextSlotIndex(String* name, VariableMode* mode) {
    577   DCHECK(name->IsInternalizedString());
    578   DCHECK(mode != NULL);
    579   if (length() > 0) {
    580     if (FunctionVariableField::decode(Flags()) == CONTEXT &&
    581         FunctionName() == name) {
    582       *mode = FunctionVariableMode::decode(Flags());
    583       return Smi::cast(get(FunctionNameEntryIndex() + 1))->value();
    584     }
    585   }
    586   return -1;
    587 }
    588 
    589 
    590 FunctionKind ScopeInfo::function_kind() {
    591   return FunctionKindField::decode(Flags());
    592 }
    593 
    594 
    595 int ScopeInfo::ParameterEntriesIndex() {
    596   DCHECK(length() > 0);
    597   return kVariablePartIndex;
    598 }
    599 
    600 
    601 int ScopeInfo::StackLocalFirstSlotIndex() {
    602   return ParameterEntriesIndex() + ParameterCount();
    603 }
    604 
    605 
    606 int ScopeInfo::StackLocalEntriesIndex() {
    607   return StackLocalFirstSlotIndex() + 1;
    608 }
    609 
    610 
    611 int ScopeInfo::ContextLocalNameEntriesIndex() {
    612   return StackLocalEntriesIndex() + StackLocalCount();
    613 }
    614 
    615 
    616 int ScopeInfo::ContextGlobalNameEntriesIndex() {
    617   return ContextLocalNameEntriesIndex() + ContextLocalCount();
    618 }
    619 
    620 
    621 int ScopeInfo::ContextLocalInfoEntriesIndex() {
    622   return ContextGlobalNameEntriesIndex() + ContextGlobalCount();
    623 }
    624 
    625 
    626 int ScopeInfo::ContextGlobalInfoEntriesIndex() {
    627   return ContextLocalInfoEntriesIndex() + ContextLocalCount();
    628 }
    629 
    630 
    631 int ScopeInfo::ReceiverEntryIndex() {
    632   return ContextGlobalInfoEntriesIndex() + ContextGlobalCount();
    633 }
    634 
    635 
    636 int ScopeInfo::FunctionNameEntryIndex() {
    637   return ReceiverEntryIndex() + (HasAllocatedReceiver() ? 1 : 0);
    638 }
    639 
    640 
    641 int ContextSlotCache::Hash(Object* data, String* name) {
    642   // Uses only lower 32 bits if pointers are larger.
    643   uintptr_t addr_hash =
    644       static_cast<uint32_t>(reinterpret_cast<uintptr_t>(data)) >> 2;
    645   return static_cast<int>((addr_hash ^ name->Hash()) % kLength);
    646 }
    647 
    648 
    649 int ContextSlotCache::Lookup(Object* data, String* name, VariableMode* mode,
    650                              InitializationFlag* init_flag,
    651                              MaybeAssignedFlag* maybe_assigned_flag) {
    652   int index = Hash(data, name);
    653   Key& key = keys_[index];
    654   if ((key.data == data) && key.name->Equals(name)) {
    655     Value result(values_[index]);
    656     if (mode != NULL) *mode = result.mode();
    657     if (init_flag != NULL) *init_flag = result.initialization_flag();
    658     if (maybe_assigned_flag != NULL)
    659       *maybe_assigned_flag = result.maybe_assigned_flag();
    660     return result.index() + kNotFound;
    661   }
    662   return kNotFound;
    663 }
    664 
    665 
    666 void ContextSlotCache::Update(Handle<Object> data, Handle<String> name,
    667                               VariableMode mode, InitializationFlag init_flag,
    668                               MaybeAssignedFlag maybe_assigned_flag,
    669                               int slot_index) {
    670   DisallowHeapAllocation no_gc;
    671   Handle<String> internalized_name;
    672   DCHECK(slot_index > kNotFound);
    673   if (StringTable::InternalizeStringIfExists(name->GetIsolate(), name).
    674       ToHandle(&internalized_name)) {
    675     int index = Hash(*data, *internalized_name);
    676     Key& key = keys_[index];
    677     key.data = *data;
    678     key.name = *internalized_name;
    679     // Please note value only takes a uint as index.
    680     values_[index] = Value(mode, init_flag, maybe_assigned_flag,
    681                            slot_index - kNotFound).raw();
    682 #ifdef DEBUG
    683     ValidateEntry(data, name, mode, init_flag, maybe_assigned_flag, slot_index);
    684 #endif
    685   }
    686 }
    687 
    688 
    689 void ContextSlotCache::Clear() {
    690   for (int index = 0; index < kLength; index++) keys_[index].data = NULL;
    691 }
    692 
    693 
    694 #ifdef DEBUG
    695 
    696 void ContextSlotCache::ValidateEntry(Handle<Object> data, Handle<String> name,
    697                                      VariableMode mode,
    698                                      InitializationFlag init_flag,
    699                                      MaybeAssignedFlag maybe_assigned_flag,
    700                                      int slot_index) {
    701   DisallowHeapAllocation no_gc;
    702   Handle<String> internalized_name;
    703   if (StringTable::InternalizeStringIfExists(name->GetIsolate(), name).
    704       ToHandle(&internalized_name)) {
    705     int index = Hash(*data, *name);
    706     Key& key = keys_[index];
    707     DCHECK(key.data == *data);
    708     DCHECK(key.name->Equals(*name));
    709     Value result(values_[index]);
    710     DCHECK(result.mode() == mode);
    711     DCHECK(result.initialization_flag() == init_flag);
    712     DCHECK(result.maybe_assigned_flag() == maybe_assigned_flag);
    713     DCHECK(result.index() + kNotFound == slot_index);
    714   }
    715 }
    716 
    717 
    718 static void PrintList(const char* list_name,
    719                       int nof_internal_slots,
    720                       int start,
    721                       int end,
    722                       ScopeInfo* scope_info) {
    723   if (start < end) {
    724     PrintF("\n  // %s\n", list_name);
    725     if (nof_internal_slots > 0) {
    726       PrintF("  %2d - %2d [internal slots]\n", 0 , nof_internal_slots - 1);
    727     }
    728     for (int i = nof_internal_slots; start < end; ++i, ++start) {
    729       PrintF("  %2d ", i);
    730       String::cast(scope_info->get(start))->ShortPrint();
    731       PrintF("\n");
    732     }
    733   }
    734 }
    735 
    736 
    737 void ScopeInfo::Print() {
    738   PrintF("ScopeInfo ");
    739   if (HasFunctionName()) {
    740     FunctionName()->ShortPrint();
    741   } else {
    742     PrintF("/* no function name */");
    743   }
    744   PrintF("{");
    745 
    746   if (length() > 0) {
    747     PrintList("parameters", 0, ParameterEntriesIndex(),
    748               ParameterEntriesIndex() + ParameterCount(), this);
    749     PrintList("stack slots", 0, StackLocalEntriesIndex(),
    750               StackLocalEntriesIndex() + StackLocalCount(), this);
    751     PrintList("context slots", Context::MIN_CONTEXT_SLOTS,
    752               ContextLocalNameEntriesIndex(),
    753               ContextLocalNameEntriesIndex() + ContextLocalCount(), this);
    754   }
    755 
    756   PrintF("}\n");
    757 }
    758 #endif  // DEBUG
    759 
    760 
    761 //---------------------------------------------------------------------------
    762 // ModuleInfo.
    763 
    764 Handle<ModuleInfo> ModuleInfo::Create(Isolate* isolate,
    765                                       ModuleDescriptor* descriptor,
    766                                       Scope* scope) {
    767   Handle<ModuleInfo> info = Allocate(isolate, descriptor->Length());
    768   info->set_host_index(descriptor->Index());
    769   int i = 0;
    770   for (ModuleDescriptor::Iterator it = descriptor->iterator(); !it.done();
    771        it.Advance(), ++i) {
    772     Variable* var = scope->LookupLocal(it.local_name());
    773     info->set_name(i, *(it.export_name()->string()));
    774     info->set_mode(i, var->mode());
    775     DCHECK(var->index() >= 0);
    776     info->set_index(i, var->index());
    777   }
    778   DCHECK(i == info->length());
    779   return info;
    780 }
    781 
    782 }  // namespace internal
    783 }  // namespace v8
    784