Home | History | Annotate | Download | only in src
      1 // Copyright 2011 the V8 project authors. All rights reserved.
      2 // Redistribution and use in source and binary forms, with or without
      3 // modification, are permitted provided that the following conditions are
      4 // met:
      5 //
      6 //     * Redistributions of source code must retain the above copyright
      7 //       notice, this list of conditions and the following disclaimer.
      8 //     * Redistributions in binary form must reproduce the above
      9 //       copyright notice, this list of conditions and the following
     10 //       disclaimer in the documentation and/or other materials provided
     11 //       with the distribution.
     12 //     * Neither the name of Google Inc. nor the names of its
     13 //       contributors may be used to endorse or promote products derived
     14 //       from this software without specific prior written permission.
     15 //
     16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27 
     28 #include <stdlib.h>
     29 
     30 #include "v8.h"
     31 
     32 #include "scopeinfo.h"
     33 #include "scopes.h"
     34 
     35 namespace v8 {
     36 namespace internal {
     37 
     38 
     39 Handle<ScopeInfo> ScopeInfo::Create(Scope* scope, Zone* zone) {
     40   // Collect stack and context locals.
     41   ZoneList<Variable*> stack_locals(scope->StackLocalCount(), zone);
     42   ZoneList<Variable*> context_locals(scope->ContextLocalCount(), zone);
     43   scope->CollectStackAndContextLocals(&stack_locals, &context_locals);
     44   const int stack_local_count = stack_locals.length();
     45   const int context_local_count = context_locals.length();
     46   // Make sure we allocate the correct amount.
     47   ASSERT(scope->StackLocalCount() == stack_local_count);
     48   ASSERT(scope->ContextLocalCount() == context_local_count);
     49 
     50   // Determine use and location of the function variable if it is present.
     51   FunctionVariableInfo 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       ASSERT(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 
     69   const bool has_function_name = function_name_info != NONE;
     70   const int parameter_count = scope->num_parameters();
     71   const int length = kVariablePartIndex
     72       + parameter_count + stack_local_count + 2 * context_local_count
     73       + (has_function_name ? 2 : 0);
     74 
     75   Factory* factory = zone->isolate()->factory();
     76   Handle<ScopeInfo> scope_info = factory->NewScopeInfo(length);
     77 
     78   // Encode the flags.
     79   int flags = ScopeTypeField::encode(scope->scope_type()) |
     80       CallsEvalField::encode(scope->calls_eval()) |
     81       LanguageModeField::encode(scope->language_mode()) |
     82       FunctionVariableField::encode(function_name_info) |
     83       FunctionVariableMode::encode(function_variable_mode);
     84   scope_info->SetFlags(flags);
     85   scope_info->SetParameterCount(parameter_count);
     86   scope_info->SetStackLocalCount(stack_local_count);
     87   scope_info->SetContextLocalCount(context_local_count);
     88 
     89   int index = kVariablePartIndex;
     90   // Add parameters.
     91   ASSERT(index == scope_info->ParameterEntriesIndex());
     92   for (int i = 0; i < parameter_count; ++i) {
     93     scope_info->set(index++, *scope->parameter(i)->name());
     94   }
     95 
     96   // Add stack locals' names. We are assuming that the stack locals'
     97   // slots are allocated in increasing order, so we can simply add
     98   // them to the ScopeInfo object.
     99   ASSERT(index == scope_info->StackLocalEntriesIndex());
    100   for (int i = 0; i < stack_local_count; ++i) {
    101     ASSERT(stack_locals[i]->index() == i);
    102     scope_info->set(index++, *stack_locals[i]->name());
    103   }
    104 
    105   // Due to usage analysis, context-allocated locals are not necessarily in
    106   // increasing order: Some of them may be parameters which are allocated before
    107   // the non-parameter locals. When the non-parameter locals are sorted
    108   // according to usage, the allocated slot indices may not be in increasing
    109   // order with the variable list anymore. Thus, we first need to sort them by
    110   // context slot index before adding them to the ScopeInfo object.
    111   context_locals.Sort(&Variable::CompareIndex);
    112 
    113   // Add context locals' names.
    114   ASSERT(index == scope_info->ContextLocalNameEntriesIndex());
    115   for (int i = 0; i < context_local_count; ++i) {
    116     scope_info->set(index++, *context_locals[i]->name());
    117   }
    118 
    119   // Add context locals' info.
    120   ASSERT(index == scope_info->ContextLocalInfoEntriesIndex());
    121   for (int i = 0; i < context_local_count; ++i) {
    122     Variable* var = context_locals[i];
    123     uint32_t value = ContextLocalMode::encode(var->mode()) |
    124         ContextLocalInitFlag::encode(var->initialization_flag());
    125     scope_info->set(index++, Smi::FromInt(value));
    126   }
    127 
    128   // If present, add the function variable name and its index.
    129   ASSERT(index == scope_info->FunctionNameEntryIndex());
    130   if (has_function_name) {
    131     int var_index = scope->function()->proxy()->var()->index();
    132     scope_info->set(index++, *scope->function()->proxy()->name());
    133     scope_info->set(index++, Smi::FromInt(var_index));
    134     ASSERT(function_name_info != STACK ||
    135            (var_index == scope_info->StackLocalCount() &&
    136             var_index == scope_info->StackSlotCount() - 1));
    137     ASSERT(function_name_info != CONTEXT ||
    138            var_index == scope_info->ContextLength() - 1);
    139   }
    140 
    141   ASSERT(index == scope_info->length());
    142   ASSERT(scope->num_parameters() == scope_info->ParameterCount());
    143   ASSERT(scope->num_stack_slots() == scope_info->StackSlotCount());
    144   ASSERT(scope->num_heap_slots() == scope_info->ContextLength() ||
    145          (scope->num_heap_slots() == kVariablePartIndex &&
    146           scope_info->ContextLength() == 0));
    147   return scope_info;
    148 }
    149 
    150 
    151 ScopeInfo* ScopeInfo::Empty(Isolate* isolate) {
    152   return reinterpret_cast<ScopeInfo*>(isolate->heap()->empty_fixed_array());
    153 }
    154 
    155 
    156 ScopeType ScopeInfo::scope_type() {
    157   ASSERT(length() > 0);
    158   return ScopeTypeField::decode(Flags());
    159 }
    160 
    161 
    162 bool ScopeInfo::CallsEval() {
    163   return length() > 0 && CallsEvalField::decode(Flags());
    164 }
    165 
    166 
    167 LanguageMode ScopeInfo::language_mode() {
    168   return length() > 0 ? LanguageModeField::decode(Flags()) : CLASSIC_MODE;
    169 }
    170 
    171 
    172 int ScopeInfo::LocalCount() {
    173   return StackLocalCount() + ContextLocalCount();
    174 }
    175 
    176 
    177 int ScopeInfo::StackSlotCount() {
    178   if (length() > 0) {
    179     bool function_name_stack_slot =
    180         FunctionVariableField::decode(Flags()) == STACK;
    181     return StackLocalCount() + (function_name_stack_slot ? 1 : 0);
    182   }
    183   return 0;
    184 }
    185 
    186 
    187 int ScopeInfo::ContextLength() {
    188   if (length() > 0) {
    189     int context_locals = ContextLocalCount();
    190     bool function_name_context_slot =
    191         FunctionVariableField::decode(Flags()) == CONTEXT;
    192     bool has_context = context_locals > 0 ||
    193         function_name_context_slot ||
    194         scope_type() == WITH_SCOPE ||
    195         (scope_type() == FUNCTION_SCOPE && CallsEval()) ||
    196         scope_type() == MODULE_SCOPE;
    197     if (has_context) {
    198       return Context::MIN_CONTEXT_SLOTS + context_locals +
    199           (function_name_context_slot ? 1 : 0);
    200     }
    201   }
    202   return 0;
    203 }
    204 
    205 
    206 bool ScopeInfo::HasFunctionName() {
    207   if (length() > 0) {
    208     return NONE != FunctionVariableField::decode(Flags());
    209   } else {
    210     return false;
    211   }
    212 }
    213 
    214 
    215 bool ScopeInfo::HasHeapAllocatedLocals() {
    216   if (length() > 0) {
    217     return ContextLocalCount() > 0;
    218   } else {
    219     return false;
    220   }
    221 }
    222 
    223 
    224 bool ScopeInfo::HasContext() {
    225   return ContextLength() > 0;
    226 }
    227 
    228 
    229 String* ScopeInfo::FunctionName() {
    230   ASSERT(HasFunctionName());
    231   return String::cast(get(FunctionNameEntryIndex()));
    232 }
    233 
    234 
    235 String* ScopeInfo::ParameterName(int var) {
    236   ASSERT(0 <= var && var < ParameterCount());
    237   int info_index = ParameterEntriesIndex() + var;
    238   return String::cast(get(info_index));
    239 }
    240 
    241 
    242 String* ScopeInfo::LocalName(int var) {
    243   ASSERT(0 <= var && var < LocalCount());
    244   ASSERT(StackLocalEntriesIndex() + StackLocalCount() ==
    245          ContextLocalNameEntriesIndex());
    246   int info_index = StackLocalEntriesIndex() + var;
    247   return String::cast(get(info_index));
    248 }
    249 
    250 
    251 String* ScopeInfo::StackLocalName(int var) {
    252   ASSERT(0 <= var && var < StackLocalCount());
    253   int info_index = StackLocalEntriesIndex() + var;
    254   return String::cast(get(info_index));
    255 }
    256 
    257 
    258 String* ScopeInfo::ContextLocalName(int var) {
    259   ASSERT(0 <= var && var < ContextLocalCount());
    260   int info_index = ContextLocalNameEntriesIndex() + var;
    261   return String::cast(get(info_index));
    262 }
    263 
    264 
    265 VariableMode ScopeInfo::ContextLocalMode(int var) {
    266   ASSERT(0 <= var && var < ContextLocalCount());
    267   int info_index = ContextLocalInfoEntriesIndex() + var;
    268   int value = Smi::cast(get(info_index))->value();
    269   return ContextLocalMode::decode(value);
    270 }
    271 
    272 
    273 InitializationFlag ScopeInfo::ContextLocalInitFlag(int var) {
    274   ASSERT(0 <= var && var < ContextLocalCount());
    275   int info_index = ContextLocalInfoEntriesIndex() + var;
    276   int value = Smi::cast(get(info_index))->value();
    277   return ContextLocalInitFlag::decode(value);
    278 }
    279 
    280 
    281 int ScopeInfo::StackSlotIndex(String* name) {
    282   ASSERT(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(String* name,
    297                                 VariableMode* mode,
    298                                 InitializationFlag* init_flag) {
    299   ASSERT(name->IsInternalizedString());
    300   ASSERT(mode != NULL);
    301   ASSERT(init_flag != NULL);
    302   if (length() > 0) {
    303     ContextSlotCache* context_slot_cache = GetIsolate()->context_slot_cache();
    304     int result = context_slot_cache->Lookup(this, name, mode, init_flag);
    305     if (result != ContextSlotCache::kNotFound) {
    306       ASSERT(result < ContextLength());
    307       return result;
    308     }
    309 
    310     int start = ContextLocalNameEntriesIndex();
    311     int end = ContextLocalNameEntriesIndex() + ContextLocalCount();
    312     for (int i = start; i < end; ++i) {
    313       if (name == get(i)) {
    314         int var = i - start;
    315         *mode = ContextLocalMode(var);
    316         *init_flag = ContextLocalInitFlag(var);
    317         result = Context::MIN_CONTEXT_SLOTS + var;
    318         context_slot_cache->Update(this, name, *mode, *init_flag, result);
    319         ASSERT(result < ContextLength());
    320         return result;
    321       }
    322     }
    323     // Cache as not found. Mode and init flag don't matter.
    324     context_slot_cache->Update(this, name, INTERNAL, kNeedsInitialization, -1);
    325   }
    326   return -1;
    327 }
    328 
    329 
    330 int ScopeInfo::ParameterIndex(String* name) {
    331   ASSERT(name->IsInternalizedString());
    332   if (length() > 0) {
    333     // We must read parameters from the end since for
    334     // multiply declared parameters the value of the
    335     // last declaration of that parameter is used
    336     // inside a function (and thus we need to look
    337     // at the last index). Was bug# 1110337.
    338     int start = ParameterEntriesIndex();
    339     int end = ParameterEntriesIndex() + ParameterCount();
    340     for (int i = end - 1; i >= start; --i) {
    341       if (name == get(i)) {
    342         return i - start;
    343       }
    344     }
    345   }
    346   return -1;
    347 }
    348 
    349 
    350 int ScopeInfo::FunctionContextSlotIndex(String* name, VariableMode* mode) {
    351   ASSERT(name->IsInternalizedString());
    352   ASSERT(mode != NULL);
    353   if (length() > 0) {
    354     if (FunctionVariableField::decode(Flags()) == CONTEXT &&
    355         FunctionName() == name) {
    356       *mode = FunctionVariableMode::decode(Flags());
    357       return Smi::cast(get(FunctionNameEntryIndex() + 1))->value();
    358     }
    359   }
    360   return -1;
    361 }
    362 
    363 
    364 bool ScopeInfo::CopyContextLocalsToScopeObject(Handle<ScopeInfo> scope_info,
    365                                                Handle<Context> context,
    366                                                Handle<JSObject> scope_object) {
    367   Isolate* isolate = scope_info->GetIsolate();
    368   int local_count = scope_info->ContextLocalCount();
    369   if (local_count == 0) return true;
    370   // Fill all context locals to the context extension.
    371   int start = scope_info->ContextLocalNameEntriesIndex();
    372   int end = start + local_count;
    373   for (int i = start; i < end; ++i) {
    374     int context_index = Context::MIN_CONTEXT_SLOTS + i - start;
    375     Handle<Object> result = Runtime::SetObjectProperty(
    376         isolate,
    377         scope_object,
    378         Handle<String>(String::cast(scope_info->get(i))),
    379         Handle<Object>(context->get(context_index), isolate),
    380         ::NONE,
    381         kNonStrictMode);
    382     RETURN_IF_EMPTY_HANDLE_VALUE(isolate, result, false);
    383   }
    384   return true;
    385 }
    386 
    387 
    388 int ScopeInfo::ParameterEntriesIndex() {
    389   ASSERT(length() > 0);
    390   return kVariablePartIndex;
    391 }
    392 
    393 
    394 int ScopeInfo::StackLocalEntriesIndex() {
    395   return ParameterEntriesIndex() + ParameterCount();
    396 }
    397 
    398 
    399 int ScopeInfo::ContextLocalNameEntriesIndex() {
    400   return StackLocalEntriesIndex() + StackLocalCount();
    401 }
    402 
    403 
    404 int ScopeInfo::ContextLocalInfoEntriesIndex() {
    405   return ContextLocalNameEntriesIndex() + ContextLocalCount();
    406 }
    407 
    408 
    409 int ScopeInfo::FunctionNameEntryIndex() {
    410   return ContextLocalInfoEntriesIndex() + ContextLocalCount();
    411 }
    412 
    413 
    414 int ContextSlotCache::Hash(Object* data, String* name) {
    415   // Uses only lower 32 bits if pointers are larger.
    416   uintptr_t addr_hash =
    417       static_cast<uint32_t>(reinterpret_cast<uintptr_t>(data)) >> 2;
    418   return static_cast<int>((addr_hash ^ name->Hash()) % kLength);
    419 }
    420 
    421 
    422 int ContextSlotCache::Lookup(Object* data,
    423                              String* name,
    424                              VariableMode* mode,
    425                              InitializationFlag* init_flag) {
    426   int index = Hash(data, name);
    427   Key& key = keys_[index];
    428   if ((key.data == data) && key.name->Equals(name)) {
    429     Value result(values_[index]);
    430     if (mode != NULL) *mode = result.mode();
    431     if (init_flag != NULL) *init_flag = result.initialization_flag();
    432     return result.index() + kNotFound;
    433   }
    434   return kNotFound;
    435 }
    436 
    437 
    438 void ContextSlotCache::Update(Object* data,
    439                               String* name,
    440                               VariableMode mode,
    441                               InitializationFlag init_flag,
    442                               int slot_index) {
    443   String* internalized_name;
    444   ASSERT(slot_index > kNotFound);
    445   if (name->GetIsolate()->heap()->InternalizeStringIfExists(
    446           name, &internalized_name)) {
    447     int index = Hash(data, internalized_name);
    448     Key& key = keys_[index];
    449     key.data = data;
    450     key.name = internalized_name;
    451     // Please note value only takes a uint as index.
    452     values_[index] = Value(mode, init_flag, slot_index - kNotFound).raw();
    453 #ifdef DEBUG
    454     ValidateEntry(data, name, mode, init_flag, slot_index);
    455 #endif
    456   }
    457 }
    458 
    459 
    460 void ContextSlotCache::Clear() {
    461   for (int index = 0; index < kLength; index++) keys_[index].data = NULL;
    462 }
    463 
    464 
    465 #ifdef DEBUG
    466 
    467 void ContextSlotCache::ValidateEntry(Object* data,
    468                                      String* name,
    469                                      VariableMode mode,
    470                                      InitializationFlag init_flag,
    471                                      int slot_index) {
    472   String* internalized_name;
    473   if (name->GetIsolate()->heap()->InternalizeStringIfExists(
    474           name, &internalized_name)) {
    475     int index = Hash(data, name);
    476     Key& key = keys_[index];
    477     ASSERT(key.data == data);
    478     ASSERT(key.name->Equals(name));
    479     Value result(values_[index]);
    480     ASSERT(result.mode() == mode);
    481     ASSERT(result.initialization_flag() == init_flag);
    482     ASSERT(result.index() + kNotFound == slot_index);
    483   }
    484 }
    485 
    486 
    487 static void PrintList(const char* list_name,
    488                       int nof_internal_slots,
    489                       int start,
    490                       int end,
    491                       ScopeInfo* scope_info) {
    492   if (start < end) {
    493     PrintF("\n  // %s\n", list_name);
    494     if (nof_internal_slots > 0) {
    495       PrintF("  %2d - %2d [internal slots]\n", 0 , nof_internal_slots - 1);
    496     }
    497     for (int i = nof_internal_slots; start < end; ++i, ++start) {
    498       PrintF("  %2d ", i);
    499       String::cast(scope_info->get(start))->ShortPrint();
    500       PrintF("\n");
    501     }
    502   }
    503 }
    504 
    505 
    506 void ScopeInfo::Print() {
    507   PrintF("ScopeInfo ");
    508   if (HasFunctionName()) {
    509     FunctionName()->ShortPrint();
    510   } else {
    511     PrintF("/* no function name */");
    512   }
    513   PrintF("{");
    514 
    515   PrintList("parameters", 0,
    516             ParameterEntriesIndex(),
    517             ParameterEntriesIndex() + ParameterCount(),
    518             this);
    519   PrintList("stack slots", 0,
    520             StackLocalEntriesIndex(),
    521             StackLocalEntriesIndex() + StackLocalCount(),
    522             this);
    523   PrintList("context slots",
    524             Context::MIN_CONTEXT_SLOTS,
    525             ContextLocalNameEntriesIndex(),
    526             ContextLocalNameEntriesIndex() + ContextLocalCount(),
    527             this);
    528 
    529   PrintF("}\n");
    530 }
    531 #endif  // DEBUG
    532 
    533 
    534 //---------------------------------------------------------------------------
    535 // ModuleInfo.
    536 
    537 Handle<ModuleInfo> ModuleInfo::Create(
    538     Isolate* isolate, Interface* interface, Scope* scope) {
    539   Handle<ModuleInfo> info = Allocate(isolate, interface->Length());
    540   info->set_host_index(interface->Index());
    541   int i = 0;
    542   for (Interface::Iterator it = interface->iterator();
    543        !it.done(); it.Advance(), ++i) {
    544     Variable* var = scope->LocalLookup(it.name());
    545     info->set_name(i, *it.name());
    546     info->set_mode(i, var->mode());
    547     ASSERT((var->mode() == MODULE) == (it.interface()->IsModule()));
    548     if (var->mode() == MODULE) {
    549       ASSERT(it.interface()->IsFrozen());
    550       ASSERT(it.interface()->Index() >= 0);
    551       info->set_index(i, it.interface()->Index());
    552     } else {
    553       ASSERT(var->index() >= 0);
    554       info->set_index(i, var->index());
    555     }
    556   }
    557   ASSERT(i == info->length());
    558   return info;
    559 }
    560 
    561 } }  // namespace v8::internal
    562