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/v8.h"
8
9 #include "src/scopeinfo.h"
10 #include "src/scopes.h"
11
12 namespace v8 {
13 namespace internal {
14
15
Create(Scope * scope,Zone * zone)16 Handle<ScopeInfo> ScopeInfo::Create(Scope* scope, Zone* zone) {
17 // Collect stack and context locals.
18 ZoneList<Variable*> stack_locals(scope->StackLocalCount(), zone);
19 ZoneList<Variable*> context_locals(scope->ContextLocalCount(), zone);
20 scope->CollectStackAndContextLocals(&stack_locals, &context_locals);
21 const int stack_local_count = stack_locals.length();
22 const int context_local_count = context_locals.length();
23 // Make sure we allocate the correct amount.
24 DCHECK(scope->StackLocalCount() == stack_local_count);
25 DCHECK(scope->ContextLocalCount() == context_local_count);
26
27 // Determine use and location of the function variable if it is present.
28 FunctionVariableInfo function_name_info;
29 VariableMode function_variable_mode;
30 if (scope->is_function_scope() && scope->function() != NULL) {
31 Variable* var = scope->function()->proxy()->var();
32 if (!var->is_used()) {
33 function_name_info = UNUSED;
34 } else if (var->IsContextSlot()) {
35 function_name_info = CONTEXT;
36 } else {
37 DCHECK(var->IsStackLocal());
38 function_name_info = STACK;
39 }
40 function_variable_mode = var->mode();
41 } else {
42 function_name_info = NONE;
43 function_variable_mode = VAR;
44 }
45
46 const bool has_function_name = function_name_info != NONE;
47 const int parameter_count = scope->num_parameters();
48 const int length = kVariablePartIndex
49 + parameter_count + stack_local_count + 2 * context_local_count
50 + (has_function_name ? 2 : 0);
51
52 Factory* factory = zone->isolate()->factory();
53 Handle<ScopeInfo> scope_info = factory->NewScopeInfo(length);
54
55 // Encode the flags.
56 int flags = ScopeTypeField::encode(scope->scope_type()) |
57 CallsEvalField::encode(scope->calls_eval()) |
58 StrictModeField::encode(scope->strict_mode()) |
59 FunctionVariableField::encode(function_name_info) |
60 FunctionVariableMode::encode(function_variable_mode) |
61 AsmModuleField::encode(scope->asm_module()) |
62 AsmFunctionField::encode(scope->asm_function());
63 scope_info->SetFlags(flags);
64 scope_info->SetParameterCount(parameter_count);
65 scope_info->SetStackLocalCount(stack_local_count);
66 scope_info->SetContextLocalCount(context_local_count);
67
68 int index = kVariablePartIndex;
69 // Add parameters.
70 DCHECK(index == scope_info->ParameterEntriesIndex());
71 for (int i = 0; i < parameter_count; ++i) {
72 scope_info->set(index++, *scope->parameter(i)->name());
73 }
74
75 // Add stack locals' names. We are assuming that the stack locals'
76 // slots are allocated in increasing order, so we can simply add
77 // them to the ScopeInfo object.
78 DCHECK(index == scope_info->StackLocalEntriesIndex());
79 for (int i = 0; i < stack_local_count; ++i) {
80 DCHECK(stack_locals[i]->index() == i);
81 scope_info->set(index++, *stack_locals[i]->name());
82 }
83
84 // Due to usage analysis, context-allocated locals are not necessarily in
85 // increasing order: Some of them may be parameters which are allocated before
86 // the non-parameter locals. When the non-parameter locals are sorted
87 // according to usage, the allocated slot indices may not be in increasing
88 // order with the variable list anymore. Thus, we first need to sort them by
89 // context slot index before adding them to the ScopeInfo object.
90 context_locals.Sort(&Variable::CompareIndex);
91
92 // Add context locals' names.
93 DCHECK(index == scope_info->ContextLocalNameEntriesIndex());
94 for (int i = 0; i < context_local_count; ++i) {
95 scope_info->set(index++, *context_locals[i]->name());
96 }
97
98 // Add context locals' info.
99 DCHECK(index == scope_info->ContextLocalInfoEntriesIndex());
100 for (int i = 0; i < context_local_count; ++i) {
101 Variable* var = context_locals[i];
102 uint32_t value =
103 ContextLocalMode::encode(var->mode()) |
104 ContextLocalInitFlag::encode(var->initialization_flag()) |
105 ContextLocalMaybeAssignedFlag::encode(var->maybe_assigned());
106 scope_info->set(index++, Smi::FromInt(value));
107 }
108
109 // If present, add the function variable name and its index.
110 DCHECK(index == scope_info->FunctionNameEntryIndex());
111 if (has_function_name) {
112 int var_index = scope->function()->proxy()->var()->index();
113 scope_info->set(index++, *scope->function()->proxy()->name());
114 scope_info->set(index++, Smi::FromInt(var_index));
115 DCHECK(function_name_info != STACK ||
116 (var_index == scope_info->StackLocalCount() &&
117 var_index == scope_info->StackSlotCount() - 1));
118 DCHECK(function_name_info != CONTEXT ||
119 var_index == scope_info->ContextLength() - 1);
120 }
121
122 DCHECK(index == scope_info->length());
123 DCHECK(scope->num_parameters() == scope_info->ParameterCount());
124 DCHECK(scope->num_stack_slots() == scope_info->StackSlotCount());
125 DCHECK(scope->num_heap_slots() == scope_info->ContextLength() ||
126 (scope->num_heap_slots() == kVariablePartIndex &&
127 scope_info->ContextLength() == 0));
128 return scope_info;
129 }
130
131
Empty(Isolate * isolate)132 ScopeInfo* ScopeInfo::Empty(Isolate* isolate) {
133 return reinterpret_cast<ScopeInfo*>(isolate->heap()->empty_fixed_array());
134 }
135
136
scope_type()137 ScopeType ScopeInfo::scope_type() {
138 DCHECK(length() > 0);
139 return ScopeTypeField::decode(Flags());
140 }
141
142
CallsEval()143 bool ScopeInfo::CallsEval() {
144 return length() > 0 && CallsEvalField::decode(Flags());
145 }
146
147
strict_mode()148 StrictMode ScopeInfo::strict_mode() {
149 return length() > 0 ? StrictModeField::decode(Flags()) : SLOPPY;
150 }
151
152
LocalCount()153 int ScopeInfo::LocalCount() {
154 return StackLocalCount() + ContextLocalCount();
155 }
156
157
StackSlotCount()158 int ScopeInfo::StackSlotCount() {
159 if (length() > 0) {
160 bool function_name_stack_slot =
161 FunctionVariableField::decode(Flags()) == STACK;
162 return StackLocalCount() + (function_name_stack_slot ? 1 : 0);
163 }
164 return 0;
165 }
166
167
ContextLength()168 int ScopeInfo::ContextLength() {
169 if (length() > 0) {
170 int context_locals = ContextLocalCount();
171 bool function_name_context_slot =
172 FunctionVariableField::decode(Flags()) == CONTEXT;
173 bool has_context = context_locals > 0 ||
174 function_name_context_slot ||
175 scope_type() == WITH_SCOPE ||
176 (scope_type() == FUNCTION_SCOPE && CallsEval()) ||
177 scope_type() == MODULE_SCOPE;
178 if (has_context) {
179 return Context::MIN_CONTEXT_SLOTS + context_locals +
180 (function_name_context_slot ? 1 : 0);
181 }
182 }
183 return 0;
184 }
185
186
HasFunctionName()187 bool ScopeInfo::HasFunctionName() {
188 if (length() > 0) {
189 return NONE != FunctionVariableField::decode(Flags());
190 } else {
191 return false;
192 }
193 }
194
195
HasHeapAllocatedLocals()196 bool ScopeInfo::HasHeapAllocatedLocals() {
197 if (length() > 0) {
198 return ContextLocalCount() > 0;
199 } else {
200 return false;
201 }
202 }
203
204
HasContext()205 bool ScopeInfo::HasContext() {
206 return ContextLength() > 0;
207 }
208
209
FunctionName()210 String* ScopeInfo::FunctionName() {
211 DCHECK(HasFunctionName());
212 return String::cast(get(FunctionNameEntryIndex()));
213 }
214
215
ParameterName(int var)216 String* ScopeInfo::ParameterName(int var) {
217 DCHECK(0 <= var && var < ParameterCount());
218 int info_index = ParameterEntriesIndex() + var;
219 return String::cast(get(info_index));
220 }
221
222
LocalName(int var)223 String* ScopeInfo::LocalName(int var) {
224 DCHECK(0 <= var && var < LocalCount());
225 DCHECK(StackLocalEntriesIndex() + StackLocalCount() ==
226 ContextLocalNameEntriesIndex());
227 int info_index = StackLocalEntriesIndex() + var;
228 return String::cast(get(info_index));
229 }
230
231
StackLocalName(int var)232 String* ScopeInfo::StackLocalName(int var) {
233 DCHECK(0 <= var && var < StackLocalCount());
234 int info_index = StackLocalEntriesIndex() + var;
235 return String::cast(get(info_index));
236 }
237
238
ContextLocalName(int var)239 String* ScopeInfo::ContextLocalName(int var) {
240 DCHECK(0 <= var && var < ContextLocalCount());
241 int info_index = ContextLocalNameEntriesIndex() + var;
242 return String::cast(get(info_index));
243 }
244
245
ContextLocalMode(int var)246 VariableMode ScopeInfo::ContextLocalMode(int var) {
247 DCHECK(0 <= var && var < ContextLocalCount());
248 int info_index = ContextLocalInfoEntriesIndex() + var;
249 int value = Smi::cast(get(info_index))->value();
250 return ContextLocalMode::decode(value);
251 }
252
253
ContextLocalInitFlag(int var)254 InitializationFlag ScopeInfo::ContextLocalInitFlag(int var) {
255 DCHECK(0 <= var && var < ContextLocalCount());
256 int info_index = ContextLocalInfoEntriesIndex() + var;
257 int value = Smi::cast(get(info_index))->value();
258 return ContextLocalInitFlag::decode(value);
259 }
260
261
ContextLocalMaybeAssignedFlag(int var)262 MaybeAssignedFlag ScopeInfo::ContextLocalMaybeAssignedFlag(int var) {
263 DCHECK(0 <= var && var < ContextLocalCount());
264 int info_index = ContextLocalInfoEntriesIndex() + var;
265 int value = Smi::cast(get(info_index))->value();
266 return ContextLocalMaybeAssignedFlag::decode(value);
267 }
268
269
LocalIsSynthetic(int var)270 bool ScopeInfo::LocalIsSynthetic(int var) {
271 DCHECK(0 <= var && var < LocalCount());
272 // There's currently no flag stored on the ScopeInfo to indicate that a
273 // variable is a compiler-introduced temporary. However, to avoid conflict
274 // with user declarations, the current temporaries like .generator_object and
275 // .result start with a dot, so we can use that as a flag. It's a hack!
276 Handle<String> name(LocalName(var));
277 return name->length() > 0 && name->Get(0) == '.';
278 }
279
280
StackSlotIndex(String * name)281 int ScopeInfo::StackSlotIndex(String* name) {
282 DCHECK(name->IsInternalizedString());
283 if (length() > 0) {
284 int start = StackLocalEntriesIndex();
285 int end = StackLocalEntriesIndex() + StackLocalCount();
286 for (int i = start; i < end; ++i) {
287 if (name == get(i)) {
288 return i - start;
289 }
290 }
291 }
292 return -1;
293 }
294
295
ContextSlotIndex(Handle<ScopeInfo> scope_info,Handle<String> name,VariableMode * mode,InitializationFlag * init_flag,MaybeAssignedFlag * maybe_assigned_flag)296 int ScopeInfo::ContextSlotIndex(Handle<ScopeInfo> scope_info,
297 Handle<String> name, VariableMode* mode,
298 InitializationFlag* init_flag,
299 MaybeAssignedFlag* maybe_assigned_flag) {
300 DCHECK(name->IsInternalizedString());
301 DCHECK(mode != NULL);
302 DCHECK(init_flag != NULL);
303 if (scope_info->length() > 0) {
304 ContextSlotCache* context_slot_cache =
305 scope_info->GetIsolate()->context_slot_cache();
306 int result = context_slot_cache->Lookup(*scope_info, *name, mode, init_flag,
307 maybe_assigned_flag);
308 if (result != ContextSlotCache::kNotFound) {
309 DCHECK(result < scope_info->ContextLength());
310 return result;
311 }
312
313 int start = scope_info->ContextLocalNameEntriesIndex();
314 int end = scope_info->ContextLocalNameEntriesIndex() +
315 scope_info->ContextLocalCount();
316 for (int i = start; i < end; ++i) {
317 if (*name == scope_info->get(i)) {
318 int var = i - start;
319 *mode = scope_info->ContextLocalMode(var);
320 *init_flag = scope_info->ContextLocalInitFlag(var);
321 *maybe_assigned_flag = scope_info->ContextLocalMaybeAssignedFlag(var);
322 result = Context::MIN_CONTEXT_SLOTS + var;
323 context_slot_cache->Update(scope_info, name, *mode, *init_flag,
324 *maybe_assigned_flag, result);
325 DCHECK(result < scope_info->ContextLength());
326 return result;
327 }
328 }
329 // Cache as not found. Mode, init flag and maybe assigned flag don't matter.
330 context_slot_cache->Update(scope_info, name, INTERNAL, kNeedsInitialization,
331 kNotAssigned, -1);
332 }
333 return -1;
334 }
335
336
ParameterIndex(String * name)337 int ScopeInfo::ParameterIndex(String* name) {
338 DCHECK(name->IsInternalizedString());
339 if (length() > 0) {
340 // We must read parameters from the end since for
341 // multiply declared parameters the value of the
342 // last declaration of that parameter is used
343 // inside a function (and thus we need to look
344 // at the last index). Was bug# 1110337.
345 int start = ParameterEntriesIndex();
346 int end = ParameterEntriesIndex() + ParameterCount();
347 for (int i = end - 1; i >= start; --i) {
348 if (name == get(i)) {
349 return i - start;
350 }
351 }
352 }
353 return -1;
354 }
355
356
FunctionContextSlotIndex(String * name,VariableMode * mode)357 int ScopeInfo::FunctionContextSlotIndex(String* name, VariableMode* mode) {
358 DCHECK(name->IsInternalizedString());
359 DCHECK(mode != NULL);
360 if (length() > 0) {
361 if (FunctionVariableField::decode(Flags()) == CONTEXT &&
362 FunctionName() == name) {
363 *mode = FunctionVariableMode::decode(Flags());
364 return Smi::cast(get(FunctionNameEntryIndex() + 1))->value();
365 }
366 }
367 return -1;
368 }
369
370
CopyContextLocalsToScopeObject(Handle<ScopeInfo> scope_info,Handle<Context> context,Handle<JSObject> scope_object)371 bool ScopeInfo::CopyContextLocalsToScopeObject(Handle<ScopeInfo> scope_info,
372 Handle<Context> context,
373 Handle<JSObject> scope_object) {
374 Isolate* isolate = scope_info->GetIsolate();
375 int local_count = scope_info->ContextLocalCount();
376 if (local_count == 0) return true;
377 // Fill all context locals to the context extension.
378 int first_context_var = scope_info->StackLocalCount();
379 int start = scope_info->ContextLocalNameEntriesIndex();
380 for (int i = 0; i < local_count; ++i) {
381 if (scope_info->LocalIsSynthetic(first_context_var + i)) continue;
382 int context_index = Context::MIN_CONTEXT_SLOTS + i;
383 RETURN_ON_EXCEPTION_VALUE(
384 isolate,
385 Runtime::DefineObjectProperty(
386 scope_object,
387 Handle<String>(String::cast(scope_info->get(i + start))),
388 Handle<Object>(context->get(context_index), isolate),
389 ::NONE),
390 false);
391 }
392 return true;
393 }
394
395
ParameterEntriesIndex()396 int ScopeInfo::ParameterEntriesIndex() {
397 DCHECK(length() > 0);
398 return kVariablePartIndex;
399 }
400
401
StackLocalEntriesIndex()402 int ScopeInfo::StackLocalEntriesIndex() {
403 return ParameterEntriesIndex() + ParameterCount();
404 }
405
406
ContextLocalNameEntriesIndex()407 int ScopeInfo::ContextLocalNameEntriesIndex() {
408 return StackLocalEntriesIndex() + StackLocalCount();
409 }
410
411
ContextLocalInfoEntriesIndex()412 int ScopeInfo::ContextLocalInfoEntriesIndex() {
413 return ContextLocalNameEntriesIndex() + ContextLocalCount();
414 }
415
416
FunctionNameEntryIndex()417 int ScopeInfo::FunctionNameEntryIndex() {
418 return ContextLocalInfoEntriesIndex() + ContextLocalCount();
419 }
420
421
Hash(Object * data,String * name)422 int ContextSlotCache::Hash(Object* data, String* name) {
423 // Uses only lower 32 bits if pointers are larger.
424 uintptr_t addr_hash =
425 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(data)) >> 2;
426 return static_cast<int>((addr_hash ^ name->Hash()) % kLength);
427 }
428
429
Lookup(Object * data,String * name,VariableMode * mode,InitializationFlag * init_flag,MaybeAssignedFlag * maybe_assigned_flag)430 int ContextSlotCache::Lookup(Object* data, String* name, VariableMode* mode,
431 InitializationFlag* init_flag,
432 MaybeAssignedFlag* maybe_assigned_flag) {
433 int index = Hash(data, name);
434 Key& key = keys_[index];
435 if ((key.data == data) && key.name->Equals(name)) {
436 Value result(values_[index]);
437 if (mode != NULL) *mode = result.mode();
438 if (init_flag != NULL) *init_flag = result.initialization_flag();
439 if (maybe_assigned_flag != NULL)
440 *maybe_assigned_flag = result.maybe_assigned_flag();
441 return result.index() + kNotFound;
442 }
443 return kNotFound;
444 }
445
446
Update(Handle<Object> data,Handle<String> name,VariableMode mode,InitializationFlag init_flag,MaybeAssignedFlag maybe_assigned_flag,int slot_index)447 void ContextSlotCache::Update(Handle<Object> data, Handle<String> name,
448 VariableMode mode, InitializationFlag init_flag,
449 MaybeAssignedFlag maybe_assigned_flag,
450 int slot_index) {
451 DisallowHeapAllocation no_gc;
452 Handle<String> internalized_name;
453 DCHECK(slot_index > kNotFound);
454 if (StringTable::InternalizeStringIfExists(name->GetIsolate(), name).
455 ToHandle(&internalized_name)) {
456 int index = Hash(*data, *internalized_name);
457 Key& key = keys_[index];
458 key.data = *data;
459 key.name = *internalized_name;
460 // Please note value only takes a uint as index.
461 values_[index] = Value(mode, init_flag, maybe_assigned_flag,
462 slot_index - kNotFound).raw();
463 #ifdef DEBUG
464 ValidateEntry(data, name, mode, init_flag, maybe_assigned_flag, slot_index);
465 #endif
466 }
467 }
468
469
Clear()470 void ContextSlotCache::Clear() {
471 for (int index = 0; index < kLength; index++) keys_[index].data = NULL;
472 }
473
474
475 #ifdef DEBUG
476
ValidateEntry(Handle<Object> data,Handle<String> name,VariableMode mode,InitializationFlag init_flag,MaybeAssignedFlag maybe_assigned_flag,int slot_index)477 void ContextSlotCache::ValidateEntry(Handle<Object> data, Handle<String> name,
478 VariableMode mode,
479 InitializationFlag init_flag,
480 MaybeAssignedFlag maybe_assigned_flag,
481 int slot_index) {
482 DisallowHeapAllocation no_gc;
483 Handle<String> internalized_name;
484 if (StringTable::InternalizeStringIfExists(name->GetIsolate(), name).
485 ToHandle(&internalized_name)) {
486 int index = Hash(*data, *name);
487 Key& key = keys_[index];
488 DCHECK(key.data == *data);
489 DCHECK(key.name->Equals(*name));
490 Value result(values_[index]);
491 DCHECK(result.mode() == mode);
492 DCHECK(result.initialization_flag() == init_flag);
493 DCHECK(result.maybe_assigned_flag() == maybe_assigned_flag);
494 DCHECK(result.index() + kNotFound == slot_index);
495 }
496 }
497
498
PrintList(const char * list_name,int nof_internal_slots,int start,int end,ScopeInfo * scope_info)499 static void PrintList(const char* list_name,
500 int nof_internal_slots,
501 int start,
502 int end,
503 ScopeInfo* scope_info) {
504 if (start < end) {
505 PrintF("\n // %s\n", list_name);
506 if (nof_internal_slots > 0) {
507 PrintF(" %2d - %2d [internal slots]\n", 0 , nof_internal_slots - 1);
508 }
509 for (int i = nof_internal_slots; start < end; ++i, ++start) {
510 PrintF(" %2d ", i);
511 String::cast(scope_info->get(start))->ShortPrint();
512 PrintF("\n");
513 }
514 }
515 }
516
517
Print()518 void ScopeInfo::Print() {
519 PrintF("ScopeInfo ");
520 if (HasFunctionName()) {
521 FunctionName()->ShortPrint();
522 } else {
523 PrintF("/* no function name */");
524 }
525 PrintF("{");
526
527 PrintList("parameters", 0,
528 ParameterEntriesIndex(),
529 ParameterEntriesIndex() + ParameterCount(),
530 this);
531 PrintList("stack slots", 0,
532 StackLocalEntriesIndex(),
533 StackLocalEntriesIndex() + StackLocalCount(),
534 this);
535 PrintList("context slots",
536 Context::MIN_CONTEXT_SLOTS,
537 ContextLocalNameEntriesIndex(),
538 ContextLocalNameEntriesIndex() + ContextLocalCount(),
539 this);
540
541 PrintF("}\n");
542 }
543 #endif // DEBUG
544
545
546 //---------------------------------------------------------------------------
547 // ModuleInfo.
548
Create(Isolate * isolate,Interface * interface,Scope * scope)549 Handle<ModuleInfo> ModuleInfo::Create(
550 Isolate* isolate, Interface* interface, Scope* scope) {
551 Handle<ModuleInfo> info = Allocate(isolate, interface->Length());
552 info->set_host_index(interface->Index());
553 int i = 0;
554 for (Interface::Iterator it = interface->iterator();
555 !it.done(); it.Advance(), ++i) {
556 Variable* var = scope->LookupLocal(it.name());
557 info->set_name(i, *(it.name()->string()));
558 info->set_mode(i, var->mode());
559 DCHECK((var->mode() == MODULE) == (it.interface()->IsModule()));
560 if (var->mode() == MODULE) {
561 DCHECK(it.interface()->IsFrozen());
562 DCHECK(it.interface()->Index() >= 0);
563 info->set_index(i, it.interface()->Index());
564 } else {
565 DCHECK(var->index() >= 0);
566 info->set_index(i, var->index());
567 }
568 }
569 DCHECK(i == info->length());
570 return info;
571 }
572
573 } } // namespace v8::internal
574