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
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.
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.
32
#include "scopeinfo.h"
35
#include "allocation-inl.h"
41
Handle<ScopeInfo> ScopeInfo::Create(Scope* scope, Zone* zone) {
42
// Collect stack and context locals.
43
ZoneList<Variable*> stack_locals(scope->StackLocalCount(), zone);
44
ZoneList<Variable*> context_locals(scope->ContextLocalCount(), zone);
45
scope->CollectStackAndContextLocals(&stack_locals, &context_locals);
46
const int stack_local_count = stack_locals.length();
47
const int context_local_count = context_locals.length();
48
// Make sure we allocate the correct amount.
49
ASSERT(scope->StackLocalCount() == stack_local_count);
50
ASSERT(scope->ContextLocalCount() == context_local_count);
52
// Determine use and location of the function variable if it is present.
53
FunctionVariableInfo function_name_info;
54
VariableMode function_variable_mode;
55
if (scope->is_function_scope() && scope->function() != NULL) {
56
Variable* var = scope->function()->proxy()->var();
57
if (!var->is_used()) {
58
function_name_info = UNUSED;
59
} else if (var->IsContextSlot()) {
60
function_name_info = CONTEXT;
62
ASSERT(var->IsStackLocal());
63
function_name_info = STACK;
65
function_variable_mode = var->mode();
67
function_name_info = NONE;
68
function_variable_mode = VAR;
71
const bool has_function_name = function_name_info != NONE;
72
const int parameter_count = scope->num_parameters();
73
const int length = kVariablePartIndex
74
+ parameter_count + stack_local_count + 2 * context_local_count
75
+ (has_function_name ? 2 : 0);
77
Handle<ScopeInfo> scope_info = FACTORY->NewScopeInfo(length);
80
int flags = TypeField::encode(scope->type()) |
81
CallsEvalField::encode(scope->calls_eval()) |
82
LanguageModeField::encode(scope->language_mode()) |
83
FunctionVariableField::encode(function_name_info) |
84
FunctionVariableMode::encode(function_variable_mode);
85
scope_info->SetFlags(flags);
86
scope_info->SetParameterCount(parameter_count);
87
scope_info->SetStackLocalCount(stack_local_count);
88
scope_info->SetContextLocalCount(context_local_count);
90
int index = kVariablePartIndex;
92
ASSERT(index == scope_info->ParameterEntriesIndex());
93
for (int i = 0; i < parameter_count; ++i) {
94
scope_info->set(index++, *scope->parameter(i)->name());
97
// Add stack locals' names. We are assuming that the stack locals'
98
// slots are allocated in increasing order, so we can simply add
99
// them to the ScopeInfo object.
100
ASSERT(index == scope_info->StackLocalEntriesIndex());
101
for (int i = 0; i < stack_local_count; ++i) {
102
ASSERT(stack_locals[i]->index() == i);
103
scope_info->set(index++, *stack_locals[i]->name());
106
// Due to usage analysis, context-allocated locals are not necessarily in
107
// increasing order: Some of them may be parameters which are allocated before
108
// the non-parameter locals. When the non-parameter locals are sorted
109
// according to usage, the allocated slot indices may not be in increasing
110
// order with the variable list anymore. Thus, we first need to sort them by
111
// context slot index before adding them to the ScopeInfo object.
112
context_locals.Sort(&Variable::CompareIndex);
114
// Add context locals' names.
115
ASSERT(index == scope_info->ContextLocalNameEntriesIndex());
116
for (int i = 0; i < context_local_count; ++i) {
117
scope_info->set(index++, *context_locals[i]->name());
120
// Add context locals' info.
121
ASSERT(index == scope_info->ContextLocalInfoEntriesIndex());
122
for (int i = 0; i < context_local_count; ++i) {
123
Variable* var = context_locals[i];
124
uint32_t value = ContextLocalMode::encode(var->mode()) |
125
ContextLocalInitFlag::encode(var->initialization_flag());
126
scope_info->set(index++, Smi::FromInt(value));
129
// If present, add the function variable name and its index.
130
ASSERT(index == scope_info->FunctionNameEntryIndex());
131
if (has_function_name) {
132
int var_index = scope->function()->proxy()->var()->index();
133
scope_info->set(index++, *scope->function()->proxy()->name());
134
scope_info->set(index++, Smi::FromInt(var_index));
135
ASSERT(function_name_info != STACK ||
136
(var_index == scope_info->StackLocalCount() &&
137
var_index == scope_info->StackSlotCount() - 1));
138
ASSERT(function_name_info != CONTEXT ||
139
var_index == scope_info->ContextLength() - 1);
142
ASSERT(index == scope_info->length());
143
ASSERT(scope->num_parameters() == scope_info->ParameterCount());
144
ASSERT(scope->num_stack_slots() == scope_info->StackSlotCount());
145
ASSERT(scope->num_heap_slots() == scope_info->ContextLength() ||
146
(scope->num_heap_slots() == kVariablePartIndex &&
147
scope_info->ContextLength() == 0));
152
ScopeInfo* ScopeInfo::Empty() {
153
return reinterpret_cast<ScopeInfo*>(HEAP->empty_fixed_array());
157
ScopeType ScopeInfo::Type() {
158
ASSERT(length() > 0);
159
return TypeField::decode(Flags());
163
bool ScopeInfo::CallsEval() {
164
return length() > 0 && CallsEvalField::decode(Flags());
168
LanguageMode ScopeInfo::language_mode() {
169
return length() > 0 ? LanguageModeField::decode(Flags()) : CLASSIC_MODE;
173
int ScopeInfo::LocalCount() {
174
return StackLocalCount() + ContextLocalCount();
178
int ScopeInfo::StackSlotCount() {
180
bool function_name_stack_slot =
181
FunctionVariableField::decode(Flags()) == STACK;
182
return StackLocalCount() + (function_name_stack_slot ? 1 : 0);
188
int ScopeInfo::ContextLength() {
190
int context_locals = ContextLocalCount();
191
bool function_name_context_slot =
192
FunctionVariableField::decode(Flags()) == CONTEXT;
193
bool has_context = context_locals > 0 ||
194
function_name_context_slot ||
195
Type() == WITH_SCOPE ||
196
(Type() == FUNCTION_SCOPE && CallsEval()) ||
197
Type() == MODULE_SCOPE;
199
return Context::MIN_CONTEXT_SLOTS + context_locals +
200
(function_name_context_slot ? 1 : 0);
207
bool ScopeInfo::HasFunctionName() {
209
return NONE != FunctionVariableField::decode(Flags());
216
bool ScopeInfo::HasHeapAllocatedLocals() {
218
return ContextLocalCount() > 0;
225
bool ScopeInfo::HasContext() {
226
return ContextLength() > 0;
230
String* ScopeInfo::FunctionName() {
231
ASSERT(HasFunctionName());
232
return String::cast(get(FunctionNameEntryIndex()));
236
String* ScopeInfo::ParameterName(int var) {
237
ASSERT(0 <= var && var < ParameterCount());
238
int info_index = ParameterEntriesIndex() + var;
239
return String::cast(get(info_index));
243
String* ScopeInfo::LocalName(int var) {
244
ASSERT(0 <= var && var < LocalCount());
245
ASSERT(StackLocalEntriesIndex() + StackLocalCount() ==
246
ContextLocalNameEntriesIndex());
247
int info_index = StackLocalEntriesIndex() + var;
248
return String::cast(get(info_index));
252
String* ScopeInfo::StackLocalName(int var) {
253
ASSERT(0 <= var && var < StackLocalCount());
254
int info_index = StackLocalEntriesIndex() + var;
255
return String::cast(get(info_index));
259
String* ScopeInfo::ContextLocalName(int var) {
260
ASSERT(0 <= var && var < ContextLocalCount());
261
int info_index = ContextLocalNameEntriesIndex() + var;
262
return String::cast(get(info_index));
266
VariableMode ScopeInfo::ContextLocalMode(int var) {
267
ASSERT(0 <= var && var < ContextLocalCount());
268
int info_index = ContextLocalInfoEntriesIndex() + var;
269
int value = Smi::cast(get(info_index))->value();
270
return ContextLocalMode::decode(value);
274
InitializationFlag ScopeInfo::ContextLocalInitFlag(int var) {
275
ASSERT(0 <= var && var < ContextLocalCount());
276
int info_index = ContextLocalInfoEntriesIndex() + var;
277
int value = Smi::cast(get(info_index))->value();
278
return ContextLocalInitFlag::decode(value);
282
int ScopeInfo::StackSlotIndex(String* name) {
283
ASSERT(name->IsSymbol());
285
int start = StackLocalEntriesIndex();
286
int end = StackLocalEntriesIndex() + StackLocalCount();
287
for (int i = start; i < end; ++i) {
288
if (name == get(i)) {
297
int ScopeInfo::ContextSlotIndex(String* name,
299
InitializationFlag* init_flag) {
300
ASSERT(name->IsSymbol());
301
ASSERT(mode != NULL);
302
ASSERT(init_flag != NULL);
304
ContextSlotCache* context_slot_cache = GetIsolate()->context_slot_cache();
305
int result = context_slot_cache->Lookup(this, name, mode, init_flag);
306
if (result != ContextSlotCache::kNotFound) {
307
ASSERT(result < ContextLength());
311
int start = ContextLocalNameEntriesIndex();
312
int end = ContextLocalNameEntriesIndex() + ContextLocalCount();
313
for (int i = start; i < end; ++i) {
314
if (name == get(i)) {
316
*mode = ContextLocalMode(var);
317
*init_flag = ContextLocalInitFlag(var);
318
result = Context::MIN_CONTEXT_SLOTS + var;
319
context_slot_cache->Update(this, name, *mode, *init_flag, result);
320
ASSERT(result < ContextLength());
324
context_slot_cache->Update(this, name, INTERNAL, kNeedsInitialization, -1);
330
int ScopeInfo::ParameterIndex(String* name) {
331
ASSERT(name->IsSymbol());
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)) {
350
int ScopeInfo::FunctionContextSlotIndex(String* name, VariableMode* mode) {
351
ASSERT(name->IsSymbol());
352
ASSERT(mode != NULL);
354
if (FunctionVariableField::decode(Flags()) == CONTEXT &&
355
FunctionName() == name) {
356
*mode = FunctionVariableMode::decode(Flags());
357
return Smi::cast(get(FunctionNameEntryIndex() + 1))->value();
364
int ScopeInfo::ParameterEntriesIndex() {
365
ASSERT(length() > 0);
366
return kVariablePartIndex;
370
int ScopeInfo::StackLocalEntriesIndex() {
371
return ParameterEntriesIndex() + ParameterCount();
375
int ScopeInfo::ContextLocalNameEntriesIndex() {
376
return StackLocalEntriesIndex() + StackLocalCount();
380
int ScopeInfo::ContextLocalInfoEntriesIndex() {
381
return ContextLocalNameEntriesIndex() + ContextLocalCount();
385
int ScopeInfo::FunctionNameEntryIndex() {
386
return ContextLocalInfoEntriesIndex() + ContextLocalCount();
390
int ContextSlotCache::Hash(Object* data, String* name) {
391
// Uses only lower 32 bits if pointers are larger.
392
uintptr_t addr_hash =
393
static_cast<uint32_t>(reinterpret_cast<uintptr_t>(data)) >> 2;
394
return static_cast<int>((addr_hash ^ name->Hash()) % kLength);
398
int ContextSlotCache::Lookup(Object* data,
401
InitializationFlag* init_flag) {
402
int index = Hash(data, name);
403
Key& key = keys_[index];
404
if ((key.data == data) && key.name->Equals(name)) {
405
Value result(values_[index]);
406
if (mode != NULL) *mode = result.mode();
407
if (init_flag != NULL) *init_flag = result.initialization_flag();
408
return result.index() + kNotFound;
414
void ContextSlotCache::Update(Object* data,
417
InitializationFlag init_flag,
420
ASSERT(slot_index > kNotFound);
421
if (HEAP->LookupSymbolIfExists(name, &symbol)) {
422
int index = Hash(data, symbol);
423
Key& key = keys_[index];
426
// Please note value only takes a uint as index.
427
values_[index] = Value(mode, init_flag, slot_index - kNotFound).raw();
429
ValidateEntry(data, name, mode, init_flag, slot_index);
435
void ContextSlotCache::Clear() {
436
for (int index = 0; index < kLength; index++) keys_[index].data = NULL;
442
void ContextSlotCache::ValidateEntry(Object* data,
445
InitializationFlag init_flag,
448
if (HEAP->LookupSymbolIfExists(name, &symbol)) {
449
int index = Hash(data, name);
450
Key& key = keys_[index];
451
ASSERT(key.data == data);
452
ASSERT(key.name->Equals(name));
453
Value result(values_[index]);
454
ASSERT(result.mode() == mode);
455
ASSERT(result.initialization_flag() == init_flag);
456
ASSERT(result.index() + kNotFound == slot_index);
461
static void PrintList(const char* list_name,
462
int nof_internal_slots,
465
ScopeInfo* scope_info) {
467
PrintF("\n // %s\n", list_name);
468
if (nof_internal_slots > 0) {
469
PrintF(" %2d - %2d [internal slots]\n", 0 , nof_internal_slots - 1);
471
for (int i = nof_internal_slots; start < end; ++i, ++start) {
473
String::cast(scope_info->get(start))->ShortPrint();
480
void ScopeInfo::Print() {
481
PrintF("ScopeInfo ");
482
if (HasFunctionName()) {
483
FunctionName()->ShortPrint();
485
PrintF("/* no function name */");
489
PrintList("parameters", 0,
490
ParameterEntriesIndex(),
491
ParameterEntriesIndex() + ParameterCount(),
493
PrintList("stack slots", 0,
494
StackLocalEntriesIndex(),
495
StackLocalEntriesIndex() + StackLocalCount(),
497
PrintList("context slots",
498
Context::MIN_CONTEXT_SLOTS,
499
ContextLocalNameEntriesIndex(),
500
ContextLocalNameEntriesIndex() + ContextLocalCount(),
507
} } // namespace v8::internal