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