• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
Create(Scope * scope,Zone * zone)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 
Empty(Isolate * isolate)128 ScopeInfo* ScopeInfo::Empty(Isolate* isolate) {
129   return reinterpret_cast<ScopeInfo*>(isolate->heap()->empty_fixed_array());
130 }
131 
132 
scope_type()133 ScopeType ScopeInfo::scope_type() {
134   ASSERT(length() > 0);
135   return ScopeTypeField::decode(Flags());
136 }
137 
138 
CallsEval()139 bool ScopeInfo::CallsEval() {
140   return length() > 0 && CallsEvalField::decode(Flags());
141 }
142 
143 
strict_mode()144 StrictMode ScopeInfo::strict_mode() {
145   return length() > 0 ? StrictModeField::decode(Flags()) : SLOPPY;
146 }
147 
148 
LocalCount()149 int ScopeInfo::LocalCount() {
150   return StackLocalCount() + ContextLocalCount();
151 }
152 
153 
StackSlotCount()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 
ContextLength()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 
HasFunctionName()183 bool ScopeInfo::HasFunctionName() {
184   if (length() > 0) {
185     return NONE != FunctionVariableField::decode(Flags());
186   } else {
187     return false;
188   }
189 }
190 
191 
HasHeapAllocatedLocals()192 bool ScopeInfo::HasHeapAllocatedLocals() {
193   if (length() > 0) {
194     return ContextLocalCount() > 0;
195   } else {
196     return false;
197   }
198 }
199 
200 
HasContext()201 bool ScopeInfo::HasContext() {
202   return ContextLength() > 0;
203 }
204 
205 
FunctionName()206 String* ScopeInfo::FunctionName() {
207   ASSERT(HasFunctionName());
208   return String::cast(get(FunctionNameEntryIndex()));
209 }
210 
211 
ParameterName(int var)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 
LocalName(int var)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 
StackLocalName(int var)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 
ContextLocalName(int var)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 
ContextLocalMode(int var)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 
ContextLocalInitFlag(int var)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 
LocalIsSynthetic(int var)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 
StackSlotIndex(String * name)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 
ContextSlotIndex(Handle<ScopeInfo> scope_info,Handle<String> name,VariableMode * mode,InitializationFlag * init_flag)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 
ParameterIndex(String * name)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 
FunctionContextSlotIndex(String * name,VariableMode * mode)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 
CopyContextLocalsToScopeObject(Handle<ScopeInfo> scope_info,Handle<Context> context,Handle<JSObject> scope_object)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 
ParameterEntriesIndex()384 int ScopeInfo::ParameterEntriesIndex() {
385   ASSERT(length() > 0);
386   return kVariablePartIndex;
387 }
388 
389 
StackLocalEntriesIndex()390 int ScopeInfo::StackLocalEntriesIndex() {
391   return ParameterEntriesIndex() + ParameterCount();
392 }
393 
394 
ContextLocalNameEntriesIndex()395 int ScopeInfo::ContextLocalNameEntriesIndex() {
396   return StackLocalEntriesIndex() + StackLocalCount();
397 }
398 
399 
ContextLocalInfoEntriesIndex()400 int ScopeInfo::ContextLocalInfoEntriesIndex() {
401   return ContextLocalNameEntriesIndex() + ContextLocalCount();
402 }
403 
404 
FunctionNameEntryIndex()405 int ScopeInfo::FunctionNameEntryIndex() {
406   return ContextLocalInfoEntriesIndex() + ContextLocalCount();
407 }
408 
409 
Hash(Object * data,String * name)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 
Lookup(Object * data,String * name,VariableMode * mode,InitializationFlag * init_flag)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 
Update(Handle<Object> data,Handle<String> name,VariableMode mode,InitializationFlag init_flag,int slot_index)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 
Clear()457 void ContextSlotCache::Clear() {
458   for (int index = 0; index < kLength; index++) keys_[index].data = NULL;
459 }
460 
461 
462 #ifdef DEBUG
463 
ValidateEntry(Handle<Object> data,Handle<String> name,VariableMode mode,InitializationFlag init_flag,int slot_index)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 
PrintList(const char * list_name,int nof_internal_slots,int start,int end,ScopeInfo * scope_info)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 
Print()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 
Create(Isolate * isolate,Interface * interface,Scope * scope)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