• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "allocation-inl.h"
36 
37 namespace v8 {
38 namespace internal {
39 
40 
Create(Scope * scope)41 Handle<ScopeInfo> ScopeInfo::Create(Scope* scope) {
42   // Collect stack and context locals.
43   ZoneList<Variable*> stack_locals(scope->StackLocalCount());
44   ZoneList<Variable*> context_locals(scope->ContextLocalCount());
45   scope->CollectStackAndContextLocals(&stack_locals, &context_locals);
46   const int stack_local_count = stack_locals.length();
47   const int context_local_count = context_locals.length();
48   // Make sure we allocate the correct amount.
49   ASSERT(scope->StackLocalCount() == stack_local_count);
50   ASSERT(scope->ContextLocalCount() == context_local_count);
51 
52   // Determine use and location of the function variable if it is present.
53   FunctionVariableInfo function_name_info;
54   VariableMode function_variable_mode;
55   if (scope->is_function_scope() && scope->function() != NULL) {
56     Variable* var = scope->function()->var();
57     if (!var->is_used()) {
58       function_name_info = UNUSED;
59     } else if (var->IsContextSlot()) {
60       function_name_info = CONTEXT;
61     } else {
62       ASSERT(var->IsStackLocal());
63       function_name_info = STACK;
64     }
65     function_variable_mode = var->mode();
66   } else {
67     function_name_info = NONE;
68     function_variable_mode = VAR;
69   }
70 
71   const bool has_function_name = function_name_info != NONE;
72   const int parameter_count = scope->num_parameters();
73   const int length = kVariablePartIndex
74       + parameter_count + stack_local_count + 2 * context_local_count
75       + (has_function_name ? 2 : 0);
76 
77   Handle<ScopeInfo> scope_info = FACTORY->NewScopeInfo(length);
78 
79   // Encode the flags.
80   int flags = TypeField::encode(scope->type()) |
81       CallsEvalField::encode(scope->calls_eval()) |
82       LanguageModeField::encode(scope->language_mode()) |
83       FunctionVariableField::encode(function_name_info) |
84       FunctionVariableMode::encode(function_variable_mode);
85   scope_info->SetFlags(flags);
86   scope_info->SetParameterCount(parameter_count);
87   scope_info->SetStackLocalCount(stack_local_count);
88   scope_info->SetContextLocalCount(context_local_count);
89 
90   int index = kVariablePartIndex;
91   // Add parameters.
92   ASSERT(index == scope_info->ParameterEntriesIndex());
93   for (int i = 0; i < parameter_count; ++i) {
94     scope_info->set(index++, *scope->parameter(i)->name());
95   }
96 
97   // Add stack locals' names. We are assuming that the stack locals'
98   // slots are allocated in increasing order, so we can simply add
99   // them to the ScopeInfo object.
100   ASSERT(index == scope_info->StackLocalEntriesIndex());
101   for (int i = 0; i < stack_local_count; ++i) {
102     ASSERT(stack_locals[i]->index() == i);
103     scope_info->set(index++, *stack_locals[i]->name());
104   }
105 
106   // Due to usage analysis, context-allocated locals are not necessarily in
107   // increasing order: Some of them may be parameters which are allocated before
108   // the non-parameter locals. When the non-parameter locals are sorted
109   // according to usage, the allocated slot indices may not be in increasing
110   // order with the variable list anymore. Thus, we first need to sort them by
111   // context slot index before adding them to the ScopeInfo object.
112   context_locals.Sort(&Variable::CompareIndex);
113 
114   // Add context locals' names.
115   ASSERT(index == scope_info->ContextLocalNameEntriesIndex());
116   for (int i = 0; i < context_local_count; ++i) {
117     scope_info->set(index++, *context_locals[i]->name());
118   }
119 
120   // Add context locals' info.
121   ASSERT(index == scope_info->ContextLocalInfoEntriesIndex());
122   for (int i = 0; i < context_local_count; ++i) {
123     Variable* var = context_locals[i];
124     uint32_t value = ContextLocalMode::encode(var->mode()) |
125         ContextLocalInitFlag::encode(var->initialization_flag());
126     scope_info->set(index++, Smi::FromInt(value));
127   }
128 
129   // If present, add the function variable name and its index.
130   ASSERT(index == scope_info->FunctionNameEntryIndex());
131   if (has_function_name) {
132     int var_index = scope->function()->var()->index();
133     scope_info->set(index++, *scope->function()->name());
134     scope_info->set(index++, Smi::FromInt(var_index));
135     ASSERT(function_name_info != STACK ||
136            (var_index == scope_info->StackLocalCount() &&
137             var_index == scope_info->StackSlotCount() - 1));
138     ASSERT(function_name_info != CONTEXT ||
139            var_index == scope_info->ContextLength() - 1);
140   }
141 
142   ASSERT(index == scope_info->length());
143   ASSERT(scope->num_parameters() == scope_info->ParameterCount());
144   ASSERT(scope->num_stack_slots() == scope_info->StackSlotCount());
145   ASSERT(scope->num_heap_slots() == scope_info->ContextLength());
146   return scope_info;
147 }
148 
149 
Empty()150 ScopeInfo* ScopeInfo::Empty() {
151   return reinterpret_cast<ScopeInfo*>(HEAP->empty_fixed_array());
152 }
153 
154 
Type()155 ScopeType ScopeInfo::Type() {
156   ASSERT(length() > 0);
157   return TypeField::decode(Flags());
158 }
159 
160 
CallsEval()161 bool ScopeInfo::CallsEval() {
162   return length() > 0 && CallsEvalField::decode(Flags());
163 }
164 
165 
language_mode()166 LanguageMode ScopeInfo::language_mode() {
167   return length() > 0 ? LanguageModeField::decode(Flags()) : CLASSIC_MODE;
168 }
169 
170 
LocalCount()171 int ScopeInfo::LocalCount() {
172   return StackLocalCount() + ContextLocalCount();
173 }
174 
175 
StackSlotCount()176 int ScopeInfo::StackSlotCount() {
177   if (length() > 0) {
178     bool function_name_stack_slot =
179         FunctionVariableField::decode(Flags()) == STACK;
180     return StackLocalCount() + (function_name_stack_slot ? 1 : 0);
181   }
182   return 0;
183 }
184 
185 
ContextLength()186 int ScopeInfo::ContextLength() {
187   if (length() > 0) {
188     int context_locals = ContextLocalCount();
189     bool function_name_context_slot =
190         FunctionVariableField::decode(Flags()) == CONTEXT;
191     bool has_context = context_locals > 0 ||
192         function_name_context_slot ||
193         Type() == WITH_SCOPE ||
194         (Type() == FUNCTION_SCOPE && CallsEval());
195     if (has_context) {
196       return Context::MIN_CONTEXT_SLOTS + context_locals +
197           (function_name_context_slot ? 1 : 0);
198     }
199   }
200   return 0;
201 }
202 
203 
HasFunctionName()204 bool ScopeInfo::HasFunctionName() {
205   if (length() > 0) {
206     return NONE != FunctionVariableField::decode(Flags());
207   } else {
208     return false;
209   }
210 }
211 
212 
HasHeapAllocatedLocals()213 bool ScopeInfo::HasHeapAllocatedLocals() {
214   if (length() > 0) {
215     return ContextLocalCount() > 0;
216   } else {
217     return false;
218   }
219 }
220 
221 
HasContext()222 bool ScopeInfo::HasContext() {
223   if (length() > 0) {
224     return ContextLength() > 0;
225   } else {
226     return false;
227   }
228 }
229 
230 
FunctionName()231 String* ScopeInfo::FunctionName() {
232   ASSERT(HasFunctionName());
233   return String::cast(get(FunctionNameEntryIndex()));
234 }
235 
236 
ParameterName(int var)237 String* ScopeInfo::ParameterName(int var) {
238   ASSERT(0 <= var && var < ParameterCount());
239   int info_index = ParameterEntriesIndex() + var;
240   return String::cast(get(info_index));
241 }
242 
243 
LocalName(int var)244 String* ScopeInfo::LocalName(int var) {
245   ASSERT(0 <= var && var < LocalCount());
246   ASSERT(StackLocalEntriesIndex() + StackLocalCount() ==
247          ContextLocalNameEntriesIndex());
248   int info_index = StackLocalEntriesIndex() + var;
249   return String::cast(get(info_index));
250 }
251 
252 
StackLocalName(int var)253 String* ScopeInfo::StackLocalName(int var) {
254   ASSERT(0 <= var && var < StackLocalCount());
255   int info_index = StackLocalEntriesIndex() + var;
256   return String::cast(get(info_index));
257 }
258 
259 
ContextLocalName(int var)260 String* ScopeInfo::ContextLocalName(int var) {
261   ASSERT(0 <= var && var < ContextLocalCount());
262   int info_index = ContextLocalNameEntriesIndex() + var;
263   return String::cast(get(info_index));
264 }
265 
266 
ContextLocalMode(int var)267 VariableMode ScopeInfo::ContextLocalMode(int var) {
268   ASSERT(0 <= var && var < ContextLocalCount());
269   int info_index = ContextLocalInfoEntriesIndex() + var;
270   int value = Smi::cast(get(info_index))->value();
271   return ContextLocalMode::decode(value);
272 }
273 
274 
ContextLocalInitFlag(int var)275 InitializationFlag ScopeInfo::ContextLocalInitFlag(int var) {
276   ASSERT(0 <= var && var < ContextLocalCount());
277   int info_index = ContextLocalInfoEntriesIndex() + var;
278   int value = Smi::cast(get(info_index))->value();
279   return ContextLocalInitFlag::decode(value);
280 }
281 
282 
StackSlotIndex(String * name)283 int ScopeInfo::StackSlotIndex(String* name) {
284   ASSERT(name->IsSymbol());
285   if (length() > 0) {
286     int start = StackLocalEntriesIndex();
287     int end = StackLocalEntriesIndex() + StackLocalCount();
288     for (int i = start; i < end; ++i) {
289       if (name == get(i)) {
290         return i - start;
291       }
292     }
293   }
294   return -1;
295 }
296 
297 
ContextSlotIndex(String * name,VariableMode * mode,InitializationFlag * init_flag)298 int ScopeInfo::ContextSlotIndex(String* name,
299                                 VariableMode* mode,
300                                 InitializationFlag* init_flag) {
301   ASSERT(name->IsSymbol());
302   ASSERT(mode != NULL);
303   ASSERT(init_flag != NULL);
304   if (length() > 0) {
305     ContextSlotCache* context_slot_cache = GetIsolate()->context_slot_cache();
306     int result = context_slot_cache->Lookup(this, name, mode, init_flag);
307     if (result != ContextSlotCache::kNotFound) {
308       ASSERT(result < ContextLength());
309       return result;
310     }
311 
312     int start = ContextLocalNameEntriesIndex();
313     int end = ContextLocalNameEntriesIndex() + ContextLocalCount();
314     for (int i = start; i < end; ++i) {
315       if (name == get(i)) {
316         int var = i - start;
317         *mode = ContextLocalMode(var);
318         *init_flag = ContextLocalInitFlag(var);
319         result = Context::MIN_CONTEXT_SLOTS + var;
320         context_slot_cache->Update(this, name, *mode, *init_flag, result);
321         ASSERT(result < ContextLength());
322         return result;
323       }
324     }
325     context_slot_cache->Update(this, name, INTERNAL, kNeedsInitialization, -1);
326   }
327   return -1;
328 }
329 
330 
ParameterIndex(String * name)331 int ScopeInfo::ParameterIndex(String* name) {
332   ASSERT(name->IsSymbol());
333   if (length() > 0) {
334     // We must read parameters from the end since for
335     // multiply declared parameters the value of the
336     // last declaration of that parameter is used
337     // inside a function (and thus we need to look
338     // at the last index). Was bug# 1110337.
339     int start = ParameterEntriesIndex();
340     int end = ParameterEntriesIndex() + ParameterCount();
341     for (int i = end - 1; i >= start; --i) {
342       if (name == get(i)) {
343         return i - start;
344       }
345     }
346   }
347   return -1;
348 }
349 
350 
FunctionContextSlotIndex(String * name,VariableMode * mode)351 int ScopeInfo::FunctionContextSlotIndex(String* name, VariableMode* mode) {
352   ASSERT(name->IsSymbol());
353   ASSERT(mode != NULL);
354   if (length() > 0) {
355     if (FunctionVariableField::decode(Flags()) == CONTEXT &&
356         FunctionName() == name) {
357       *mode = FunctionVariableMode::decode(Flags());
358       return Smi::cast(get(FunctionNameEntryIndex() + 1))->value();
359     }
360   }
361   return -1;
362 }
363 
364 
ParameterEntriesIndex()365 int ScopeInfo::ParameterEntriesIndex() {
366   ASSERT(length() > 0);
367   return kVariablePartIndex;
368 }
369 
370 
StackLocalEntriesIndex()371 int ScopeInfo::StackLocalEntriesIndex() {
372   return ParameterEntriesIndex() + ParameterCount();
373 }
374 
375 
ContextLocalNameEntriesIndex()376 int ScopeInfo::ContextLocalNameEntriesIndex() {
377   return StackLocalEntriesIndex() + StackLocalCount();
378 }
379 
380 
ContextLocalInfoEntriesIndex()381 int ScopeInfo::ContextLocalInfoEntriesIndex() {
382   return ContextLocalNameEntriesIndex() + ContextLocalCount();
383 }
384 
385 
FunctionNameEntryIndex()386 int ScopeInfo::FunctionNameEntryIndex() {
387   return ContextLocalInfoEntriesIndex() + ContextLocalCount();
388 }
389 
390 
Hash(Object * data,String * name)391 int ContextSlotCache::Hash(Object* data, String* name) {
392   // Uses only lower 32 bits if pointers are larger.
393   uintptr_t addr_hash =
394       static_cast<uint32_t>(reinterpret_cast<uintptr_t>(data)) >> 2;
395   return static_cast<int>((addr_hash ^ name->Hash()) % kLength);
396 }
397 
398 
Lookup(Object * data,String * name,VariableMode * mode,InitializationFlag * init_flag)399 int ContextSlotCache::Lookup(Object* data,
400                              String* name,
401                              VariableMode* mode,
402                              InitializationFlag* init_flag) {
403   int index = Hash(data, name);
404   Key& key = keys_[index];
405   if ((key.data == data) && key.name->Equals(name)) {
406     Value result(values_[index]);
407     if (mode != NULL) *mode = result.mode();
408     if (init_flag != NULL) *init_flag = result.initialization_flag();
409     return result.index() + kNotFound;
410   }
411   return kNotFound;
412 }
413 
414 
Update(Object * data,String * name,VariableMode mode,InitializationFlag init_flag,int slot_index)415 void ContextSlotCache::Update(Object* data,
416                               String* name,
417                               VariableMode mode,
418                               InitializationFlag init_flag,
419                               int slot_index) {
420   String* symbol;
421   ASSERT(slot_index > kNotFound);
422   if (HEAP->LookupSymbolIfExists(name, &symbol)) {
423     int index = Hash(data, symbol);
424     Key& key = keys_[index];
425     key.data = data;
426     key.name = symbol;
427     // Please note value only takes a uint as index.
428     values_[index] = Value(mode, init_flag, slot_index - kNotFound).raw();
429 #ifdef DEBUG
430     ValidateEntry(data, name, mode, init_flag, slot_index);
431 #endif
432   }
433 }
434 
435 
Clear()436 void ContextSlotCache::Clear() {
437   for (int index = 0; index < kLength; index++) keys_[index].data = NULL;
438 }
439 
440 
441 #ifdef DEBUG
442 
ValidateEntry(Object * data,String * name,VariableMode mode,InitializationFlag init_flag,int slot_index)443 void ContextSlotCache::ValidateEntry(Object* data,
444                                      String* name,
445                                      VariableMode mode,
446                                      InitializationFlag init_flag,
447                                      int slot_index) {
448   String* symbol;
449   if (HEAP->LookupSymbolIfExists(name, &symbol)) {
450     int index = Hash(data, name);
451     Key& key = keys_[index];
452     ASSERT(key.data == data);
453     ASSERT(key.name->Equals(name));
454     Value result(values_[index]);
455     ASSERT(result.mode() == mode);
456     ASSERT(result.initialization_flag() == init_flag);
457     ASSERT(result.index() + kNotFound == slot_index);
458   }
459 }
460 
461 
PrintList(const char * list_name,int nof_internal_slots,int start,int end,ScopeInfo * scope_info)462 static void PrintList(const char* list_name,
463                       int nof_internal_slots,
464                       int start,
465                       int end,
466                       ScopeInfo* scope_info) {
467   if (start < end) {
468     PrintF("\n  // %s\n", list_name);
469     if (nof_internal_slots > 0) {
470       PrintF("  %2d - %2d [internal slots]\n", 0 , nof_internal_slots - 1);
471     }
472     for (int i = nof_internal_slots; start < end; ++i, ++start) {
473       PrintF("  %2d ", i);
474       String::cast(scope_info->get(start))->ShortPrint();
475       PrintF("\n");
476     }
477   }
478 }
479 
480 
Print()481 void ScopeInfo::Print() {
482   PrintF("ScopeInfo ");
483   if (HasFunctionName()) {
484     FunctionName()->ShortPrint();
485   } else {
486     PrintF("/* no function name */");
487   }
488   PrintF("{");
489 
490   PrintList("parameters", 0,
491             ParameterEntriesIndex(),
492             ParameterEntriesIndex() + ParameterCount(),
493             this);
494   PrintList("stack slots", 0,
495             StackLocalEntriesIndex(),
496             StackLocalEntriesIndex() + StackLocalCount(),
497             this);
498   PrintList("context slots",
499             Context::MIN_CONTEXT_SLOTS,
500             ContextLocalNameEntriesIndex(),
501             ContextLocalNameEntriesIndex() + ContextLocalCount(),
502             this);
503 
504   PrintF("}\n");
505 }
506 #endif  // DEBUG
507 
508 } }  // namespace v8::internal
509