OLD | NEW |
| (Empty) |
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 | |
27 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 | |
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 | |
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 | |
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 | |
399 | |
400 ScopeInfo* ScopeInfo::Empty(Isolate* isolate) { | |
401 return isolate->heap()->empty_scope_info(); | |
402 } | |
403 | |
404 | |
405 ScopeType ScopeInfo::scope_type() { | |
406 DCHECK_LT(0, length()); | |
407 return ScopeTypeField::decode(Flags()); | |
408 } | |
409 | |
410 | |
411 bool ScopeInfo::CallsEval() { | |
412 return length() > 0 && CallsEvalField::decode(Flags()); | |
413 } | |
414 | |
415 | |
416 LanguageMode ScopeInfo::language_mode() { | |
417 return length() > 0 ? LanguageModeField::decode(Flags()) : SLOPPY; | |
418 } | |
419 | |
420 | |
421 bool ScopeInfo::is_declaration_scope() { | |
422 return DeclarationScopeField::decode(Flags()); | |
423 } | |
424 | |
425 | |
426 int ScopeInfo::LocalCount() { | |
427 return StackLocalCount() + ContextLocalCount(); | |
428 } | |
429 | |
430 | |
431 int ScopeInfo::StackSlotCount() { | |
432 if (length() > 0) { | |
433 bool function_name_stack_slot = | |
434 FunctionVariableField::decode(Flags()) == STACK; | |
435 return StackLocalCount() + (function_name_stack_slot ? 1 : 0); | |
436 } | |
437 return 0; | |
438 } | |
439 | |
440 | |
441 int ScopeInfo::ContextLength() { | |
442 if (length() > 0) { | |
443 int context_locals = ContextLocalCount(); | |
444 bool function_name_context_slot = | |
445 FunctionVariableField::decode(Flags()) == CONTEXT; | |
446 bool has_context = context_locals > 0 || function_name_context_slot || | |
447 scope_type() == WITH_SCOPE || | |
448 (scope_type() == BLOCK_SCOPE && CallsSloppyEval() && | |
449 is_declaration_scope()) || | |
450 (scope_type() == FUNCTION_SCOPE && CallsSloppyEval()) || | |
451 (scope_type() == FUNCTION_SCOPE && IsAsmModule()) || | |
452 scope_type() == MODULE_SCOPE; | |
453 | |
454 if (has_context) { | |
455 return Context::MIN_CONTEXT_SLOTS + context_locals + | |
456 (function_name_context_slot ? 1 : 0); | |
457 } | |
458 } | |
459 return 0; | |
460 } | |
461 | |
462 | |
463 bool ScopeInfo::HasReceiver() { | |
464 if (length() > 0) { | |
465 return NONE != ReceiverVariableField::decode(Flags()); | |
466 } else { | |
467 return false; | |
468 } | |
469 } | |
470 | |
471 | |
472 bool ScopeInfo::HasAllocatedReceiver() { | |
473 if (length() > 0) { | |
474 VariableAllocationInfo allocation = ReceiverVariableField::decode(Flags()); | |
475 return allocation == STACK || allocation == CONTEXT; | |
476 } else { | |
477 return false; | |
478 } | |
479 } | |
480 | |
481 | |
482 bool ScopeInfo::HasNewTarget() { return HasNewTargetField::decode(Flags()); } | |
483 | |
484 | |
485 bool ScopeInfo::HasFunctionName() { | |
486 if (length() > 0) { | |
487 return NONE != FunctionVariableField::decode(Flags()); | |
488 } else { | |
489 return false; | |
490 } | |
491 } | |
492 | |
493 bool ScopeInfo::HasOuterScopeInfo() { | |
494 if (length() > 0) { | |
495 return HasOuterScopeInfoField::decode(Flags()); | |
496 } else { | |
497 return false; | |
498 } | |
499 } | |
500 | |
501 bool ScopeInfo::IsDebugEvaluateScope() { | |
502 if (length() > 0) { | |
503 return IsDebugEvaluateScopeField::decode(Flags()); | |
504 } else { | |
505 return false; | |
506 } | |
507 } | |
508 | |
509 void ScopeInfo::SetIsDebugEvaluateScope() { | |
510 if (length() > 0) { | |
511 DCHECK_EQ(scope_type(), WITH_SCOPE); | |
512 SetFlags(Flags() | IsDebugEvaluateScopeField::encode(true)); | |
513 } else { | |
514 UNREACHABLE(); | |
515 } | |
516 } | |
517 | |
518 bool ScopeInfo::HasHeapAllocatedLocals() { | |
519 if (length() > 0) { | |
520 return ContextLocalCount() > 0; | |
521 } else { | |
522 return false; | |
523 } | |
524 } | |
525 | |
526 | |
527 bool ScopeInfo::HasContext() { | |
528 return ContextLength() > 0; | |
529 } | |
530 | |
531 | |
532 String* ScopeInfo::FunctionName() { | |
533 DCHECK(HasFunctionName()); | |
534 return String::cast(get(FunctionNameInfoIndex())); | |
535 } | |
536 | |
537 ScopeInfo* ScopeInfo::OuterScopeInfo() { | |
538 DCHECK(HasOuterScopeInfo()); | |
539 return ScopeInfo::cast(get(OuterScopeInfoIndex())); | |
540 } | |
541 | |
542 ModuleInfo* ScopeInfo::ModuleDescriptorInfo() { | |
543 DCHECK(scope_type() == MODULE_SCOPE); | |
544 return ModuleInfo::cast(get(ModuleInfoIndex())); | |
545 } | |
546 | |
547 String* ScopeInfo::ParameterName(int var) { | |
548 DCHECK_LE(0, var); | |
549 DCHECK_LT(var, ParameterCount()); | |
550 int info_index = ParameterNamesIndex() + var; | |
551 return String::cast(get(info_index)); | |
552 } | |
553 | |
554 | |
555 String* ScopeInfo::LocalName(int var) { | |
556 DCHECK_LE(0, var); | |
557 DCHECK_LT(var, LocalCount()); | |
558 DCHECK(StackLocalNamesIndex() + StackLocalCount() == | |
559 ContextLocalNamesIndex()); | |
560 int info_index = StackLocalNamesIndex() + var; | |
561 return String::cast(get(info_index)); | |
562 } | |
563 | |
564 | |
565 String* ScopeInfo::StackLocalName(int var) { | |
566 DCHECK_LE(0, var); | |
567 DCHECK_LT(var, StackLocalCount()); | |
568 int info_index = StackLocalNamesIndex() + var; | |
569 return String::cast(get(info_index)); | |
570 } | |
571 | |
572 | |
573 int ScopeInfo::StackLocalIndex(int var) { | |
574 DCHECK_LE(0, var); | |
575 DCHECK_LT(var, StackLocalCount()); | |
576 int first_slot_index = Smi::cast(get(StackLocalFirstSlotIndex()))->value(); | |
577 return first_slot_index + var; | |
578 } | |
579 | |
580 | |
581 String* ScopeInfo::ContextLocalName(int var) { | |
582 DCHECK_LE(0, var); | |
583 DCHECK_LT(var, ContextLocalCount()); | |
584 int info_index = ContextLocalNamesIndex() + var; | |
585 return String::cast(get(info_index)); | |
586 } | |
587 | |
588 | |
589 VariableMode ScopeInfo::ContextLocalMode(int var) { | |
590 DCHECK_LE(0, var); | |
591 DCHECK_LT(var, ContextLocalCount()); | |
592 int info_index = ContextLocalInfosIndex() + var; | |
593 int value = Smi::cast(get(info_index))->value(); | |
594 return VariableModeField::decode(value); | |
595 } | |
596 | |
597 | |
598 InitializationFlag ScopeInfo::ContextLocalInitFlag(int var) { | |
599 DCHECK_LE(0, var); | |
600 DCHECK_LT(var, ContextLocalCount()); | |
601 int info_index = ContextLocalInfosIndex() + var; | |
602 int value = Smi::cast(get(info_index))->value(); | |
603 return InitFlagField::decode(value); | |
604 } | |
605 | |
606 | |
607 MaybeAssignedFlag ScopeInfo::ContextLocalMaybeAssignedFlag(int var) { | |
608 DCHECK_LE(0, var); | |
609 DCHECK_LT(var, ContextLocalCount()); | |
610 int info_index = ContextLocalInfosIndex() + var; | |
611 int value = Smi::cast(get(info_index))->value(); | |
612 return MaybeAssignedFlagField::decode(value); | |
613 } | |
614 | |
615 bool ScopeInfo::VariableIsSynthetic(String* name) { | |
616 // There's currently no flag stored on the ScopeInfo to indicate that a | |
617 // variable is a compiler-introduced temporary. However, to avoid conflict | |
618 // with user declarations, the current temporaries like .generator_object and | |
619 // .result start with a dot, so we can use that as a flag. It's a hack! | |
620 return name->length() == 0 || name->Get(0) == '.' || | |
621 name->Equals(name->GetHeap()->this_string()); | |
622 } | |
623 | |
624 | |
625 int ScopeInfo::StackSlotIndex(String* name) { | |
626 DCHECK(name->IsInternalizedString()); | |
627 if (length() > 0) { | |
628 int first_slot_index = Smi::cast(get(StackLocalFirstSlotIndex()))->value(); | |
629 int start = StackLocalNamesIndex(); | |
630 int end = start + StackLocalCount(); | |
631 for (int i = start; i < end; ++i) { | |
632 if (name == get(i)) { | |
633 return i - start + first_slot_index; | |
634 } | |
635 } | |
636 } | |
637 return -1; | |
638 } | |
639 | |
640 int ScopeInfo::ModuleIndex(Handle<String> name, VariableMode* mode, | |
641 InitializationFlag* init_flag, | |
642 MaybeAssignedFlag* maybe_assigned_flag) { | |
643 DCHECK_EQ(scope_type(), MODULE_SCOPE); | |
644 DCHECK(name->IsInternalizedString()); | |
645 DCHECK_NOT_NULL(mode); | |
646 DCHECK_NOT_NULL(init_flag); | |
647 DCHECK_NOT_NULL(maybe_assigned_flag); | |
648 | |
649 int module_vars_count = Smi::cast(get(ModuleVariableCountIndex()))->value(); | |
650 int entry = ModuleVariablesIndex(); | |
651 for (int i = 0; i < module_vars_count; ++i) { | |
652 if (*name == get(entry + kModuleVariableNameOffset)) { | |
653 int index; | |
654 ModuleVariable(i, nullptr, &index, mode, init_flag, maybe_assigned_flag); | |
655 return index; | |
656 } | |
657 entry += kModuleVariableEntryLength; | |
658 } | |
659 | |
660 return 0; | |
661 } | |
662 | |
663 int ScopeInfo::ContextSlotIndex(Handle<ScopeInfo> scope_info, | |
664 Handle<String> name, VariableMode* mode, | |
665 InitializationFlag* init_flag, | |
666 MaybeAssignedFlag* maybe_assigned_flag) { | |
667 DCHECK(name->IsInternalizedString()); | |
668 DCHECK_NOT_NULL(mode); | |
669 DCHECK_NOT_NULL(init_flag); | |
670 DCHECK_NOT_NULL(maybe_assigned_flag); | |
671 | |
672 if (scope_info->length() > 0) { | |
673 ContextSlotCache* context_slot_cache = | |
674 scope_info->GetIsolate()->context_slot_cache(); | |
675 int result = context_slot_cache->Lookup(*scope_info, *name, mode, init_flag, | |
676 maybe_assigned_flag); | |
677 if (result != ContextSlotCache::kNotFound) { | |
678 DCHECK_LT(result, scope_info->ContextLength()); | |
679 return result; | |
680 } | |
681 | |
682 int start = scope_info->ContextLocalNamesIndex(); | |
683 int end = start + scope_info->ContextLocalCount(); | |
684 for (int i = start; i < end; ++i) { | |
685 if (*name == scope_info->get(i)) { | |
686 int var = i - start; | |
687 *mode = scope_info->ContextLocalMode(var); | |
688 *init_flag = scope_info->ContextLocalInitFlag(var); | |
689 *maybe_assigned_flag = scope_info->ContextLocalMaybeAssignedFlag(var); | |
690 result = Context::MIN_CONTEXT_SLOTS + var; | |
691 | |
692 context_slot_cache->Update(scope_info, name, *mode, *init_flag, | |
693 *maybe_assigned_flag, result); | |
694 DCHECK_LT(result, scope_info->ContextLength()); | |
695 return result; | |
696 } | |
697 } | |
698 // Cache as not found. Mode, init flag and maybe assigned flag don't matter. | |
699 context_slot_cache->Update(scope_info, name, TEMPORARY, | |
700 kNeedsInitialization, kNotAssigned, -1); | |
701 } | |
702 | |
703 return -1; | |
704 } | |
705 | |
706 String* ScopeInfo::ContextSlotName(int slot_index) { | |
707 int const var = slot_index - Context::MIN_CONTEXT_SLOTS; | |
708 DCHECK_LE(0, var); | |
709 DCHECK_LT(var, ContextLocalCount()); | |
710 return ContextLocalName(var); | |
711 } | |
712 | |
713 | |
714 int ScopeInfo::ParameterIndex(String* name) { | |
715 DCHECK(name->IsInternalizedString()); | |
716 if (length() > 0) { | |
717 // We must read parameters from the end since for | |
718 // multiply declared parameters the value of the | |
719 // last declaration of that parameter is used | |
720 // inside a function (and thus we need to look | |
721 // at the last index). Was bug# 1110337. | |
722 int start = ParameterNamesIndex(); | |
723 int end = start + ParameterCount(); | |
724 for (int i = end - 1; i >= start; --i) { | |
725 if (name == get(i)) { | |
726 return i - start; | |
727 } | |
728 } | |
729 } | |
730 return -1; | |
731 } | |
732 | |
733 | |
734 int ScopeInfo::ReceiverContextSlotIndex() { | |
735 if (length() > 0 && ReceiverVariableField::decode(Flags()) == CONTEXT) | |
736 return Smi::cast(get(ReceiverInfoIndex()))->value(); | |
737 return -1; | |
738 } | |
739 | |
740 int ScopeInfo::FunctionContextSlotIndex(String* name) { | |
741 DCHECK(name->IsInternalizedString()); | |
742 if (length() > 0) { | |
743 if (FunctionVariableField::decode(Flags()) == CONTEXT && | |
744 FunctionName() == name) { | |
745 return Smi::cast(get(FunctionNameInfoIndex() + 1))->value(); | |
746 } | |
747 } | |
748 return -1; | |
749 } | |
750 | |
751 | |
752 FunctionKind ScopeInfo::function_kind() { | |
753 return FunctionKindField::decode(Flags()); | |
754 } | |
755 | |
756 int ScopeInfo::ParameterNamesIndex() { | |
757 DCHECK_LT(0, length()); | |
758 return kVariablePartIndex; | |
759 } | |
760 | |
761 | |
762 int ScopeInfo::StackLocalFirstSlotIndex() { | |
763 return ParameterNamesIndex() + ParameterCount(); | |
764 } | |
765 | |
766 int ScopeInfo::StackLocalNamesIndex() { return StackLocalFirstSlotIndex() + 1; } | |
767 | |
768 int ScopeInfo::ContextLocalNamesIndex() { | |
769 return StackLocalNamesIndex() + StackLocalCount(); | |
770 } | |
771 | |
772 int ScopeInfo::ContextLocalInfosIndex() { | |
773 return ContextLocalNamesIndex() + ContextLocalCount(); | |
774 } | |
775 | |
776 int ScopeInfo::ReceiverInfoIndex() { | |
777 return ContextLocalInfosIndex() + ContextLocalCount(); | |
778 } | |
779 | |
780 int ScopeInfo::FunctionNameInfoIndex() { | |
781 return ReceiverInfoIndex() + (HasAllocatedReceiver() ? 1 : 0); | |
782 } | |
783 | |
784 int ScopeInfo::OuterScopeInfoIndex() { | |
785 return FunctionNameInfoIndex() + (HasFunctionName() ? 2 : 0); | |
786 } | |
787 | |
788 int ScopeInfo::ModuleInfoIndex() { | |
789 return OuterScopeInfoIndex() + (HasOuterScopeInfo() ? 1 : 0); | |
790 } | |
791 | |
792 int ScopeInfo::ModuleVariableCountIndex() { return ModuleInfoIndex() + 1; } | |
793 | |
794 int ScopeInfo::ModuleVariablesIndex() { return ModuleVariableCountIndex() + 1; } | |
795 | |
796 void ScopeInfo::ModuleVariable(int i, String** name, int* index, | |
797 VariableMode* mode, | |
798 InitializationFlag* init_flag, | |
799 MaybeAssignedFlag* maybe_assigned_flag) { | |
800 DCHECK_LE(0, i); | |
801 DCHECK_LT(i, Smi::cast(get(ModuleVariableCountIndex()))->value()); | |
802 | |
803 int entry = ModuleVariablesIndex() + i * kModuleVariableEntryLength; | |
804 int properties = | |
805 Smi::cast(get(entry + kModuleVariablePropertiesOffset))->value(); | |
806 | |
807 if (name != nullptr) { | |
808 *name = String::cast(get(entry + kModuleVariableNameOffset)); | |
809 } | |
810 if (index != nullptr) { | |
811 *index = Smi::cast(get(entry + kModuleVariableIndexOffset))->value(); | |
812 DCHECK_NE(*index, 0); | |
813 } | |
814 if (mode != nullptr) { | |
815 *mode = VariableModeField::decode(properties); | |
816 } | |
817 if (init_flag != nullptr) { | |
818 *init_flag = InitFlagField::decode(properties); | |
819 } | |
820 if (maybe_assigned_flag != nullptr) { | |
821 *maybe_assigned_flag = MaybeAssignedFlagField::decode(properties); | |
822 } | |
823 } | |
824 | |
825 #ifdef DEBUG | |
826 | |
827 static void PrintList(const char* list_name, | |
828 int nof_internal_slots, | |
829 int start, | |
830 int end, | |
831 ScopeInfo* scope_info) { | |
832 if (start < end) { | |
833 PrintF("\n // %s\n", list_name); | |
834 if (nof_internal_slots > 0) { | |
835 PrintF(" %2d - %2d [internal slots]\n", 0 , nof_internal_slots - 1); | |
836 } | |
837 for (int i = nof_internal_slots; start < end; ++i, ++start) { | |
838 PrintF(" %2d ", i); | |
839 String::cast(scope_info->get(start))->ShortPrint(); | |
840 PrintF("\n"); | |
841 } | |
842 } | |
843 } | |
844 | |
845 | |
846 void ScopeInfo::Print() { | |
847 PrintF("ScopeInfo "); | |
848 if (HasFunctionName()) { | |
849 FunctionName()->ShortPrint(); | |
850 } else { | |
851 PrintF("/* no function name */"); | |
852 } | |
853 PrintF("{"); | |
854 | |
855 if (length() > 0) { | |
856 PrintList("parameters", 0, ParameterNamesIndex(), | |
857 ParameterNamesIndex() + ParameterCount(), this); | |
858 PrintList("stack slots", 0, StackLocalNamesIndex(), | |
859 StackLocalNamesIndex() + StackLocalCount(), this); | |
860 PrintList("context slots", Context::MIN_CONTEXT_SLOTS, | |
861 ContextLocalNamesIndex(), | |
862 ContextLocalNamesIndex() + ContextLocalCount(), this); | |
863 // TODO(neis): Print module stuff if present. | |
864 } | |
865 | |
866 PrintF("}\n"); | |
867 } | |
868 #endif // DEBUG | |
869 | |
870 Handle<ModuleInfoEntry> ModuleInfoEntry::New(Isolate* isolate, | |
871 Handle<Object> export_name, | |
872 Handle<Object> local_name, | |
873 Handle<Object> import_name, | |
874 int module_request, int cell_index, | |
875 int beg_pos, int end_pos) { | |
876 Handle<ModuleInfoEntry> result = Handle<ModuleInfoEntry>::cast( | |
877 isolate->factory()->NewStruct(MODULE_INFO_ENTRY_TYPE)); | |
878 result->set_export_name(*export_name); | |
879 result->set_local_name(*local_name); | |
880 result->set_import_name(*import_name); | |
881 result->set_module_request(module_request); | |
882 result->set_cell_index(cell_index); | |
883 result->set_beg_pos(beg_pos); | |
884 result->set_end_pos(end_pos); | |
885 return result; | |
886 } | |
887 | |
888 Handle<ModuleInfo> ModuleInfo::New(Isolate* isolate, Zone* zone, | |
889 ModuleDescriptor* descr) { | |
890 // Serialize module requests. | |
891 Handle<FixedArray> module_requests = isolate->factory()->NewFixedArray( | |
892 static_cast<int>(descr->module_requests().size())); | |
893 for (const auto& elem : descr->module_requests()) { | |
894 module_requests->set(elem.second, *elem.first->string()); | |
895 } | |
896 | |
897 // Serialize special exports. | |
898 Handle<FixedArray> special_exports = | |
899 isolate->factory()->NewFixedArray(descr->special_exports().length()); | |
900 { | |
901 int i = 0; | |
902 for (auto entry : descr->special_exports()) { | |
903 Handle<ModuleInfoEntry> serialized_entry = entry->Serialize(isolate); | |
904 special_exports->set(i++, *serialized_entry); | |
905 } | |
906 } | |
907 | |
908 // Serialize namespace imports. | |
909 Handle<FixedArray> namespace_imports = | |
910 isolate->factory()->NewFixedArray(descr->namespace_imports().length()); | |
911 { | |
912 int i = 0; | |
913 for (auto entry : descr->namespace_imports()) { | |
914 Handle<ModuleInfoEntry> serialized_entry = entry->Serialize(isolate); | |
915 namespace_imports->set(i++, *serialized_entry); | |
916 } | |
917 } | |
918 | |
919 // Serialize regular exports. | |
920 Handle<FixedArray> regular_exports = | |
921 descr->SerializeRegularExports(isolate, zone); | |
922 | |
923 // Serialize regular imports. | |
924 Handle<FixedArray> regular_imports = isolate->factory()->NewFixedArray( | |
925 static_cast<int>(descr->regular_imports().size())); | |
926 { | |
927 int i = 0; | |
928 for (const auto& elem : descr->regular_imports()) { | |
929 Handle<ModuleInfoEntry> serialized_entry = | |
930 elem.second->Serialize(isolate); | |
931 regular_imports->set(i++, *serialized_entry); | |
932 } | |
933 } | |
934 | |
935 Handle<ModuleInfo> result = isolate->factory()->NewModuleInfo(); | |
936 result->set(kModuleRequestsIndex, *module_requests); | |
937 result->set(kSpecialExportsIndex, *special_exports); | |
938 result->set(kRegularExportsIndex, *regular_exports); | |
939 result->set(kNamespaceImportsIndex, *namespace_imports); | |
940 result->set(kRegularImportsIndex, *regular_imports); | |
941 return result; | |
942 } | |
943 | |
944 int ModuleInfo::RegularExportCount() const { | |
945 DCHECK_EQ(regular_exports()->length() % kRegularExportLength, 0); | |
946 return regular_exports()->length() / kRegularExportLength; | |
947 } | |
948 | |
949 String* ModuleInfo::RegularExportLocalName(int i) const { | |
950 return String::cast(regular_exports()->get(i * kRegularExportLength + | |
951 kRegularExportLocalNameOffset)); | |
952 } | |
953 | |
954 int ModuleInfo::RegularExportCellIndex(int i) const { | |
955 return Smi::cast(regular_exports()->get(i * kRegularExportLength + | |
956 kRegularExportCellIndexOffset)) | |
957 ->value(); | |
958 } | |
959 | |
960 FixedArray* ModuleInfo::RegularExportExportNames(int i) const { | |
961 return FixedArray::cast(regular_exports()->get( | |
962 i * kRegularExportLength + kRegularExportExportNamesOffset)); | |
963 } | |
964 | |
965 Handle<ModuleInfoEntry> ModuleInfo::LookupRegularImport( | |
966 Handle<ModuleInfo> info, Handle<String> local_name) { | |
967 Isolate* isolate = info->GetIsolate(); | |
968 Handle<FixedArray> regular_imports(info->regular_imports(), isolate); | |
969 for (int i = 0, n = regular_imports->length(); i < n; ++i) { | |
970 Handle<ModuleInfoEntry> entry( | |
971 ModuleInfoEntry::cast(regular_imports->get(i)), isolate); | |
972 if (String::cast(entry->local_name())->Equals(*local_name)) { | |
973 return entry; | |
974 } | |
975 } | |
976 UNREACHABLE(); | |
977 return Handle<ModuleInfoEntry>(); | |
978 } | |
979 | |
980 } // namespace internal | |
981 } // namespace v8 | |
OLD | NEW |