• 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 namespace v8 {
36 namespace internal {
37 
38 
Create(Scope * scope,Zone * zone)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 
Empty(Isolate * isolate)151 ScopeInfo* ScopeInfo::Empty(Isolate* isolate) {
152   return reinterpret_cast<ScopeInfo*>(isolate->heap()->empty_fixed_array());
153 }
154 
155 
scope_type()156 ScopeType ScopeInfo::scope_type() {
157   ASSERT(length() > 0);
158   return ScopeTypeField::decode(Flags());
159 }
160 
161 
CallsEval()162 bool ScopeInfo::CallsEval() {
163   return length() > 0 && CallsEvalField::decode(Flags());
164 }
165 
166 
language_mode()167 LanguageMode ScopeInfo::language_mode() {
168   return length() > 0 ? LanguageModeField::decode(Flags()) : CLASSIC_MODE;
169 }
170 
171 
LocalCount()172 int ScopeInfo::LocalCount() {
173   return StackLocalCount() + ContextLocalCount();
174 }
175 
176 
StackSlotCount()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 
ContextLength()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 
HasFunctionName()206 bool ScopeInfo::HasFunctionName() {
207   if (length() > 0) {
208     return NONE != FunctionVariableField::decode(Flags());
209   } else {
210     return false;
211   }
212 }
213 
214 
HasHeapAllocatedLocals()215 bool ScopeInfo::HasHeapAllocatedLocals() {
216   if (length() > 0) {
217     return ContextLocalCount() > 0;
218   } else {
219     return false;
220   }
221 }
222 
223 
HasContext()224 bool ScopeInfo::HasContext() {
225   return ContextLength() > 0;
226 }
227 
228 
FunctionName()229 String* ScopeInfo::FunctionName() {
230   ASSERT(HasFunctionName());
231   return String::cast(get(FunctionNameEntryIndex()));
232 }
233 
234 
ParameterName(int var)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 
LocalName(int var)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 
StackLocalName(int var)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 
ContextLocalName(int var)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 
ContextLocalMode(int var)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 
ContextLocalInitFlag(int var)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 
StackSlotIndex(String * name)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 
ContextSlotIndex(String * name,VariableMode * mode,InitializationFlag * init_flag)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 
ParameterIndex(String * name)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 
FunctionContextSlotIndex(String * name,VariableMode * mode)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 
CopyContextLocalsToScopeObject(Handle<ScopeInfo> scope_info,Handle<Context> context,Handle<JSObject> scope_object)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 
ParameterEntriesIndex()388 int ScopeInfo::ParameterEntriesIndex() {
389   ASSERT(length() > 0);
390   return kVariablePartIndex;
391 }
392 
393 
StackLocalEntriesIndex()394 int ScopeInfo::StackLocalEntriesIndex() {
395   return ParameterEntriesIndex() + ParameterCount();
396 }
397 
398 
ContextLocalNameEntriesIndex()399 int ScopeInfo::ContextLocalNameEntriesIndex() {
400   return StackLocalEntriesIndex() + StackLocalCount();
401 }
402 
403 
ContextLocalInfoEntriesIndex()404 int ScopeInfo::ContextLocalInfoEntriesIndex() {
405   return ContextLocalNameEntriesIndex() + ContextLocalCount();
406 }
407 
408 
FunctionNameEntryIndex()409 int ScopeInfo::FunctionNameEntryIndex() {
410   return ContextLocalInfoEntriesIndex() + ContextLocalCount();
411 }
412 
413 
Hash(Object * data,String * name)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 
Lookup(Object * data,String * name,VariableMode * mode,InitializationFlag * init_flag)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 
Update(Object * data,String * name,VariableMode mode,InitializationFlag init_flag,int slot_index)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 
Clear()460 void ContextSlotCache::Clear() {
461   for (int index = 0; index < kLength; index++) keys_[index].data = NULL;
462 }
463 
464 
465 #ifdef DEBUG
466 
ValidateEntry(Object * data,String * name,VariableMode mode,InitializationFlag init_flag,int slot_index)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 
PrintList(const char * list_name,int nof_internal_slots,int start,int end,ScopeInfo * scope_info)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 
Print()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 
Create(Isolate * isolate,Interface * interface,Scope * scope)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