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