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