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.
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);
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;
37 ASSERT(var->IsStackLocal());
38 function_name_info = STACK;
40 function_variable_mode = var->mode();
42 function_name_info = NONE;
43 function_variable_mode = VAR;
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);
52 Factory* factory = zone->isolate()->factory();
53 Handle<ScopeInfo> scope_info = factory->NewScopeInfo(length);
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);
66 int index = kVariablePartIndex;
68 ASSERT(index == scope_info->ParameterEntriesIndex());
69 for (int i = 0; i < parameter_count; ++i) {
70 scope_info->set(index++, *scope->parameter(i)->name());
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());
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);
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());
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));
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);
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));
128 ScopeInfo* ScopeInfo::Empty(Isolate* isolate) {
129 return reinterpret_cast<ScopeInfo*>(isolate->heap()->empty_fixed_array());
133 ScopeType ScopeInfo::scope_type() {
134 ASSERT(length() > 0);
135 return ScopeTypeField::decode(Flags());
139 bool ScopeInfo::CallsEval() {
140 return length() > 0 && CallsEvalField::decode(Flags());
144 StrictMode ScopeInfo::strict_mode() {
145 return length() > 0 ? StrictModeField::decode(Flags()) : SLOPPY;
149 int ScopeInfo::LocalCount() {
150 return StackLocalCount() + ContextLocalCount();
154 int ScopeInfo::StackSlotCount() {
156 bool function_name_stack_slot =
157 FunctionVariableField::decode(Flags()) == STACK;
158 return StackLocalCount() + (function_name_stack_slot ? 1 : 0);
164 int ScopeInfo::ContextLength() {
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;
175 return Context::MIN_CONTEXT_SLOTS + context_locals +
176 (function_name_context_slot ? 1 : 0);
183 bool ScopeInfo::HasFunctionName() {
185 return NONE != FunctionVariableField::decode(Flags());
192 bool ScopeInfo::HasHeapAllocatedLocals() {
194 return ContextLocalCount() > 0;
201 bool ScopeInfo::HasContext() {
202 return ContextLength() > 0;
206 String* ScopeInfo::FunctionName() {
207 ASSERT(HasFunctionName());
208 return String::cast(get(FunctionNameEntryIndex()));
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));
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));
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));
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));
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);
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);
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) == '.';
269 int ScopeInfo::StackSlotIndex(String* name) {
270 ASSERT(name->IsInternalizedString());
272 int start = StackLocalEntriesIndex();
273 int end = StackLocalEntriesIndex() + StackLocalCount();
274 for (int i = start; i < end; ++i) {
275 if (name == get(i)) {
284 int ScopeInfo::ContextSlotIndex(Handle<ScopeInfo> scope_info,
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();
295 context_slot_cache->Lookup(*scope_info, *name, mode, init_flag);
296 if (result != ContextSlotCache::kNotFound) {
297 ASSERT(result < scope_info->ContextLength());
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)) {
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());
315 // Cache as not found. Mode and init flag don't matter.
316 context_slot_cache->Update(
317 scope_info, name, INTERNAL, kNeedsInitialization, -1);
323 int ScopeInfo::ParameterIndex(String* name) {
324 ASSERT(name->IsInternalizedString());
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)) {
343 int ScopeInfo::FunctionContextSlotIndex(String* name, VariableMode* mode) {
344 ASSERT(name->IsInternalizedString());
345 ASSERT(mode != NULL);
347 if (FunctionVariableField::decode(Flags()) == CONTEXT &&
348 FunctionName() == name) {
349 *mode = FunctionVariableMode::decode(Flags());
350 return Smi::cast(get(FunctionNameEntryIndex() + 1))->value();
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(
371 Runtime::SetObjectProperty(
374 Handle<String>(String::cast(scope_info->get(i + start))),
375 Handle<Object>(context->get(context_index), isolate),
384 int ScopeInfo::ParameterEntriesIndex() {
385 ASSERT(length() > 0);
386 return kVariablePartIndex;
390 int ScopeInfo::StackLocalEntriesIndex() {
391 return ParameterEntriesIndex() + ParameterCount();
395 int ScopeInfo::ContextLocalNameEntriesIndex() {
396 return StackLocalEntriesIndex() + StackLocalCount();
400 int ScopeInfo::ContextLocalInfoEntriesIndex() {
401 return ContextLocalNameEntriesIndex() + ContextLocalCount();
405 int ScopeInfo::FunctionNameEntryIndex() {
406 return ContextLocalInfoEntriesIndex() + ContextLocalCount();
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);
418 int ContextSlotCache::Lookup(Object* data,
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;
434 void ContextSlotCache::Update(Handle<Object> data,
437 InitializationFlag init_flag,
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];
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();
451 ValidateEntry(data, name, mode, init_flag, slot_index);
457 void ContextSlotCache::Clear() {
458 for (int index = 0; index < kLength; index++) keys_[index].data = NULL;
464 void ContextSlotCache::ValidateEntry(Handle<Object> data,
467 InitializationFlag init_flag,
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);
485 static void PrintList(const char* list_name,
486 int nof_internal_slots,
489 ScopeInfo* scope_info) {
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);
495 for (int i = nof_internal_slots; start < end; ++i, ++start) {
497 String::cast(scope_info->get(start))->ShortPrint();
504 void ScopeInfo::Print() {
505 PrintF("ScopeInfo ");
506 if (HasFunctionName()) {
507 FunctionName()->ShortPrint();
509 PrintF("/* no function name */");
513 PrintList("parameters", 0,
514 ParameterEntriesIndex(),
515 ParameterEntriesIndex() + ParameterCount(),
517 PrintList("stack slots", 0,
518 StackLocalEntriesIndex(),
519 StackLocalEntriesIndex() + StackLocalCount(),
521 PrintList("context slots",
522 Context::MIN_CONTEXT_SLOTS,
523 ContextLocalNameEntriesIndex(),
524 ContextLocalNameEntriesIndex() + ContextLocalCount(),
532 //---------------------------------------------------------------------------
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());
540 for (Interface::Iterator it = interface->iterator();
541 !it.done(); it.Advance(), ++i) {
542 Variable* var = scope->LocalLookup(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());
551 ASSERT(var->index() >= 0);
552 info->set_index(i, var->index());
555 ASSERT(i == info->length());
559 } } // namespace v8::internal