Home | History | Annotate | Download | only in src
      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 <stdlib.h>
      6 
      7 #include "src/v8.h"
      8 
      9 #include "src/scopeinfo.h"
     10 #include "src/scopes.h"
     11 
     12 namespace v8 {
     13 namespace internal {
     14 
     15 
     16 Handle<ScopeInfo> ScopeInfo::Create(Scope* scope, Zone* zone) {
     17   // Collect stack and context locals.
     18   ZoneList<Variable*> stack_locals(scope->StackLocalCount(), zone);
     19   ZoneList<Variable*> context_locals(scope->ContextLocalCount(), zone);
     20   scope->CollectStackAndContextLocals(&stack_locals, &context_locals);
     21   const int stack_local_count = stack_locals.length();
     22   const int context_local_count = context_locals.length();
     23   // Make sure we allocate the correct amount.
     24   DCHECK(scope->StackLocalCount() == stack_local_count);
     25   DCHECK(scope->ContextLocalCount() == context_local_count);
     26 
     27   // Determine use and location of the function variable if it is present.
     28   FunctionVariableInfo function_name_info;
     29   VariableMode function_variable_mode;
     30   if (scope->is_function_scope() && scope->function() != NULL) {
     31     Variable* var = scope->function()->proxy()->var();
     32     if (!var->is_used()) {
     33       function_name_info = UNUSED;
     34     } else if (var->IsContextSlot()) {
     35       function_name_info = CONTEXT;
     36     } else {
     37       DCHECK(var->IsStackLocal());
     38       function_name_info = STACK;
     39     }
     40     function_variable_mode = var->mode();
     41   } else {
     42     function_name_info = NONE;
     43     function_variable_mode = VAR;
     44   }
     45 
     46   const bool has_function_name = function_name_info != NONE;
     47   const int parameter_count = scope->num_parameters();
     48   const int length = kVariablePartIndex
     49       + parameter_count + stack_local_count + 2 * context_local_count
     50       + (has_function_name ? 2 : 0);
     51 
     52   Factory* factory = zone->isolate()->factory();
     53   Handle<ScopeInfo> scope_info = factory->NewScopeInfo(length);
     54 
     55   // Encode the flags.
     56   int flags = ScopeTypeField::encode(scope->scope_type()) |
     57               CallsEvalField::encode(scope->calls_eval()) |
     58               StrictModeField::encode(scope->strict_mode()) |
     59               FunctionVariableField::encode(function_name_info) |
     60               FunctionVariableMode::encode(function_variable_mode) |
     61               AsmModuleField::encode(scope->asm_module()) |
     62               AsmFunctionField::encode(scope->asm_function());
     63   scope_info->SetFlags(flags);
     64   scope_info->SetParameterCount(parameter_count);
     65   scope_info->SetStackLocalCount(stack_local_count);
     66   scope_info->SetContextLocalCount(context_local_count);
     67 
     68   int index = kVariablePartIndex;
     69   // Add parameters.
     70   DCHECK(index == scope_info->ParameterEntriesIndex());
     71   for (int i = 0; i < parameter_count; ++i) {
     72     scope_info->set(index++, *scope->parameter(i)->name());
     73   }
     74 
     75   // Add stack locals' names. We are assuming that the stack locals'
     76   // slots are allocated in increasing order, so we can simply add
     77   // them to the ScopeInfo object.
     78   DCHECK(index == scope_info->StackLocalEntriesIndex());
     79   for (int i = 0; i < stack_local_count; ++i) {
     80     DCHECK(stack_locals[i]->index() == i);
     81     scope_info->set(index++, *stack_locals[i]->name());
     82   }
     83 
     84   // Due to usage analysis, context-allocated locals are not necessarily in
     85   // increasing order: Some of them may be parameters which are allocated before
     86   // the non-parameter locals. When the non-parameter locals are sorted
     87   // according to usage, the allocated slot indices may not be in increasing
     88   // order with the variable list anymore. Thus, we first need to sort them by
     89   // context slot index before adding them to the ScopeInfo object.
     90   context_locals.Sort(&Variable::CompareIndex);
     91 
     92   // Add context locals' names.
     93   DCHECK(index == scope_info->ContextLocalNameEntriesIndex());
     94   for (int i = 0; i < context_local_count; ++i) {
     95     scope_info->set(index++, *context_locals[i]->name());
     96   }
     97 
     98   // Add context locals' info.
     99   DCHECK(index == scope_info->ContextLocalInfoEntriesIndex());
    100   for (int i = 0; i < context_local_count; ++i) {
    101     Variable* var = context_locals[i];
    102     uint32_t value =
    103         ContextLocalMode::encode(var->mode()) |
    104         ContextLocalInitFlag::encode(var->initialization_flag()) |
    105         ContextLocalMaybeAssignedFlag::encode(var->maybe_assigned());
    106     scope_info->set(index++, Smi::FromInt(value));
    107   }
    108 
    109   // If present, add the function variable name and its index.
    110   DCHECK(index == scope_info->FunctionNameEntryIndex());
    111   if (has_function_name) {
    112     int var_index = scope->function()->proxy()->var()->index();
    113     scope_info->set(index++, *scope->function()->proxy()->name());
    114     scope_info->set(index++, Smi::FromInt(var_index));
    115     DCHECK(function_name_info != STACK ||
    116            (var_index == scope_info->StackLocalCount() &&
    117             var_index == scope_info->StackSlotCount() - 1));
    118     DCHECK(function_name_info != CONTEXT ||
    119            var_index == scope_info->ContextLength() - 1);
    120   }
    121 
    122   DCHECK(index == scope_info->length());
    123   DCHECK(scope->num_parameters() == scope_info->ParameterCount());
    124   DCHECK(scope->num_stack_slots() == scope_info->StackSlotCount());
    125   DCHECK(scope->num_heap_slots() == scope_info->ContextLength() ||
    126          (scope->num_heap_slots() == kVariablePartIndex &&
    127           scope_info->ContextLength() == 0));
    128   return scope_info;
    129 }
    130 
    131 
    132 ScopeInfo* ScopeInfo::Empty(Isolate* isolate) {
    133   return reinterpret_cast<ScopeInfo*>(isolate->heap()->empty_fixed_array());
    134 }
    135 
    136 
    137 ScopeType ScopeInfo::scope_type() {
    138   DCHECK(length() > 0);
    139   return ScopeTypeField::decode(Flags());
    140 }
    141 
    142 
    143 bool ScopeInfo::CallsEval() {
    144   return length() > 0 && CallsEvalField::decode(Flags());
    145 }
    146 
    147 
    148 StrictMode ScopeInfo::strict_mode() {
    149   return length() > 0 ? StrictModeField::decode(Flags()) : SLOPPY;
    150 }
    151 
    152 
    153 int ScopeInfo::LocalCount() {
    154   return StackLocalCount() + ContextLocalCount();
    155 }
    156 
    157 
    158 int ScopeInfo::StackSlotCount() {
    159   if (length() > 0) {
    160     bool function_name_stack_slot =
    161         FunctionVariableField::decode(Flags()) == STACK;
    162     return StackLocalCount() + (function_name_stack_slot ? 1 : 0);
    163   }
    164   return 0;
    165 }
    166 
    167 
    168 int ScopeInfo::ContextLength() {
    169   if (length() > 0) {
    170     int context_locals = ContextLocalCount();
    171     bool function_name_context_slot =
    172         FunctionVariableField::decode(Flags()) == CONTEXT;
    173     bool has_context = context_locals > 0 ||
    174         function_name_context_slot ||
    175         scope_type() == WITH_SCOPE ||
    176         (scope_type() == FUNCTION_SCOPE && CallsEval()) ||
    177         scope_type() == MODULE_SCOPE;
    178     if (has_context) {
    179       return Context::MIN_CONTEXT_SLOTS + context_locals +
    180           (function_name_context_slot ? 1 : 0);
    181     }
    182   }
    183   return 0;
    184 }
    185 
    186 
    187 bool ScopeInfo::HasFunctionName() {
    188   if (length() > 0) {
    189     return NONE != FunctionVariableField::decode(Flags());
    190   } else {
    191     return false;
    192   }
    193 }
    194 
    195 
    196 bool ScopeInfo::HasHeapAllocatedLocals() {
    197   if (length() > 0) {
    198     return ContextLocalCount() > 0;
    199   } else {
    200     return false;
    201   }
    202 }
    203 
    204 
    205 bool ScopeInfo::HasContext() {
    206   return ContextLength() > 0;
    207 }
    208 
    209 
    210 String* ScopeInfo::FunctionName() {
    211   DCHECK(HasFunctionName());
    212   return String::cast(get(FunctionNameEntryIndex()));
    213 }
    214 
    215 
    216 String* ScopeInfo::ParameterName(int var) {
    217   DCHECK(0 <= var && var < ParameterCount());
    218   int info_index = ParameterEntriesIndex() + var;
    219   return String::cast(get(info_index));
    220 }
    221 
    222 
    223 String* ScopeInfo::LocalName(int var) {
    224   DCHECK(0 <= var && var < LocalCount());
    225   DCHECK(StackLocalEntriesIndex() + StackLocalCount() ==
    226          ContextLocalNameEntriesIndex());
    227   int info_index = StackLocalEntriesIndex() + var;
    228   return String::cast(get(info_index));
    229 }
    230 
    231 
    232 String* ScopeInfo::StackLocalName(int var) {
    233   DCHECK(0 <= var && var < StackLocalCount());
    234   int info_index = StackLocalEntriesIndex() + var;
    235   return String::cast(get(info_index));
    236 }
    237 
    238 
    239 String* ScopeInfo::ContextLocalName(int var) {
    240   DCHECK(0 <= var && var < ContextLocalCount());
    241   int info_index = ContextLocalNameEntriesIndex() + var;
    242   return String::cast(get(info_index));
    243 }
    244 
    245 
    246 VariableMode ScopeInfo::ContextLocalMode(int var) {
    247   DCHECK(0 <= var && var < ContextLocalCount());
    248   int info_index = ContextLocalInfoEntriesIndex() + var;
    249   int value = Smi::cast(get(info_index))->value();
    250   return ContextLocalMode::decode(value);
    251 }
    252 
    253 
    254 InitializationFlag ScopeInfo::ContextLocalInitFlag(int var) {
    255   DCHECK(0 <= var && var < ContextLocalCount());
    256   int info_index = ContextLocalInfoEntriesIndex() + var;
    257   int value = Smi::cast(get(info_index))->value();
    258   return ContextLocalInitFlag::decode(value);
    259 }
    260 
    261 
    262 MaybeAssignedFlag ScopeInfo::ContextLocalMaybeAssignedFlag(int var) {
    263   DCHECK(0 <= var && var < ContextLocalCount());
    264   int info_index = ContextLocalInfoEntriesIndex() + var;
    265   int value = Smi::cast(get(info_index))->value();
    266   return ContextLocalMaybeAssignedFlag::decode(value);
    267 }
    268 
    269 
    270 bool ScopeInfo::LocalIsSynthetic(int var) {
    271   DCHECK(0 <= var && var < LocalCount());
    272   // There's currently no flag stored on the ScopeInfo to indicate that a
    273   // variable is a compiler-introduced temporary. However, to avoid conflict
    274   // with user declarations, the current temporaries like .generator_object and
    275   // .result start with a dot, so we can use that as a flag. It's a hack!
    276   Handle<String> name(LocalName(var));
    277   return name->length() > 0 && name->Get(0) == '.';
    278 }
    279 
    280 
    281 int ScopeInfo::StackSlotIndex(String* name) {
    282   DCHECK(name->IsInternalizedString());
    283   if (length() > 0) {
    284     int start = StackLocalEntriesIndex();
    285     int end = StackLocalEntriesIndex() + StackLocalCount();
    286     for (int i = start; i < end; ++i) {
    287       if (name == get(i)) {
    288         return i - start;
    289       }
    290     }
    291   }
    292   return -1;
    293 }
    294 
    295 
    296 int ScopeInfo::ContextSlotIndex(Handle<ScopeInfo> scope_info,
    297                                 Handle<String> name, VariableMode* mode,
    298                                 InitializationFlag* init_flag,
    299                                 MaybeAssignedFlag* maybe_assigned_flag) {
    300   DCHECK(name->IsInternalizedString());
    301   DCHECK(mode != NULL);
    302   DCHECK(init_flag != NULL);
    303   if (scope_info->length() > 0) {
    304     ContextSlotCache* context_slot_cache =
    305         scope_info->GetIsolate()->context_slot_cache();
    306     int result = context_slot_cache->Lookup(*scope_info, *name, mode, init_flag,
    307                                             maybe_assigned_flag);
    308     if (result != ContextSlotCache::kNotFound) {
    309       DCHECK(result < scope_info->ContextLength());
    310       return result;
    311     }
    312 
    313     int start = scope_info->ContextLocalNameEntriesIndex();
    314     int end = scope_info->ContextLocalNameEntriesIndex() +
    315         scope_info->ContextLocalCount();
    316     for (int i = start; i < end; ++i) {
    317       if (*name == scope_info->get(i)) {
    318         int var = i - start;
    319         *mode = scope_info->ContextLocalMode(var);
    320         *init_flag = scope_info->ContextLocalInitFlag(var);
    321         *maybe_assigned_flag = scope_info->ContextLocalMaybeAssignedFlag(var);
    322         result = Context::MIN_CONTEXT_SLOTS + var;
    323         context_slot_cache->Update(scope_info, name, *mode, *init_flag,
    324                                    *maybe_assigned_flag, result);
    325         DCHECK(result < scope_info->ContextLength());
    326         return result;
    327       }
    328     }
    329     // Cache as not found. Mode, init flag and maybe assigned flag don't matter.
    330     context_slot_cache->Update(scope_info, name, INTERNAL, kNeedsInitialization,
    331                                kNotAssigned, -1);
    332   }
    333   return -1;
    334 }
    335 
    336 
    337 int ScopeInfo::ParameterIndex(String* name) {
    338   DCHECK(name->IsInternalizedString());
    339   if (length() > 0) {
    340     // We must read parameters from the end since for
    341     // multiply declared parameters the value of the
    342     // last declaration of that parameter is used
    343     // inside a function (and thus we need to look
    344     // at the last index). Was bug# 1110337.
    345     int start = ParameterEntriesIndex();
    346     int end = ParameterEntriesIndex() + ParameterCount();
    347     for (int i = end - 1; i >= start; --i) {
    348       if (name == get(i)) {
    349         return i - start;
    350       }
    351     }
    352   }
    353   return -1;
    354 }
    355 
    356 
    357 int ScopeInfo::FunctionContextSlotIndex(String* name, VariableMode* mode) {
    358   DCHECK(name->IsInternalizedString());
    359   DCHECK(mode != NULL);
    360   if (length() > 0) {
    361     if (FunctionVariableField::decode(Flags()) == CONTEXT &&
    362         FunctionName() == name) {
    363       *mode = FunctionVariableMode::decode(Flags());
    364       return Smi::cast(get(FunctionNameEntryIndex() + 1))->value();
    365     }
    366   }
    367   return -1;
    368 }
    369 
    370 
    371 bool ScopeInfo::CopyContextLocalsToScopeObject(Handle<ScopeInfo> scope_info,
    372                                                Handle<Context> context,
    373                                                Handle<JSObject> scope_object) {
    374   Isolate* isolate = scope_info->GetIsolate();
    375   int local_count = scope_info->ContextLocalCount();
    376   if (local_count == 0) return true;
    377   // Fill all context locals to the context extension.
    378   int first_context_var = scope_info->StackLocalCount();
    379   int start = scope_info->ContextLocalNameEntriesIndex();
    380   for (int i = 0; i < local_count; ++i) {
    381     if (scope_info->LocalIsSynthetic(first_context_var + i)) continue;
    382     int context_index = Context::MIN_CONTEXT_SLOTS + i;
    383     RETURN_ON_EXCEPTION_VALUE(
    384         isolate,
    385         Runtime::DefineObjectProperty(
    386             scope_object,
    387             Handle<String>(String::cast(scope_info->get(i + start))),
    388             Handle<Object>(context->get(context_index), isolate),
    389             ::NONE),
    390         false);
    391   }
    392   return true;
    393 }
    394 
    395 
    396 int ScopeInfo::ParameterEntriesIndex() {
    397   DCHECK(length() > 0);
    398   return kVariablePartIndex;
    399 }
    400 
    401 
    402 int ScopeInfo::StackLocalEntriesIndex() {
    403   return ParameterEntriesIndex() + ParameterCount();
    404 }
    405 
    406 
    407 int ScopeInfo::ContextLocalNameEntriesIndex() {
    408   return StackLocalEntriesIndex() + StackLocalCount();
    409 }
    410 
    411 
    412 int ScopeInfo::ContextLocalInfoEntriesIndex() {
    413   return ContextLocalNameEntriesIndex() + ContextLocalCount();
    414 }
    415 
    416 
    417 int ScopeInfo::FunctionNameEntryIndex() {
    418   return ContextLocalInfoEntriesIndex() + ContextLocalCount();
    419 }
    420 
    421 
    422 int ContextSlotCache::Hash(Object* data, String* name) {
    423   // Uses only lower 32 bits if pointers are larger.
    424   uintptr_t addr_hash =
    425       static_cast<uint32_t>(reinterpret_cast<uintptr_t>(data)) >> 2;
    426   return static_cast<int>((addr_hash ^ name->Hash()) % kLength);
    427 }
    428 
    429 
    430 int ContextSlotCache::Lookup(Object* data, String* name, VariableMode* mode,
    431                              InitializationFlag* init_flag,
    432                              MaybeAssignedFlag* maybe_assigned_flag) {
    433   int index = Hash(data, name);
    434   Key& key = keys_[index];
    435   if ((key.data == data) && key.name->Equals(name)) {
    436     Value result(values_[index]);
    437     if (mode != NULL) *mode = result.mode();
    438     if (init_flag != NULL) *init_flag = result.initialization_flag();
    439     if (maybe_assigned_flag != NULL)
    440       *maybe_assigned_flag = result.maybe_assigned_flag();
    441     return result.index() + kNotFound;
    442   }
    443   return kNotFound;
    444 }
    445 
    446 
    447 void ContextSlotCache::Update(Handle<Object> data, Handle<String> name,
    448                               VariableMode mode, InitializationFlag init_flag,
    449                               MaybeAssignedFlag maybe_assigned_flag,
    450                               int slot_index) {
    451   DisallowHeapAllocation no_gc;
    452   Handle<String> internalized_name;
    453   DCHECK(slot_index > kNotFound);
    454   if (StringTable::InternalizeStringIfExists(name->GetIsolate(), name).
    455       ToHandle(&internalized_name)) {
    456     int index = Hash(*data, *internalized_name);
    457     Key& key = keys_[index];
    458     key.data = *data;
    459     key.name = *internalized_name;
    460     // Please note value only takes a uint as index.
    461     values_[index] = Value(mode, init_flag, maybe_assigned_flag,
    462                            slot_index - kNotFound).raw();
    463 #ifdef DEBUG
    464     ValidateEntry(data, name, mode, init_flag, maybe_assigned_flag, slot_index);
    465 #endif
    466   }
    467 }
    468 
    469 
    470 void ContextSlotCache::Clear() {
    471   for (int index = 0; index < kLength; index++) keys_[index].data = NULL;
    472 }
    473 
    474 
    475 #ifdef DEBUG
    476 
    477 void ContextSlotCache::ValidateEntry(Handle<Object> data, Handle<String> name,
    478                                      VariableMode mode,
    479                                      InitializationFlag init_flag,
    480                                      MaybeAssignedFlag maybe_assigned_flag,
    481                                      int slot_index) {
    482   DisallowHeapAllocation no_gc;
    483   Handle<String> internalized_name;
    484   if (StringTable::InternalizeStringIfExists(name->GetIsolate(), name).
    485       ToHandle(&internalized_name)) {
    486     int index = Hash(*data, *name);
    487     Key& key = keys_[index];
    488     DCHECK(key.data == *data);
    489     DCHECK(key.name->Equals(*name));
    490     Value result(values_[index]);
    491     DCHECK(result.mode() == mode);
    492     DCHECK(result.initialization_flag() == init_flag);
    493     DCHECK(result.maybe_assigned_flag() == maybe_assigned_flag);
    494     DCHECK(result.index() + kNotFound == slot_index);
    495   }
    496 }
    497 
    498 
    499 static void PrintList(const char* list_name,
    500                       int nof_internal_slots,
    501                       int start,
    502                       int end,
    503                       ScopeInfo* scope_info) {
    504   if (start < end) {
    505     PrintF("\n  // %s\n", list_name);
    506     if (nof_internal_slots > 0) {
    507       PrintF("  %2d - %2d [internal slots]\n", 0 , nof_internal_slots - 1);
    508     }
    509     for (int i = nof_internal_slots; start < end; ++i, ++start) {
    510       PrintF("  %2d ", i);
    511       String::cast(scope_info->get(start))->ShortPrint();
    512       PrintF("\n");
    513     }
    514   }
    515 }
    516 
    517 
    518 void ScopeInfo::Print() {
    519   PrintF("ScopeInfo ");
    520   if (HasFunctionName()) {
    521     FunctionName()->ShortPrint();
    522   } else {
    523     PrintF("/* no function name */");
    524   }
    525   PrintF("{");
    526 
    527   PrintList("parameters", 0,
    528             ParameterEntriesIndex(),
    529             ParameterEntriesIndex() + ParameterCount(),
    530             this);
    531   PrintList("stack slots", 0,
    532             StackLocalEntriesIndex(),
    533             StackLocalEntriesIndex() + StackLocalCount(),
    534             this);
    535   PrintList("context slots",
    536             Context::MIN_CONTEXT_SLOTS,
    537             ContextLocalNameEntriesIndex(),
    538             ContextLocalNameEntriesIndex() + ContextLocalCount(),
    539             this);
    540 
    541   PrintF("}\n");
    542 }
    543 #endif  // DEBUG
    544 
    545 
    546 //---------------------------------------------------------------------------
    547 // ModuleInfo.
    548 
    549 Handle<ModuleInfo> ModuleInfo::Create(
    550     Isolate* isolate, Interface* interface, Scope* scope) {
    551   Handle<ModuleInfo> info = Allocate(isolate, interface->Length());
    552   info->set_host_index(interface->Index());
    553   int i = 0;
    554   for (Interface::Iterator it = interface->iterator();
    555        !it.done(); it.Advance(), ++i) {
    556     Variable* var = scope->LookupLocal(it.name());
    557     info->set_name(i, *(it.name()->string()));
    558     info->set_mode(i, var->mode());
    559     DCHECK((var->mode() == MODULE) == (it.interface()->IsModule()));
    560     if (var->mode() == MODULE) {
    561       DCHECK(it.interface()->IsFrozen());
    562       DCHECK(it.interface()->Index() >= 0);
    563       info->set_index(i, it.interface()->Index());
    564     } else {
    565       DCHECK(var->index() >= 0);
    566       info->set_index(i, var->index());
    567     }
    568   }
    569   DCHECK(i == info->length());
    570   return info;
    571 }
    572 
    573 } }  // namespace v8::internal
    574