• 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/objects/scope-info.h"
8 
9 #include "src/ast/context-slot-cache.h"
10 #include "src/ast/scopes.h"
11 #include "src/ast/variables.h"
12 #include "src/bootstrapper.h"
13 #include "src/objects-inl.h"
14 
15 namespace v8 {
16 namespace internal {
17 
18 // An entry in ModuleVariableEntries consists of several slots:
19 enum ModuleVariableEntryOffset {
20   kModuleVariableNameOffset,
21   kModuleVariableIndexOffset,
22   kModuleVariablePropertiesOffset,
23   kModuleVariableEntryLength  // Sentinel value.
24 };
25 
26 #ifdef DEBUG
Equals(ScopeInfo * other) const27 bool ScopeInfo::Equals(ScopeInfo* other) const {
28   if (length() != other->length()) return false;
29   for (int index = 0; index < length(); ++index) {
30     Object* entry = get(index);
31     Object* other_entry = other->get(index);
32     if (entry->IsSmi()) {
33       if (entry != other_entry) return false;
34     } else {
35       if (HeapObject::cast(entry)->map()->instance_type() !=
36           HeapObject::cast(other_entry)->map()->instance_type()) {
37         return false;
38       }
39       if (entry->IsString()) {
40         if (!String::cast(entry)->Equals(String::cast(other_entry))) {
41           return false;
42         }
43       } else if (entry->IsScopeInfo()) {
44         if (!ScopeInfo::cast(entry)->Equals(ScopeInfo::cast(other_entry))) {
45           return false;
46         }
47       } else if (entry->IsModuleInfo()) {
48         if (!ModuleInfo::cast(entry)->Equals(ModuleInfo::cast(other_entry))) {
49           return false;
50         }
51       } else {
52         UNREACHABLE();
53         return false;
54       }
55     }
56   }
57   return true;
58 }
59 #endif
60 
Create(Isolate * isolate,Zone * zone,Scope * scope,MaybeHandle<ScopeInfo> outer_scope)61 Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate, Zone* zone, Scope* scope,
62                                     MaybeHandle<ScopeInfo> outer_scope) {
63   // Collect variables.
64   int stack_local_count = 0;
65   int context_local_count = 0;
66   int module_vars_count = 0;
67   // Stack allocated block scope variables are allocated in the parent
68   // declaration scope, but are recorded in the block scope's scope info. First
69   // slot index indicates at which offset a particular scope starts in the
70   // parent declaration scope.
71   int first_slot_index = 0;
72   for (Variable* var : *scope->locals()) {
73     switch (var->location()) {
74       case VariableLocation::LOCAL:
75         if (stack_local_count == 0) first_slot_index = var->index();
76         stack_local_count++;
77         break;
78       case VariableLocation::CONTEXT:
79         context_local_count++;
80         break;
81       case VariableLocation::MODULE:
82         module_vars_count++;
83         break;
84       default:
85         break;
86     }
87   }
88   DCHECK(module_vars_count == 0 || scope->is_module_scope());
89 
90   // Make sure we allocate the correct amount.
91   DCHECK_EQ(scope->ContextLocalCount(), context_local_count);
92 
93   // Determine use and location of the "this" binding if it is present.
94   VariableAllocationInfo receiver_info;
95   if (scope->is_declaration_scope() &&
96       scope->AsDeclarationScope()->has_this_declaration()) {
97     Variable* var = scope->AsDeclarationScope()->receiver();
98     if (!var->is_used()) {
99       receiver_info = UNUSED;
100     } else if (var->IsContextSlot()) {
101       receiver_info = CONTEXT;
102     } else {
103       DCHECK(var->IsParameter());
104       receiver_info = STACK;
105     }
106   } else {
107     receiver_info = NONE;
108   }
109 
110   bool has_new_target =
111       scope->is_declaration_scope() &&
112       scope->AsDeclarationScope()->new_target_var() != nullptr;
113 
114   // Determine use and location of the function variable if it is present.
115   VariableAllocationInfo function_name_info;
116   if (scope->is_function_scope() &&
117       scope->AsDeclarationScope()->function_var() != nullptr) {
118     Variable* var = scope->AsDeclarationScope()->function_var();
119     if (!var->is_used()) {
120       function_name_info = UNUSED;
121     } else if (var->IsContextSlot()) {
122       function_name_info = CONTEXT;
123     } else {
124       DCHECK(var->IsStackLocal());
125       function_name_info = STACK;
126     }
127   } else {
128     function_name_info = NONE;
129   }
130 
131   const bool has_function_name = function_name_info != NONE;
132   const bool has_receiver = receiver_info == STACK || receiver_info == CONTEXT;
133   const int parameter_count = scope->num_parameters();
134   const bool has_outer_scope_info = !outer_scope.is_null();
135   const int length = kVariablePartIndex + parameter_count +
136                      (1 + stack_local_count) + 2 * context_local_count +
137                      (has_receiver ? 1 : 0) + (has_function_name ? 2 : 0) +
138                      (has_outer_scope_info ? 1 : 0) +
139                      (scope->is_module_scope()
140                           ? 2 + kModuleVariableEntryLength * module_vars_count
141                           : 0);
142 
143   Factory* factory = isolate->factory();
144   Handle<ScopeInfo> scope_info = factory->NewScopeInfo(length);
145 
146   bool has_simple_parameters = false;
147   bool asm_module = false;
148   bool asm_function = false;
149   if (scope->is_function_scope()) {
150     DeclarationScope* function_scope = scope->AsDeclarationScope();
151     has_simple_parameters = function_scope->has_simple_parameters();
152     asm_module = function_scope->asm_module();
153     asm_function = function_scope->asm_function();
154   }
155   FunctionKind function_kind = kNormalFunction;
156   if (scope->is_declaration_scope()) {
157     function_kind = scope->AsDeclarationScope()->function_kind();
158   }
159 
160   // Encode the flags.
161   int flags =
162       ScopeTypeField::encode(scope->scope_type()) |
163       CallsEvalField::encode(scope->calls_eval()) |
164       LanguageModeField::encode(scope->language_mode()) |
165       DeclarationScopeField::encode(scope->is_declaration_scope()) |
166       ReceiverVariableField::encode(receiver_info) |
167       HasNewTargetField::encode(has_new_target) |
168       FunctionVariableField::encode(function_name_info) |
169       AsmModuleField::encode(asm_module) |
170       AsmFunctionField::encode(asm_function) |
171       HasSimpleParametersField::encode(has_simple_parameters) |
172       FunctionKindField::encode(function_kind) |
173       HasOuterScopeInfoField::encode(has_outer_scope_info) |
174       IsDebugEvaluateScopeField::encode(scope->is_debug_evaluate_scope());
175   scope_info->SetFlags(flags);
176 
177   scope_info->SetParameterCount(parameter_count);
178   scope_info->SetStackLocalCount(stack_local_count);
179   scope_info->SetContextLocalCount(context_local_count);
180 
181   int index = kVariablePartIndex;
182   // Add parameters.
183   DCHECK_EQ(index, scope_info->ParameterNamesIndex());
184   if (scope->is_declaration_scope()) {
185     for (int i = 0; i < parameter_count; ++i) {
186       scope_info->set(index++,
187                       *scope->AsDeclarationScope()->parameter(i)->name());
188     }
189   }
190 
191   // Add stack locals' names, context locals' names and info, module variables'
192   // names and info. We are assuming that the stack locals' slots are allocated
193   // in increasing order, so we can simply add them to the ScopeInfo object.
194   // Context locals are added using their index.
195   DCHECK_EQ(index, scope_info->StackLocalFirstSlotIndex());
196   scope_info->set(index++, Smi::FromInt(first_slot_index));
197   DCHECK_EQ(index, scope_info->StackLocalNamesIndex());
198 
199   int stack_local_base = index;
200   int context_local_base = stack_local_base + stack_local_count;
201   int context_local_info_base = context_local_base + context_local_count;
202   int module_var_entry = scope_info->ModuleVariablesIndex();
203 
204   for (Variable* var : *scope->locals()) {
205     switch (var->location()) {
206       case VariableLocation::LOCAL: {
207         int local_index = var->index() - first_slot_index;
208         DCHECK_LE(0, local_index);
209         DCHECK_LT(local_index, stack_local_count);
210         scope_info->set(stack_local_base + local_index, *var->name());
211         break;
212       }
213       case VariableLocation::CONTEXT: {
214         // Due to duplicate parameters, context locals aren't guaranteed to come
215         // in order.
216         int local_index = var->index() - Context::MIN_CONTEXT_SLOTS;
217         DCHECK_LE(0, local_index);
218         DCHECK_LT(local_index, context_local_count);
219         uint32_t info = VariableModeField::encode(var->mode()) |
220                         InitFlagField::encode(var->initialization_flag()) |
221                         MaybeAssignedFlagField::encode(var->maybe_assigned());
222         scope_info->set(context_local_base + local_index, *var->name());
223         scope_info->set(context_local_info_base + local_index,
224                         Smi::FromInt(info));
225         break;
226       }
227       case VariableLocation::MODULE: {
228         scope_info->set(module_var_entry + kModuleVariableNameOffset,
229                         *var->name());
230         scope_info->set(module_var_entry + kModuleVariableIndexOffset,
231                         Smi::FromInt(var->index()));
232         uint32_t properties =
233             VariableModeField::encode(var->mode()) |
234             InitFlagField::encode(var->initialization_flag()) |
235             MaybeAssignedFlagField::encode(var->maybe_assigned());
236         scope_info->set(module_var_entry + kModuleVariablePropertiesOffset,
237                         Smi::FromInt(properties));
238         module_var_entry += kModuleVariableEntryLength;
239         break;
240       }
241       default:
242         break;
243     }
244   }
245 
246   index += stack_local_count + 2 * context_local_count;
247 
248   // If the receiver is allocated, add its index.
249   DCHECK_EQ(index, scope_info->ReceiverInfoIndex());
250   if (has_receiver) {
251     int var_index = scope->AsDeclarationScope()->receiver()->index();
252     scope_info->set(index++, Smi::FromInt(var_index));
253     // ?? DCHECK(receiver_info != CONTEXT || var_index ==
254     // scope_info->ContextLength() - 1);
255   }
256 
257   // If present, add the function variable name and its index.
258   DCHECK_EQ(index, scope_info->FunctionNameInfoIndex());
259   if (has_function_name) {
260     int var_index = scope->AsDeclarationScope()->function_var()->index();
261     scope_info->set(index++,
262                     *scope->AsDeclarationScope()->function_var()->name());
263     scope_info->set(index++, Smi::FromInt(var_index));
264     DCHECK(function_name_info != CONTEXT ||
265            var_index == scope_info->ContextLength() - 1);
266   }
267 
268   // If present, add the outer scope info.
269   DCHECK(index == scope_info->OuterScopeInfoIndex());
270   if (has_outer_scope_info) {
271     scope_info->set(index++, *outer_scope.ToHandleChecked());
272   }
273 
274   // Module-specific information (only for module scopes).
275   if (scope->is_module_scope()) {
276     Handle<ModuleInfo> module_info =
277         ModuleInfo::New(isolate, zone, scope->AsModuleScope()->module());
278     DCHECK_EQ(index, scope_info->ModuleInfoIndex());
279     scope_info->set(index++, *module_info);
280     DCHECK_EQ(index, scope_info->ModuleVariableCountIndex());
281     scope_info->set(index++, Smi::FromInt(module_vars_count));
282     DCHECK_EQ(index, scope_info->ModuleVariablesIndex());
283     // The variable entries themselves have already been written above.
284     index += kModuleVariableEntryLength * module_vars_count;
285   }
286 
287   DCHECK_EQ(index, scope_info->length());
288   DCHECK_EQ(scope->num_parameters(), scope_info->ParameterCount());
289   DCHECK_EQ(scope->num_heap_slots(), scope_info->ContextLength());
290   return scope_info;
291 }
292 
CreateForWithScope(Isolate * isolate,MaybeHandle<ScopeInfo> outer_scope)293 Handle<ScopeInfo> ScopeInfo::CreateForWithScope(
294     Isolate* isolate, MaybeHandle<ScopeInfo> outer_scope) {
295   const bool has_outer_scope_info = !outer_scope.is_null();
296   const int length = kVariablePartIndex + 1 + (has_outer_scope_info ? 1 : 0);
297 
298   Factory* factory = isolate->factory();
299   Handle<ScopeInfo> scope_info = factory->NewScopeInfo(length);
300 
301   // Encode the flags.
302   int flags =
303       ScopeTypeField::encode(WITH_SCOPE) | CallsEvalField::encode(false) |
304       LanguageModeField::encode(SLOPPY) | DeclarationScopeField::encode(false) |
305       ReceiverVariableField::encode(NONE) | HasNewTargetField::encode(false) |
306       FunctionVariableField::encode(NONE) | AsmModuleField::encode(false) |
307       AsmFunctionField::encode(false) | HasSimpleParametersField::encode(true) |
308       FunctionKindField::encode(kNormalFunction) |
309       HasOuterScopeInfoField::encode(has_outer_scope_info) |
310       IsDebugEvaluateScopeField::encode(false);
311   scope_info->SetFlags(flags);
312 
313   scope_info->SetParameterCount(0);
314   scope_info->SetStackLocalCount(0);
315   scope_info->SetContextLocalCount(0);
316 
317   int index = kVariablePartIndex;
318   DCHECK_EQ(index, scope_info->ParameterNamesIndex());
319   DCHECK_EQ(index, scope_info->StackLocalFirstSlotIndex());
320   scope_info->set(index++, Smi::kZero);
321   DCHECK_EQ(index, scope_info->StackLocalNamesIndex());
322   DCHECK_EQ(index, scope_info->ReceiverInfoIndex());
323   DCHECK_EQ(index, scope_info->FunctionNameInfoIndex());
324   DCHECK(index == scope_info->OuterScopeInfoIndex());
325   if (has_outer_scope_info) {
326     scope_info->set(index++, *outer_scope.ToHandleChecked());
327   }
328   DCHECK_EQ(index, scope_info->length());
329   DCHECK_EQ(0, scope_info->ParameterCount());
330   DCHECK_EQ(Context::MIN_CONTEXT_SLOTS, scope_info->ContextLength());
331   return scope_info;
332 }
333 
CreateGlobalThisBinding(Isolate * isolate)334 Handle<ScopeInfo> ScopeInfo::CreateGlobalThisBinding(Isolate* isolate) {
335   DCHECK(isolate->bootstrapper()->IsActive());
336 
337   const int stack_local_count = 0;
338   const int context_local_count = 1;
339   const bool has_simple_parameters = true;
340   const VariableAllocationInfo receiver_info = CONTEXT;
341   const VariableAllocationInfo function_name_info = NONE;
342   const bool has_function_name = false;
343   const bool has_receiver = true;
344   const bool has_outer_scope_info = false;
345   const int parameter_count = 0;
346   const int length = kVariablePartIndex + parameter_count +
347                      (1 + stack_local_count) + 2 * context_local_count +
348                      (has_receiver ? 1 : 0) + (has_function_name ? 2 : 0) +
349                      (has_outer_scope_info ? 1 : 0);
350 
351   Factory* factory = isolate->factory();
352   Handle<ScopeInfo> scope_info = factory->NewScopeInfo(length);
353 
354   // Encode the flags.
355   int flags =
356       ScopeTypeField::encode(SCRIPT_SCOPE) | CallsEvalField::encode(false) |
357       LanguageModeField::encode(SLOPPY) | DeclarationScopeField::encode(true) |
358       ReceiverVariableField::encode(receiver_info) |
359       FunctionVariableField::encode(function_name_info) |
360       AsmModuleField::encode(false) | AsmFunctionField::encode(false) |
361       HasSimpleParametersField::encode(has_simple_parameters) |
362       FunctionKindField::encode(FunctionKind::kNormalFunction) |
363       HasOuterScopeInfoField::encode(has_outer_scope_info) |
364       IsDebugEvaluateScopeField::encode(false);
365   scope_info->SetFlags(flags);
366   scope_info->SetParameterCount(parameter_count);
367   scope_info->SetStackLocalCount(stack_local_count);
368   scope_info->SetContextLocalCount(context_local_count);
369 
370   int index = kVariablePartIndex;
371   const int first_slot_index = 0;
372   DCHECK_EQ(index, scope_info->StackLocalFirstSlotIndex());
373   scope_info->set(index++, Smi::FromInt(first_slot_index));
374   DCHECK_EQ(index, scope_info->StackLocalNamesIndex());
375 
376   // Here we add info for context-allocated "this".
377   DCHECK_EQ(index, scope_info->ContextLocalNamesIndex());
378   scope_info->set(index++, isolate->heap()->this_string());
379   DCHECK_EQ(index, scope_info->ContextLocalInfosIndex());
380   const uint32_t value = VariableModeField::encode(CONST) |
381                          InitFlagField::encode(kCreatedInitialized) |
382                          MaybeAssignedFlagField::encode(kNotAssigned);
383   scope_info->set(index++, Smi::FromInt(value));
384 
385   // And here we record that this scopeinfo binds a receiver.
386   DCHECK_EQ(index, scope_info->ReceiverInfoIndex());
387   const int receiver_index = Context::MIN_CONTEXT_SLOTS + 0;
388   scope_info->set(index++, Smi::FromInt(receiver_index));
389 
390   DCHECK_EQ(index, scope_info->FunctionNameInfoIndex());
391   DCHECK_EQ(index, scope_info->OuterScopeInfoIndex());
392   DCHECK_EQ(index, scope_info->length());
393   DCHECK_EQ(scope_info->ParameterCount(), 0);
394   DCHECK_EQ(scope_info->ContextLength(), Context::MIN_CONTEXT_SLOTS + 1);
395 
396   return scope_info;
397 }
398 
Empty(Isolate * isolate)399 ScopeInfo* ScopeInfo::Empty(Isolate* isolate) {
400   return isolate->heap()->empty_scope_info();
401 }
402 
scope_type()403 ScopeType ScopeInfo::scope_type() {
404   DCHECK_LT(0, length());
405   return ScopeTypeField::decode(Flags());
406 }
407 
CallsEval()408 bool ScopeInfo::CallsEval() {
409   return length() > 0 && CallsEvalField::decode(Flags());
410 }
411 
language_mode()412 LanguageMode ScopeInfo::language_mode() {
413   return length() > 0 ? LanguageModeField::decode(Flags()) : SLOPPY;
414 }
415 
is_declaration_scope()416 bool ScopeInfo::is_declaration_scope() {
417   return DeclarationScopeField::decode(Flags());
418 }
419 
LocalCount()420 int ScopeInfo::LocalCount() { return StackLocalCount() + ContextLocalCount(); }
421 
StackSlotCount()422 int ScopeInfo::StackSlotCount() {
423   if (length() > 0) {
424     bool function_name_stack_slot =
425         FunctionVariableField::decode(Flags()) == STACK;
426     return StackLocalCount() + (function_name_stack_slot ? 1 : 0);
427   }
428   return 0;
429 }
430 
ContextLength()431 int ScopeInfo::ContextLength() {
432   if (length() > 0) {
433     int context_locals = ContextLocalCount();
434     bool function_name_context_slot =
435         FunctionVariableField::decode(Flags()) == CONTEXT;
436     bool has_context = context_locals > 0 || function_name_context_slot ||
437                        scope_type() == WITH_SCOPE ||
438                        (scope_type() == BLOCK_SCOPE && CallsSloppyEval() &&
439                         is_declaration_scope()) ||
440                        (scope_type() == FUNCTION_SCOPE && CallsSloppyEval()) ||
441                        (scope_type() == FUNCTION_SCOPE && IsAsmModule()) ||
442                        scope_type() == MODULE_SCOPE;
443 
444     if (has_context) {
445       return Context::MIN_CONTEXT_SLOTS + context_locals +
446              (function_name_context_slot ? 1 : 0);
447     }
448   }
449   return 0;
450 }
451 
HasReceiver()452 bool ScopeInfo::HasReceiver() {
453   if (length() > 0) {
454     return NONE != ReceiverVariableField::decode(Flags());
455   } else {
456     return false;
457   }
458 }
459 
HasAllocatedReceiver()460 bool ScopeInfo::HasAllocatedReceiver() {
461   if (length() > 0) {
462     VariableAllocationInfo allocation = ReceiverVariableField::decode(Flags());
463     return allocation == STACK || allocation == CONTEXT;
464   } else {
465     return false;
466   }
467 }
468 
HasNewTarget()469 bool ScopeInfo::HasNewTarget() { return HasNewTargetField::decode(Flags()); }
470 
HasFunctionName()471 bool ScopeInfo::HasFunctionName() {
472   if (length() > 0) {
473     return NONE != FunctionVariableField::decode(Flags());
474   } else {
475     return false;
476   }
477 }
478 
HasOuterScopeInfo()479 bool ScopeInfo::HasOuterScopeInfo() {
480   if (length() > 0) {
481     return HasOuterScopeInfoField::decode(Flags());
482   } else {
483     return false;
484   }
485 }
486 
IsDebugEvaluateScope()487 bool ScopeInfo::IsDebugEvaluateScope() {
488   if (length() > 0) {
489     return IsDebugEvaluateScopeField::decode(Flags());
490   } else {
491     return false;
492   }
493 }
494 
SetIsDebugEvaluateScope()495 void ScopeInfo::SetIsDebugEvaluateScope() {
496   if (length() > 0) {
497     DCHECK_EQ(scope_type(), WITH_SCOPE);
498     SetFlags(Flags() | IsDebugEvaluateScopeField::encode(true));
499   } else {
500     UNREACHABLE();
501   }
502 }
503 
HasHeapAllocatedLocals()504 bool ScopeInfo::HasHeapAllocatedLocals() {
505   if (length() > 0) {
506     return ContextLocalCount() > 0;
507   } else {
508     return false;
509   }
510 }
511 
HasContext()512 bool ScopeInfo::HasContext() { return ContextLength() > 0; }
513 
FunctionName()514 String* ScopeInfo::FunctionName() {
515   DCHECK(HasFunctionName());
516   return String::cast(get(FunctionNameInfoIndex()));
517 }
518 
OuterScopeInfo()519 ScopeInfo* ScopeInfo::OuterScopeInfo() {
520   DCHECK(HasOuterScopeInfo());
521   return ScopeInfo::cast(get(OuterScopeInfoIndex()));
522 }
523 
ModuleDescriptorInfo()524 ModuleInfo* ScopeInfo::ModuleDescriptorInfo() {
525   DCHECK(scope_type() == MODULE_SCOPE);
526   return ModuleInfo::cast(get(ModuleInfoIndex()));
527 }
528 
ParameterName(int var)529 String* ScopeInfo::ParameterName(int var) {
530   DCHECK_LE(0, var);
531   DCHECK_LT(var, ParameterCount());
532   int info_index = ParameterNamesIndex() + var;
533   return String::cast(get(info_index));
534 }
535 
LocalName(int var)536 String* ScopeInfo::LocalName(int var) {
537   DCHECK_LE(0, var);
538   DCHECK_LT(var, LocalCount());
539   DCHECK(StackLocalNamesIndex() + StackLocalCount() ==
540          ContextLocalNamesIndex());
541   int info_index = StackLocalNamesIndex() + var;
542   return String::cast(get(info_index));
543 }
544 
StackLocalName(int var)545 String* ScopeInfo::StackLocalName(int var) {
546   DCHECK_LE(0, var);
547   DCHECK_LT(var, StackLocalCount());
548   int info_index = StackLocalNamesIndex() + var;
549   return String::cast(get(info_index));
550 }
551 
StackLocalIndex(int var)552 int ScopeInfo::StackLocalIndex(int var) {
553   DCHECK_LE(0, var);
554   DCHECK_LT(var, StackLocalCount());
555   int first_slot_index = Smi::cast(get(StackLocalFirstSlotIndex()))->value();
556   return first_slot_index + var;
557 }
558 
ContextLocalName(int var)559 String* ScopeInfo::ContextLocalName(int var) {
560   DCHECK_LE(0, var);
561   DCHECK_LT(var, ContextLocalCount());
562   int info_index = ContextLocalNamesIndex() + var;
563   return String::cast(get(info_index));
564 }
565 
ContextLocalMode(int var)566 VariableMode ScopeInfo::ContextLocalMode(int var) {
567   DCHECK_LE(0, var);
568   DCHECK_LT(var, ContextLocalCount());
569   int info_index = ContextLocalInfosIndex() + var;
570   int value = Smi::cast(get(info_index))->value();
571   return VariableModeField::decode(value);
572 }
573 
ContextLocalInitFlag(int var)574 InitializationFlag ScopeInfo::ContextLocalInitFlag(int var) {
575   DCHECK_LE(0, var);
576   DCHECK_LT(var, ContextLocalCount());
577   int info_index = ContextLocalInfosIndex() + var;
578   int value = Smi::cast(get(info_index))->value();
579   return InitFlagField::decode(value);
580 }
581 
ContextLocalMaybeAssignedFlag(int var)582 MaybeAssignedFlag ScopeInfo::ContextLocalMaybeAssignedFlag(int var) {
583   DCHECK_LE(0, var);
584   DCHECK_LT(var, ContextLocalCount());
585   int info_index = ContextLocalInfosIndex() + var;
586   int value = Smi::cast(get(info_index))->value();
587   return MaybeAssignedFlagField::decode(value);
588 }
589 
VariableIsSynthetic(String * name)590 bool ScopeInfo::VariableIsSynthetic(String* name) {
591   // There's currently no flag stored on the ScopeInfo to indicate that a
592   // variable is a compiler-introduced temporary. However, to avoid conflict
593   // with user declarations, the current temporaries like .generator_object and
594   // .result start with a dot, so we can use that as a flag. It's a hack!
595   return name->length() == 0 || name->Get(0) == '.' ||
596          name->Equals(name->GetHeap()->this_string());
597 }
598 
StackSlotIndex(String * name)599 int ScopeInfo::StackSlotIndex(String* name) {
600   DCHECK(name->IsInternalizedString());
601   if (length() > 0) {
602     int first_slot_index = Smi::cast(get(StackLocalFirstSlotIndex()))->value();
603     int start = StackLocalNamesIndex();
604     int end = start + StackLocalCount();
605     for (int i = start; i < end; ++i) {
606       if (name == get(i)) {
607         return i - start + first_slot_index;
608       }
609     }
610   }
611   return -1;
612 }
613 
ModuleIndex(Handle<String> name,VariableMode * mode,InitializationFlag * init_flag,MaybeAssignedFlag * maybe_assigned_flag)614 int ScopeInfo::ModuleIndex(Handle<String> name, VariableMode* mode,
615                            InitializationFlag* init_flag,
616                            MaybeAssignedFlag* maybe_assigned_flag) {
617   DCHECK_EQ(scope_type(), MODULE_SCOPE);
618   DCHECK(name->IsInternalizedString());
619   DCHECK_NOT_NULL(mode);
620   DCHECK_NOT_NULL(init_flag);
621   DCHECK_NOT_NULL(maybe_assigned_flag);
622 
623   int module_vars_count = Smi::cast(get(ModuleVariableCountIndex()))->value();
624   int entry = ModuleVariablesIndex();
625   for (int i = 0; i < module_vars_count; ++i) {
626     if (*name == get(entry + kModuleVariableNameOffset)) {
627       int index;
628       ModuleVariable(i, nullptr, &index, mode, init_flag, maybe_assigned_flag);
629       return index;
630     }
631     entry += kModuleVariableEntryLength;
632   }
633 
634   return 0;
635 }
636 
ContextSlotIndex(Handle<ScopeInfo> scope_info,Handle<String> name,VariableMode * mode,InitializationFlag * init_flag,MaybeAssignedFlag * maybe_assigned_flag)637 int ScopeInfo::ContextSlotIndex(Handle<ScopeInfo> scope_info,
638                                 Handle<String> name, VariableMode* mode,
639                                 InitializationFlag* init_flag,
640                                 MaybeAssignedFlag* maybe_assigned_flag) {
641   DCHECK(name->IsInternalizedString());
642   DCHECK_NOT_NULL(mode);
643   DCHECK_NOT_NULL(init_flag);
644   DCHECK_NOT_NULL(maybe_assigned_flag);
645 
646   if (scope_info->length() > 0) {
647     ContextSlotCache* context_slot_cache =
648         scope_info->GetIsolate()->context_slot_cache();
649     int result = context_slot_cache->Lookup(*scope_info, *name, mode, init_flag,
650                                             maybe_assigned_flag);
651     if (result != ContextSlotCache::kNotFound) {
652       DCHECK_LT(result, scope_info->ContextLength());
653       return result;
654     }
655 
656     int start = scope_info->ContextLocalNamesIndex();
657     int end = start + scope_info->ContextLocalCount();
658     for (int i = start; i < end; ++i) {
659       if (*name == scope_info->get(i)) {
660         int var = i - start;
661         *mode = scope_info->ContextLocalMode(var);
662         *init_flag = scope_info->ContextLocalInitFlag(var);
663         *maybe_assigned_flag = scope_info->ContextLocalMaybeAssignedFlag(var);
664         result = Context::MIN_CONTEXT_SLOTS + var;
665 
666         context_slot_cache->Update(scope_info, name, *mode, *init_flag,
667                                    *maybe_assigned_flag, result);
668         DCHECK_LT(result, scope_info->ContextLength());
669         return result;
670       }
671     }
672     // Cache as not found. Mode, init flag and maybe assigned flag don't matter.
673     context_slot_cache->Update(scope_info, name, TEMPORARY,
674                                kNeedsInitialization, kNotAssigned, -1);
675   }
676 
677   return -1;
678 }
679 
ContextSlotName(int slot_index)680 String* ScopeInfo::ContextSlotName(int slot_index) {
681   int const var = slot_index - Context::MIN_CONTEXT_SLOTS;
682   DCHECK_LE(0, var);
683   DCHECK_LT(var, ContextLocalCount());
684   return ContextLocalName(var);
685 }
686 
ParameterIndex(String * name)687 int ScopeInfo::ParameterIndex(String* name) {
688   DCHECK(name->IsInternalizedString());
689   if (length() > 0) {
690     // We must read parameters from the end since for
691     // multiply declared parameters the value of the
692     // last declaration of that parameter is used
693     // inside a function (and thus we need to look
694     // at the last index). Was bug# 1110337.
695     int start = ParameterNamesIndex();
696     int end = start + ParameterCount();
697     for (int i = end - 1; i >= start; --i) {
698       if (name == get(i)) {
699         return i - start;
700       }
701     }
702   }
703   return -1;
704 }
705 
ReceiverContextSlotIndex()706 int ScopeInfo::ReceiverContextSlotIndex() {
707   if (length() > 0 && ReceiverVariableField::decode(Flags()) == CONTEXT)
708     return Smi::cast(get(ReceiverInfoIndex()))->value();
709   return -1;
710 }
711 
FunctionContextSlotIndex(String * name)712 int ScopeInfo::FunctionContextSlotIndex(String* name) {
713   DCHECK(name->IsInternalizedString());
714   if (length() > 0) {
715     if (FunctionVariableField::decode(Flags()) == CONTEXT &&
716         FunctionName() == name) {
717       return Smi::cast(get(FunctionNameInfoIndex() + 1))->value();
718     }
719   }
720   return -1;
721 }
722 
function_kind()723 FunctionKind ScopeInfo::function_kind() {
724   return FunctionKindField::decode(Flags());
725 }
726 
ParameterNamesIndex()727 int ScopeInfo::ParameterNamesIndex() {
728   DCHECK_LT(0, length());
729   return kVariablePartIndex;
730 }
731 
StackLocalFirstSlotIndex()732 int ScopeInfo::StackLocalFirstSlotIndex() {
733   return ParameterNamesIndex() + ParameterCount();
734 }
735 
StackLocalNamesIndex()736 int ScopeInfo::StackLocalNamesIndex() { return StackLocalFirstSlotIndex() + 1; }
737 
ContextLocalNamesIndex()738 int ScopeInfo::ContextLocalNamesIndex() {
739   return StackLocalNamesIndex() + StackLocalCount();
740 }
741 
ContextLocalInfosIndex()742 int ScopeInfo::ContextLocalInfosIndex() {
743   return ContextLocalNamesIndex() + ContextLocalCount();
744 }
745 
ReceiverInfoIndex()746 int ScopeInfo::ReceiverInfoIndex() {
747   return ContextLocalInfosIndex() + ContextLocalCount();
748 }
749 
FunctionNameInfoIndex()750 int ScopeInfo::FunctionNameInfoIndex() {
751   return ReceiverInfoIndex() + (HasAllocatedReceiver() ? 1 : 0);
752 }
753 
OuterScopeInfoIndex()754 int ScopeInfo::OuterScopeInfoIndex() {
755   return FunctionNameInfoIndex() + (HasFunctionName() ? 2 : 0);
756 }
757 
ModuleInfoIndex()758 int ScopeInfo::ModuleInfoIndex() {
759   return OuterScopeInfoIndex() + (HasOuterScopeInfo() ? 1 : 0);
760 }
761 
ModuleVariableCountIndex()762 int ScopeInfo::ModuleVariableCountIndex() { return ModuleInfoIndex() + 1; }
763 
ModuleVariablesIndex()764 int ScopeInfo::ModuleVariablesIndex() { return ModuleVariableCountIndex() + 1; }
765 
ModuleVariable(int i,String ** name,int * index,VariableMode * mode,InitializationFlag * init_flag,MaybeAssignedFlag * maybe_assigned_flag)766 void ScopeInfo::ModuleVariable(int i, String** name, int* index,
767                                VariableMode* mode,
768                                InitializationFlag* init_flag,
769                                MaybeAssignedFlag* maybe_assigned_flag) {
770   DCHECK_LE(0, i);
771   DCHECK_LT(i, Smi::cast(get(ModuleVariableCountIndex()))->value());
772 
773   int entry = ModuleVariablesIndex() + i * kModuleVariableEntryLength;
774   int properties =
775       Smi::cast(get(entry + kModuleVariablePropertiesOffset))->value();
776 
777   if (name != nullptr) {
778     *name = String::cast(get(entry + kModuleVariableNameOffset));
779   }
780   if (index != nullptr) {
781     *index = Smi::cast(get(entry + kModuleVariableIndexOffset))->value();
782     DCHECK_NE(*index, 0);
783   }
784   if (mode != nullptr) {
785     *mode = VariableModeField::decode(properties);
786   }
787   if (init_flag != nullptr) {
788     *init_flag = InitFlagField::decode(properties);
789   }
790   if (maybe_assigned_flag != nullptr) {
791     *maybe_assigned_flag = MaybeAssignedFlagField::decode(properties);
792   }
793 }
794 
795 #ifdef DEBUG
796 
PrintList(const char * list_name,int nof_internal_slots,int start,int end,ScopeInfo * scope_info)797 static void PrintList(const char* list_name, int nof_internal_slots, int start,
798                       int end, ScopeInfo* scope_info) {
799   if (start < end) {
800     PrintF("\n  // %s\n", list_name);
801     if (nof_internal_slots > 0) {
802       PrintF("  %2d - %2d [internal slots]\n", 0, nof_internal_slots - 1);
803     }
804     for (int i = nof_internal_slots; start < end; ++i, ++start) {
805       PrintF("  %2d ", i);
806       String::cast(scope_info->get(start))->ShortPrint();
807       PrintF("\n");
808     }
809   }
810 }
811 
Print()812 void ScopeInfo::Print() {
813   PrintF("ScopeInfo ");
814   if (HasFunctionName()) {
815     FunctionName()->ShortPrint();
816   } else {
817     PrintF("/* no function name */");
818   }
819   PrintF("{");
820 
821   if (length() > 0) {
822     PrintList("parameters", 0, ParameterNamesIndex(),
823               ParameterNamesIndex() + ParameterCount(), this);
824     PrintList("stack slots", 0, StackLocalNamesIndex(),
825               StackLocalNamesIndex() + StackLocalCount(), this);
826     PrintList("context slots", Context::MIN_CONTEXT_SLOTS,
827               ContextLocalNamesIndex(),
828               ContextLocalNamesIndex() + ContextLocalCount(), this);
829     // TODO(neis): Print module stuff if present.
830   }
831 
832   PrintF("}\n");
833 }
834 #endif  // DEBUG
835 
New(Isolate * isolate,Handle<Object> export_name,Handle<Object> local_name,Handle<Object> import_name,int module_request,int cell_index,int beg_pos,int end_pos)836 Handle<ModuleInfoEntry> ModuleInfoEntry::New(Isolate* isolate,
837                                              Handle<Object> export_name,
838                                              Handle<Object> local_name,
839                                              Handle<Object> import_name,
840                                              int module_request, int cell_index,
841                                              int beg_pos, int end_pos) {
842   Handle<ModuleInfoEntry> result = Handle<ModuleInfoEntry>::cast(
843       isolate->factory()->NewStruct(MODULE_INFO_ENTRY_TYPE));
844   result->set_export_name(*export_name);
845   result->set_local_name(*local_name);
846   result->set_import_name(*import_name);
847   result->set_module_request(module_request);
848   result->set_cell_index(cell_index);
849   result->set_beg_pos(beg_pos);
850   result->set_end_pos(end_pos);
851   return result;
852 }
853 
New(Isolate * isolate,Zone * zone,ModuleDescriptor * descr)854 Handle<ModuleInfo> ModuleInfo::New(Isolate* isolate, Zone* zone,
855                                    ModuleDescriptor* descr) {
856   // Serialize module requests.
857   Handle<FixedArray> module_requests = isolate->factory()->NewFixedArray(
858       static_cast<int>(descr->module_requests().size()));
859   for (const auto& elem : descr->module_requests()) {
860     module_requests->set(elem.second, *elem.first->string());
861   }
862 
863   // Serialize special exports.
864   Handle<FixedArray> special_exports =
865       isolate->factory()->NewFixedArray(descr->special_exports().length());
866   {
867     int i = 0;
868     for (auto entry : descr->special_exports()) {
869       Handle<ModuleInfoEntry> serialized_entry = entry->Serialize(isolate);
870       special_exports->set(i++, *serialized_entry);
871     }
872   }
873 
874   // Serialize namespace imports.
875   Handle<FixedArray> namespace_imports =
876       isolate->factory()->NewFixedArray(descr->namespace_imports().length());
877   {
878     int i = 0;
879     for (auto entry : descr->namespace_imports()) {
880       Handle<ModuleInfoEntry> serialized_entry = entry->Serialize(isolate);
881       namespace_imports->set(i++, *serialized_entry);
882     }
883   }
884 
885   // Serialize regular exports.
886   Handle<FixedArray> regular_exports =
887       descr->SerializeRegularExports(isolate, zone);
888 
889   // Serialize regular imports.
890   Handle<FixedArray> regular_imports = isolate->factory()->NewFixedArray(
891       static_cast<int>(descr->regular_imports().size()));
892   {
893     int i = 0;
894     for (const auto& elem : descr->regular_imports()) {
895       Handle<ModuleInfoEntry> serialized_entry =
896           elem.second->Serialize(isolate);
897       regular_imports->set(i++, *serialized_entry);
898     }
899   }
900 
901   Handle<ModuleInfo> result = isolate->factory()->NewModuleInfo();
902   result->set(kModuleRequestsIndex, *module_requests);
903   result->set(kSpecialExportsIndex, *special_exports);
904   result->set(kRegularExportsIndex, *regular_exports);
905   result->set(kNamespaceImportsIndex, *namespace_imports);
906   result->set(kRegularImportsIndex, *regular_imports);
907   return result;
908 }
909 
RegularExportCount() const910 int ModuleInfo::RegularExportCount() const {
911   DCHECK_EQ(regular_exports()->length() % kRegularExportLength, 0);
912   return regular_exports()->length() / kRegularExportLength;
913 }
914 
RegularExportLocalName(int i) const915 String* ModuleInfo::RegularExportLocalName(int i) const {
916   return String::cast(regular_exports()->get(i * kRegularExportLength +
917                                              kRegularExportLocalNameOffset));
918 }
919 
RegularExportCellIndex(int i) const920 int ModuleInfo::RegularExportCellIndex(int i) const {
921   return Smi::cast(regular_exports()->get(i * kRegularExportLength +
922                                           kRegularExportCellIndexOffset))
923       ->value();
924 }
925 
RegularExportExportNames(int i) const926 FixedArray* ModuleInfo::RegularExportExportNames(int i) const {
927   return FixedArray::cast(regular_exports()->get(
928       i * kRegularExportLength + kRegularExportExportNamesOffset));
929 }
930 
LookupRegularImport(Handle<ModuleInfo> info,Handle<String> local_name)931 Handle<ModuleInfoEntry> ModuleInfo::LookupRegularImport(
932     Handle<ModuleInfo> info, Handle<String> local_name) {
933   Isolate* isolate = info->GetIsolate();
934   Handle<FixedArray> regular_imports(info->regular_imports(), isolate);
935   for (int i = 0, n = regular_imports->length(); i < n; ++i) {
936     Handle<ModuleInfoEntry> entry(
937         ModuleInfoEntry::cast(regular_imports->get(i)), isolate);
938     if (String::cast(entry->local_name())->Equals(*local_name)) {
939       return entry;
940     }
941   }
942   UNREACHABLE();
943   return Handle<ModuleInfoEntry>();
944 }
945 
946 }  // namespace internal
947 }  // namespace v8
948