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