• 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 "src/ast/scopeinfo.h"
6 
7 #include <stdlib.h>
8 
9 #include "src/ast/scopes.h"
10 #include "src/bootstrapper.h"
11 
12 namespace v8 {
13 namespace internal {
14 
15 
Create(Isolate * isolate,Zone * zone,Scope * scope)16 Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate, Zone* zone,
17                                     Scope* scope) {
18   // Collect stack and context locals.
19   ZoneList<Variable*> stack_locals(scope->StackLocalCount(), zone);
20   ZoneList<Variable*> context_locals(scope->ContextLocalCount(), zone);
21   ZoneList<Variable*> context_globals(scope->ContextGlobalCount(), zone);
22 
23   scope->CollectStackAndContextLocals(&stack_locals, &context_locals,
24                                       &context_globals);
25   const int stack_local_count = stack_locals.length();
26   const int context_local_count = context_locals.length();
27   const int context_global_count = context_globals.length();
28   // Make sure we allocate the correct amount.
29   DCHECK_EQ(scope->ContextLocalCount(), context_local_count);
30   DCHECK_EQ(scope->ContextGlobalCount(), context_global_count);
31 
32   // Determine use and location of the "this" binding if it is present.
33   VariableAllocationInfo receiver_info;
34   if (scope->has_this_declaration()) {
35     Variable* var = scope->receiver();
36     if (!var->is_used()) {
37       receiver_info = UNUSED;
38     } else if (var->IsContextSlot()) {
39       receiver_info = CONTEXT;
40     } else {
41       DCHECK(var->IsParameter());
42       receiver_info = STACK;
43     }
44   } else {
45     receiver_info = NONE;
46   }
47 
48   bool has_new_target = scope->new_target_var() != nullptr;
49 
50   // Determine use and location of the function variable if it is present.
51   VariableAllocationInfo 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       DCHECK(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   DCHECK(context_global_count == 0 || scope->scope_type() == SCRIPT_SCOPE);
69 
70   const bool has_function_name = function_name_info != NONE;
71   const bool has_receiver = receiver_info == STACK || receiver_info == CONTEXT;
72   const int parameter_count = scope->num_parameters();
73   const int length = kVariablePartIndex + parameter_count +
74                      (1 + stack_local_count) + 2 * context_local_count +
75                      2 * context_global_count +
76                      (has_receiver ? 1 : 0) + (has_function_name ? 2 : 0);
77 
78   Factory* factory = isolate->factory();
79   Handle<ScopeInfo> scope_info = factory->NewScopeInfo(length);
80 
81   bool has_simple_parameters =
82       scope->is_function_scope() && scope->has_simple_parameters();
83 
84   // Encode the flags.
85   int flags = ScopeTypeField::encode(scope->scope_type()) |
86               CallsEvalField::encode(scope->calls_eval()) |
87               LanguageModeField::encode(scope->language_mode()) |
88               DeclarationScopeField::encode(scope->is_declaration_scope()) |
89               ReceiverVariableField::encode(receiver_info) |
90               HasNewTargetField::encode(has_new_target) |
91               FunctionVariableField::encode(function_name_info) |
92               FunctionVariableMode::encode(function_variable_mode) |
93               AsmModuleField::encode(scope->asm_module()) |
94               AsmFunctionField::encode(scope->asm_function()) |
95               HasSimpleParametersField::encode(has_simple_parameters) |
96               FunctionKindField::encode(scope->function_kind());
97   scope_info->SetFlags(flags);
98   scope_info->SetParameterCount(parameter_count);
99   scope_info->SetStackLocalCount(stack_local_count);
100   scope_info->SetContextLocalCount(context_local_count);
101   scope_info->SetContextGlobalCount(context_global_count);
102 
103   int index = kVariablePartIndex;
104   // Add parameters.
105   DCHECK(index == scope_info->ParameterEntriesIndex());
106   for (int i = 0; i < parameter_count; ++i) {
107     scope_info->set(index++, *scope->parameter(i)->name());
108   }
109 
110   // Add stack locals' names. We are assuming that the stack locals'
111   // slots are allocated in increasing order, so we can simply add
112   // them to the ScopeInfo object.
113   int first_slot_index;
114   if (stack_local_count > 0) {
115     first_slot_index = stack_locals[0]->index();
116   } else {
117     first_slot_index = 0;
118   }
119   DCHECK(index == scope_info->StackLocalFirstSlotIndex());
120   scope_info->set(index++, Smi::FromInt(first_slot_index));
121   DCHECK(index == scope_info->StackLocalEntriesIndex());
122   for (int i = 0; i < stack_local_count; ++i) {
123     DCHECK(stack_locals[i]->index() == first_slot_index + i);
124     scope_info->set(index++, *stack_locals[i]->name());
125   }
126 
127   // Due to usage analysis, context-allocated locals are not necessarily in
128   // increasing order: Some of them may be parameters which are allocated before
129   // the non-parameter locals. When the non-parameter locals are sorted
130   // according to usage, the allocated slot indices may not be in increasing
131   // order with the variable list anymore. Thus, we first need to sort them by
132   // context slot index before adding them to the ScopeInfo object.
133   context_locals.Sort(&Variable::CompareIndex);
134 
135   // Add context locals' names.
136   DCHECK(index == scope_info->ContextLocalNameEntriesIndex());
137   for (int i = 0; i < context_local_count; ++i) {
138     scope_info->set(index++, *context_locals[i]->name());
139   }
140 
141   // Add context globals' names.
142   DCHECK(index == scope_info->ContextGlobalNameEntriesIndex());
143   for (int i = 0; i < context_global_count; ++i) {
144     scope_info->set(index++, *context_globals[i]->name());
145   }
146 
147   // Add context locals' info.
148   DCHECK(index == scope_info->ContextLocalInfoEntriesIndex());
149   for (int i = 0; i < context_local_count; ++i) {
150     Variable* var = context_locals[i];
151     uint32_t value =
152         ContextLocalMode::encode(var->mode()) |
153         ContextLocalInitFlag::encode(var->initialization_flag()) |
154         ContextLocalMaybeAssignedFlag::encode(var->maybe_assigned());
155     scope_info->set(index++, Smi::FromInt(value));
156   }
157 
158   // Add context globals' info.
159   DCHECK(index == scope_info->ContextGlobalInfoEntriesIndex());
160   for (int i = 0; i < context_global_count; ++i) {
161     Variable* var = context_globals[i];
162     // TODO(ishell): do we need this kind of info for globals here?
163     uint32_t value =
164         ContextLocalMode::encode(var->mode()) |
165         ContextLocalInitFlag::encode(var->initialization_flag()) |
166         ContextLocalMaybeAssignedFlag::encode(var->maybe_assigned());
167     scope_info->set(index++, Smi::FromInt(value));
168   }
169 
170   // If the receiver is allocated, add its index.
171   DCHECK(index == scope_info->ReceiverEntryIndex());
172   if (has_receiver) {
173     int var_index = scope->receiver()->index();
174     scope_info->set(index++, Smi::FromInt(var_index));
175     // ?? DCHECK(receiver_info != CONTEXT || var_index ==
176     // scope_info->ContextLength() - 1);
177   }
178 
179   // If present, add the function variable name and its index.
180   DCHECK(index == scope_info->FunctionNameEntryIndex());
181   if (has_function_name) {
182     int var_index = scope->function()->proxy()->var()->index();
183     scope_info->set(index++, *scope->function()->proxy()->name());
184     scope_info->set(index++, Smi::FromInt(var_index));
185     DCHECK(function_name_info != CONTEXT ||
186            var_index == scope_info->ContextLength() - 1);
187   }
188 
189   DCHECK(index == scope_info->length());
190   DCHECK(scope->num_parameters() == scope_info->ParameterCount());
191   DCHECK(scope->num_heap_slots() == scope_info->ContextLength() ||
192          (scope->num_heap_slots() == kVariablePartIndex &&
193           scope_info->ContextLength() == 0));
194   return scope_info;
195 }
196 
197 
CreateGlobalThisBinding(Isolate * isolate)198 Handle<ScopeInfo> ScopeInfo::CreateGlobalThisBinding(Isolate* isolate) {
199   DCHECK(isolate->bootstrapper()->IsActive());
200 
201   const int stack_local_count = 0;
202   const int context_local_count = 1;
203   const int context_global_count = 0;
204   const bool has_simple_parameters = true;
205   const VariableAllocationInfo receiver_info = CONTEXT;
206   const VariableAllocationInfo function_name_info = NONE;
207   const VariableMode function_variable_mode = VAR;
208   const bool has_function_name = false;
209   const bool has_receiver = true;
210   const int parameter_count = 0;
211   const int length = kVariablePartIndex + parameter_count +
212                      (1 + stack_local_count) + 2 * context_local_count +
213                      2 * context_global_count +
214                      (has_receiver ? 1 : 0) + (has_function_name ? 2 : 0);
215 
216   Factory* factory = isolate->factory();
217   Handle<ScopeInfo> scope_info = factory->NewScopeInfo(length);
218 
219   // Encode the flags.
220   int flags = ScopeTypeField::encode(SCRIPT_SCOPE) |
221               CallsEvalField::encode(false) |
222               LanguageModeField::encode(SLOPPY) |
223               DeclarationScopeField::encode(true) |
224               ReceiverVariableField::encode(receiver_info) |
225               FunctionVariableField::encode(function_name_info) |
226               FunctionVariableMode::encode(function_variable_mode) |
227               AsmModuleField::encode(false) | AsmFunctionField::encode(false) |
228               HasSimpleParametersField::encode(has_simple_parameters) |
229               FunctionKindField::encode(FunctionKind::kNormalFunction);
230   scope_info->SetFlags(flags);
231   scope_info->SetParameterCount(parameter_count);
232   scope_info->SetStackLocalCount(stack_local_count);
233   scope_info->SetContextLocalCount(context_local_count);
234   scope_info->SetContextGlobalCount(context_global_count);
235 
236   int index = kVariablePartIndex;
237   const int first_slot_index = 0;
238   DCHECK(index == scope_info->StackLocalFirstSlotIndex());
239   scope_info->set(index++, Smi::FromInt(first_slot_index));
240   DCHECK(index == scope_info->StackLocalEntriesIndex());
241 
242   // Here we add info for context-allocated "this".
243   DCHECK(index == scope_info->ContextLocalNameEntriesIndex());
244   scope_info->set(index++, *isolate->factory()->this_string());
245   DCHECK(index == scope_info->ContextLocalInfoEntriesIndex());
246   const uint32_t value = ContextLocalMode::encode(CONST) |
247                          ContextLocalInitFlag::encode(kCreatedInitialized) |
248                          ContextLocalMaybeAssignedFlag::encode(kNotAssigned);
249   scope_info->set(index++, Smi::FromInt(value));
250 
251   // And here we record that this scopeinfo binds a receiver.
252   DCHECK(index == scope_info->ReceiverEntryIndex());
253   const int receiver_index = Context::MIN_CONTEXT_SLOTS + 0;
254   scope_info->set(index++, Smi::FromInt(receiver_index));
255 
256   DCHECK(index == scope_info->FunctionNameEntryIndex());
257 
258   DCHECK_EQ(index, scope_info->length());
259   DCHECK_EQ(scope_info->ParameterCount(), 0);
260   DCHECK_EQ(scope_info->ContextLength(), Context::MIN_CONTEXT_SLOTS + 1);
261 
262   return scope_info;
263 }
264 
265 
Empty(Isolate * isolate)266 ScopeInfo* ScopeInfo::Empty(Isolate* isolate) {
267   return reinterpret_cast<ScopeInfo*>(isolate->heap()->empty_fixed_array());
268 }
269 
270 
scope_type()271 ScopeType ScopeInfo::scope_type() {
272   DCHECK(length() > 0);
273   return ScopeTypeField::decode(Flags());
274 }
275 
276 
CallsEval()277 bool ScopeInfo::CallsEval() {
278   return length() > 0 && CallsEvalField::decode(Flags());
279 }
280 
281 
language_mode()282 LanguageMode ScopeInfo::language_mode() {
283   return length() > 0 ? LanguageModeField::decode(Flags()) : SLOPPY;
284 }
285 
286 
is_declaration_scope()287 bool ScopeInfo::is_declaration_scope() {
288   return DeclarationScopeField::decode(Flags());
289 }
290 
291 
LocalCount()292 int ScopeInfo::LocalCount() {
293   return StackLocalCount() + ContextLocalCount();
294 }
295 
296 
StackSlotCount()297 int ScopeInfo::StackSlotCount() {
298   if (length() > 0) {
299     bool function_name_stack_slot =
300         FunctionVariableField::decode(Flags()) == STACK;
301     return StackLocalCount() + (function_name_stack_slot ? 1 : 0);
302   }
303   return 0;
304 }
305 
306 
ContextLength()307 int ScopeInfo::ContextLength() {
308   if (length() > 0) {
309     int context_locals = ContextLocalCount();
310     int context_globals = ContextGlobalCount();
311     bool function_name_context_slot =
312         FunctionVariableField::decode(Flags()) == CONTEXT;
313     bool has_context = context_locals > 0 || context_globals > 0 ||
314                        function_name_context_slot ||
315                        scope_type() == WITH_SCOPE ||
316                        (scope_type() == BLOCK_SCOPE && CallsSloppyEval() &&
317                            is_declaration_scope()) ||
318                        (scope_type() == FUNCTION_SCOPE && CallsSloppyEval()) ||
319                        scope_type() == MODULE_SCOPE;
320 
321     if (has_context) {
322       return Context::MIN_CONTEXT_SLOTS + context_locals + context_globals +
323              (function_name_context_slot ? 1 : 0);
324     }
325   }
326   return 0;
327 }
328 
329 
HasReceiver()330 bool ScopeInfo::HasReceiver() {
331   if (length() > 0) {
332     return NONE != ReceiverVariableField::decode(Flags());
333   } else {
334     return false;
335   }
336 }
337 
338 
HasAllocatedReceiver()339 bool ScopeInfo::HasAllocatedReceiver() {
340   if (length() > 0) {
341     VariableAllocationInfo allocation = ReceiverVariableField::decode(Flags());
342     return allocation == STACK || allocation == CONTEXT;
343   } else {
344     return false;
345   }
346 }
347 
348 
HasNewTarget()349 bool ScopeInfo::HasNewTarget() { return HasNewTargetField::decode(Flags()); }
350 
351 
HasFunctionName()352 bool ScopeInfo::HasFunctionName() {
353   if (length() > 0) {
354     return NONE != FunctionVariableField::decode(Flags());
355   } else {
356     return false;
357   }
358 }
359 
360 
HasHeapAllocatedLocals()361 bool ScopeInfo::HasHeapAllocatedLocals() {
362   if (length() > 0) {
363     return ContextLocalCount() > 0;
364   } else {
365     return false;
366   }
367 }
368 
369 
HasContext()370 bool ScopeInfo::HasContext() {
371   return ContextLength() > 0;
372 }
373 
374 
FunctionName()375 String* ScopeInfo::FunctionName() {
376   DCHECK(HasFunctionName());
377   return String::cast(get(FunctionNameEntryIndex()));
378 }
379 
380 
ParameterName(int var)381 String* ScopeInfo::ParameterName(int var) {
382   DCHECK(0 <= var && var < ParameterCount());
383   int info_index = ParameterEntriesIndex() + var;
384   return String::cast(get(info_index));
385 }
386 
387 
LocalName(int var)388 String* ScopeInfo::LocalName(int var) {
389   DCHECK(0 <= var && var < LocalCount());
390   DCHECK(StackLocalEntriesIndex() + StackLocalCount() ==
391          ContextLocalNameEntriesIndex());
392   int info_index = StackLocalEntriesIndex() + var;
393   return String::cast(get(info_index));
394 }
395 
396 
StackLocalName(int var)397 String* ScopeInfo::StackLocalName(int var) {
398   DCHECK(0 <= var && var < StackLocalCount());
399   int info_index = StackLocalEntriesIndex() + var;
400   return String::cast(get(info_index));
401 }
402 
403 
StackLocalIndex(int var)404 int ScopeInfo::StackLocalIndex(int var) {
405   DCHECK(0 <= var && var < StackLocalCount());
406   int first_slot_index = Smi::cast(get(StackLocalFirstSlotIndex()))->value();
407   return first_slot_index + var;
408 }
409 
410 
ContextLocalName(int var)411 String* ScopeInfo::ContextLocalName(int var) {
412   DCHECK(0 <= var && var < ContextLocalCount() + ContextGlobalCount());
413   int info_index = ContextLocalNameEntriesIndex() + var;
414   return String::cast(get(info_index));
415 }
416 
417 
ContextLocalMode(int var)418 VariableMode ScopeInfo::ContextLocalMode(int var) {
419   DCHECK(0 <= var && var < ContextLocalCount() + ContextGlobalCount());
420   int info_index = ContextLocalInfoEntriesIndex() + var;
421   int value = Smi::cast(get(info_index))->value();
422   return ContextLocalMode::decode(value);
423 }
424 
425 
ContextLocalInitFlag(int var)426 InitializationFlag ScopeInfo::ContextLocalInitFlag(int var) {
427   DCHECK(0 <= var && var < ContextLocalCount() + ContextGlobalCount());
428   int info_index = ContextLocalInfoEntriesIndex() + var;
429   int value = Smi::cast(get(info_index))->value();
430   return ContextLocalInitFlag::decode(value);
431 }
432 
433 
ContextLocalMaybeAssignedFlag(int var)434 MaybeAssignedFlag ScopeInfo::ContextLocalMaybeAssignedFlag(int var) {
435   DCHECK(0 <= var && var < ContextLocalCount() + ContextGlobalCount());
436   int info_index = ContextLocalInfoEntriesIndex() + var;
437   int value = Smi::cast(get(info_index))->value();
438   return ContextLocalMaybeAssignedFlag::decode(value);
439 }
440 
VariableIsSynthetic(String * name)441 bool ScopeInfo::VariableIsSynthetic(String* name) {
442   // There's currently no flag stored on the ScopeInfo to indicate that a
443   // variable is a compiler-introduced temporary. However, to avoid conflict
444   // with user declarations, the current temporaries like .generator_object and
445   // .result start with a dot, so we can use that as a flag. It's a hack!
446   return name->length() == 0 || name->Get(0) == '.' ||
447          name->Equals(name->GetHeap()->this_string());
448 }
449 
450 
StackSlotIndex(String * name)451 int ScopeInfo::StackSlotIndex(String* name) {
452   DCHECK(name->IsInternalizedString());
453   if (length() > 0) {
454     int first_slot_index = Smi::cast(get(StackLocalFirstSlotIndex()))->value();
455     int start = StackLocalEntriesIndex();
456     int end = StackLocalEntriesIndex() + StackLocalCount();
457     for (int i = start; i < end; ++i) {
458       if (name == get(i)) {
459         return i - start + first_slot_index;
460       }
461     }
462   }
463   return -1;
464 }
465 
466 
ContextSlotIndex(Handle<ScopeInfo> scope_info,Handle<String> name,VariableMode * mode,InitializationFlag * init_flag,MaybeAssignedFlag * maybe_assigned_flag)467 int ScopeInfo::ContextSlotIndex(Handle<ScopeInfo> scope_info,
468                                 Handle<String> name, VariableMode* mode,
469                                 InitializationFlag* init_flag,
470                                 MaybeAssignedFlag* maybe_assigned_flag) {
471   DCHECK(name->IsInternalizedString());
472   DCHECK(mode != NULL);
473   DCHECK(init_flag != NULL);
474   if (scope_info->length() > 0) {
475     ContextSlotCache* context_slot_cache =
476         scope_info->GetIsolate()->context_slot_cache();
477     int result = context_slot_cache->Lookup(*scope_info, *name, mode, init_flag,
478                                             maybe_assigned_flag);
479     if (result != ContextSlotCache::kNotFound) {
480       DCHECK(result < scope_info->ContextLength());
481       return result;
482     }
483 
484     int start = scope_info->ContextLocalNameEntriesIndex();
485     int end = scope_info->ContextLocalNameEntriesIndex() +
486               scope_info->ContextLocalCount();
487     for (int i = start; i < end; ++i) {
488       if (*name == scope_info->get(i)) {
489         int var = i - start;
490         *mode = scope_info->ContextLocalMode(var);
491         *init_flag = scope_info->ContextLocalInitFlag(var);
492         *maybe_assigned_flag = scope_info->ContextLocalMaybeAssignedFlag(var);
493         result = Context::MIN_CONTEXT_SLOTS + var;
494 
495         context_slot_cache->Update(scope_info, name, *mode, *init_flag,
496                                    *maybe_assigned_flag, result);
497         DCHECK(result < scope_info->ContextLength());
498         return result;
499       }
500     }
501     // Cache as not found. Mode, init flag and maybe assigned flag don't matter.
502     context_slot_cache->Update(scope_info, name, TEMPORARY,
503                                kNeedsInitialization, kNotAssigned, -1);
504   }
505   return -1;
506 }
507 
508 
ContextGlobalSlotIndex(Handle<ScopeInfo> scope_info,Handle<String> name,VariableMode * mode,InitializationFlag * init_flag,MaybeAssignedFlag * maybe_assigned_flag)509 int ScopeInfo::ContextGlobalSlotIndex(Handle<ScopeInfo> scope_info,
510                                       Handle<String> name, VariableMode* mode,
511                                       InitializationFlag* init_flag,
512                                       MaybeAssignedFlag* maybe_assigned_flag) {
513   DCHECK(name->IsInternalizedString());
514   DCHECK(mode != NULL);
515   DCHECK(init_flag != NULL);
516   if (scope_info->length() > 0) {
517     // This is to ensure that ContextLocalMode() and co. queries would work.
518     DCHECK_EQ(scope_info->ContextGlobalNameEntriesIndex(),
519               scope_info->ContextLocalNameEntriesIndex() +
520                   scope_info->ContextLocalCount());
521     int base = scope_info->ContextLocalNameEntriesIndex();
522     int start = scope_info->ContextGlobalNameEntriesIndex();
523     int end = scope_info->ContextGlobalNameEntriesIndex() +
524               scope_info->ContextGlobalCount();
525     for (int i = start; i < end; ++i) {
526       if (*name == scope_info->get(i)) {
527         int var = i - base;
528         *mode = scope_info->ContextLocalMode(var);
529         *init_flag = scope_info->ContextLocalInitFlag(var);
530         *maybe_assigned_flag = scope_info->ContextLocalMaybeAssignedFlag(var);
531         int result = Context::MIN_CONTEXT_SLOTS + var;
532         DCHECK(result < scope_info->ContextLength());
533         return result;
534       }
535     }
536   }
537   return -1;
538 }
539 
540 
ContextSlotName(int slot_index)541 String* ScopeInfo::ContextSlotName(int slot_index) {
542   int const var = slot_index - Context::MIN_CONTEXT_SLOTS;
543   DCHECK_LE(0, var);
544   DCHECK_LT(var, ContextLocalCount() + ContextGlobalCount());
545   return ContextLocalName(var);
546 }
547 
548 
ParameterIndex(String * name)549 int ScopeInfo::ParameterIndex(String* name) {
550   DCHECK(name->IsInternalizedString());
551   if (length() > 0) {
552     // We must read parameters from the end since for
553     // multiply declared parameters the value of the
554     // last declaration of that parameter is used
555     // inside a function (and thus we need to look
556     // at the last index). Was bug# 1110337.
557     int start = ParameterEntriesIndex();
558     int end = ParameterEntriesIndex() + ParameterCount();
559     for (int i = end - 1; i >= start; --i) {
560       if (name == get(i)) {
561         return i - start;
562       }
563     }
564   }
565   return -1;
566 }
567 
568 
ReceiverContextSlotIndex()569 int ScopeInfo::ReceiverContextSlotIndex() {
570   if (length() > 0 && ReceiverVariableField::decode(Flags()) == CONTEXT)
571     return Smi::cast(get(ReceiverEntryIndex()))->value();
572   return -1;
573 }
574 
575 
FunctionContextSlotIndex(String * name,VariableMode * mode)576 int ScopeInfo::FunctionContextSlotIndex(String* name, VariableMode* mode) {
577   DCHECK(name->IsInternalizedString());
578   DCHECK(mode != NULL);
579   if (length() > 0) {
580     if (FunctionVariableField::decode(Flags()) == CONTEXT &&
581         FunctionName() == name) {
582       *mode = FunctionVariableMode::decode(Flags());
583       return Smi::cast(get(FunctionNameEntryIndex() + 1))->value();
584     }
585   }
586   return -1;
587 }
588 
589 
function_kind()590 FunctionKind ScopeInfo::function_kind() {
591   return FunctionKindField::decode(Flags());
592 }
593 
594 
ParameterEntriesIndex()595 int ScopeInfo::ParameterEntriesIndex() {
596   DCHECK(length() > 0);
597   return kVariablePartIndex;
598 }
599 
600 
StackLocalFirstSlotIndex()601 int ScopeInfo::StackLocalFirstSlotIndex() {
602   return ParameterEntriesIndex() + ParameterCount();
603 }
604 
605 
StackLocalEntriesIndex()606 int ScopeInfo::StackLocalEntriesIndex() {
607   return StackLocalFirstSlotIndex() + 1;
608 }
609 
610 
ContextLocalNameEntriesIndex()611 int ScopeInfo::ContextLocalNameEntriesIndex() {
612   return StackLocalEntriesIndex() + StackLocalCount();
613 }
614 
615 
ContextGlobalNameEntriesIndex()616 int ScopeInfo::ContextGlobalNameEntriesIndex() {
617   return ContextLocalNameEntriesIndex() + ContextLocalCount();
618 }
619 
620 
ContextLocalInfoEntriesIndex()621 int ScopeInfo::ContextLocalInfoEntriesIndex() {
622   return ContextGlobalNameEntriesIndex() + ContextGlobalCount();
623 }
624 
625 
ContextGlobalInfoEntriesIndex()626 int ScopeInfo::ContextGlobalInfoEntriesIndex() {
627   return ContextLocalInfoEntriesIndex() + ContextLocalCount();
628 }
629 
630 
ReceiverEntryIndex()631 int ScopeInfo::ReceiverEntryIndex() {
632   return ContextGlobalInfoEntriesIndex() + ContextGlobalCount();
633 }
634 
635 
FunctionNameEntryIndex()636 int ScopeInfo::FunctionNameEntryIndex() {
637   return ReceiverEntryIndex() + (HasAllocatedReceiver() ? 1 : 0);
638 }
639 
640 
Hash(Object * data,String * name)641 int ContextSlotCache::Hash(Object* data, String* name) {
642   // Uses only lower 32 bits if pointers are larger.
643   uintptr_t addr_hash =
644       static_cast<uint32_t>(reinterpret_cast<uintptr_t>(data)) >> 2;
645   return static_cast<int>((addr_hash ^ name->Hash()) % kLength);
646 }
647 
648 
Lookup(Object * data,String * name,VariableMode * mode,InitializationFlag * init_flag,MaybeAssignedFlag * maybe_assigned_flag)649 int ContextSlotCache::Lookup(Object* data, String* name, VariableMode* mode,
650                              InitializationFlag* init_flag,
651                              MaybeAssignedFlag* maybe_assigned_flag) {
652   int index = Hash(data, name);
653   Key& key = keys_[index];
654   if ((key.data == data) && key.name->Equals(name)) {
655     Value result(values_[index]);
656     if (mode != NULL) *mode = result.mode();
657     if (init_flag != NULL) *init_flag = result.initialization_flag();
658     if (maybe_assigned_flag != NULL)
659       *maybe_assigned_flag = result.maybe_assigned_flag();
660     return result.index() + kNotFound;
661   }
662   return kNotFound;
663 }
664 
665 
Update(Handle<Object> data,Handle<String> name,VariableMode mode,InitializationFlag init_flag,MaybeAssignedFlag maybe_assigned_flag,int slot_index)666 void ContextSlotCache::Update(Handle<Object> data, Handle<String> name,
667                               VariableMode mode, InitializationFlag init_flag,
668                               MaybeAssignedFlag maybe_assigned_flag,
669                               int slot_index) {
670   DisallowHeapAllocation no_gc;
671   Handle<String> internalized_name;
672   DCHECK(slot_index > kNotFound);
673   if (StringTable::InternalizeStringIfExists(name->GetIsolate(), name).
674       ToHandle(&internalized_name)) {
675     int index = Hash(*data, *internalized_name);
676     Key& key = keys_[index];
677     key.data = *data;
678     key.name = *internalized_name;
679     // Please note value only takes a uint as index.
680     values_[index] = Value(mode, init_flag, maybe_assigned_flag,
681                            slot_index - kNotFound).raw();
682 #ifdef DEBUG
683     ValidateEntry(data, name, mode, init_flag, maybe_assigned_flag, slot_index);
684 #endif
685   }
686 }
687 
688 
Clear()689 void ContextSlotCache::Clear() {
690   for (int index = 0; index < kLength; index++) keys_[index].data = NULL;
691 }
692 
693 
694 #ifdef DEBUG
695 
ValidateEntry(Handle<Object> data,Handle<String> name,VariableMode mode,InitializationFlag init_flag,MaybeAssignedFlag maybe_assigned_flag,int slot_index)696 void ContextSlotCache::ValidateEntry(Handle<Object> data, Handle<String> name,
697                                      VariableMode mode,
698                                      InitializationFlag init_flag,
699                                      MaybeAssignedFlag maybe_assigned_flag,
700                                      int slot_index) {
701   DisallowHeapAllocation no_gc;
702   Handle<String> internalized_name;
703   if (StringTable::InternalizeStringIfExists(name->GetIsolate(), name).
704       ToHandle(&internalized_name)) {
705     int index = Hash(*data, *name);
706     Key& key = keys_[index];
707     DCHECK(key.data == *data);
708     DCHECK(key.name->Equals(*name));
709     Value result(values_[index]);
710     DCHECK(result.mode() == mode);
711     DCHECK(result.initialization_flag() == init_flag);
712     DCHECK(result.maybe_assigned_flag() == maybe_assigned_flag);
713     DCHECK(result.index() + kNotFound == slot_index);
714   }
715 }
716 
717 
PrintList(const char * list_name,int nof_internal_slots,int start,int end,ScopeInfo * scope_info)718 static void PrintList(const char* list_name,
719                       int nof_internal_slots,
720                       int start,
721                       int end,
722                       ScopeInfo* scope_info) {
723   if (start < end) {
724     PrintF("\n  // %s\n", list_name);
725     if (nof_internal_slots > 0) {
726       PrintF("  %2d - %2d [internal slots]\n", 0 , nof_internal_slots - 1);
727     }
728     for (int i = nof_internal_slots; start < end; ++i, ++start) {
729       PrintF("  %2d ", i);
730       String::cast(scope_info->get(start))->ShortPrint();
731       PrintF("\n");
732     }
733   }
734 }
735 
736 
Print()737 void ScopeInfo::Print() {
738   PrintF("ScopeInfo ");
739   if (HasFunctionName()) {
740     FunctionName()->ShortPrint();
741   } else {
742     PrintF("/* no function name */");
743   }
744   PrintF("{");
745 
746   if (length() > 0) {
747     PrintList("parameters", 0, ParameterEntriesIndex(),
748               ParameterEntriesIndex() + ParameterCount(), this);
749     PrintList("stack slots", 0, StackLocalEntriesIndex(),
750               StackLocalEntriesIndex() + StackLocalCount(), this);
751     PrintList("context slots", Context::MIN_CONTEXT_SLOTS,
752               ContextLocalNameEntriesIndex(),
753               ContextLocalNameEntriesIndex() + ContextLocalCount(), this);
754   }
755 
756   PrintF("}\n");
757 }
758 #endif  // DEBUG
759 
760 
761 //---------------------------------------------------------------------------
762 // ModuleInfo.
763 
Create(Isolate * isolate,ModuleDescriptor * descriptor,Scope * scope)764 Handle<ModuleInfo> ModuleInfo::Create(Isolate* isolate,
765                                       ModuleDescriptor* descriptor,
766                                       Scope* scope) {
767   Handle<ModuleInfo> info = Allocate(isolate, descriptor->Length());
768   info->set_host_index(descriptor->Index());
769   int i = 0;
770   for (ModuleDescriptor::Iterator it = descriptor->iterator(); !it.done();
771        it.Advance(), ++i) {
772     Variable* var = scope->LookupLocal(it.local_name());
773     info->set_name(i, *(it.export_name()->string()));
774     info->set_mode(i, var->mode());
775     DCHECK(var->index() >= 0);
776     info->set_index(i, var->index());
777   }
778   DCHECK(i == info->length());
779   return info;
780 }
781 
782 }  // namespace internal
783 }  // namespace v8
784