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 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 128 ScopeInfo* ScopeInfo::Empty(Isolate* isolate) { 129 return reinterpret_cast<ScopeInfo*>(isolate->heap()->empty_fixed_array()); 130 } 131 132 133 ScopeType ScopeInfo::scope_type() { 134 ASSERT(length() > 0); 135 return ScopeTypeField::decode(Flags()); 136 } 137 138 139 bool ScopeInfo::CallsEval() { 140 return length() > 0 && CallsEvalField::decode(Flags()); 141 } 142 143 144 StrictMode ScopeInfo::strict_mode() { 145 return length() > 0 ? StrictModeField::decode(Flags()) : SLOPPY; 146 } 147 148 149 int ScopeInfo::LocalCount() { 150 return StackLocalCount() + ContextLocalCount(); 151 } 152 153 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 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 183 bool ScopeInfo::HasFunctionName() { 184 if (length() > 0) { 185 return NONE != FunctionVariableField::decode(Flags()); 186 } else { 187 return false; 188 } 189 } 190 191 192 bool ScopeInfo::HasHeapAllocatedLocals() { 193 if (length() > 0) { 194 return ContextLocalCount() > 0; 195 } else { 196 return false; 197 } 198 } 199 200 201 bool ScopeInfo::HasContext() { 202 return ContextLength() > 0; 203 } 204 205 206 String* ScopeInfo::FunctionName() { 207 ASSERT(HasFunctionName()); 208 return String::cast(get(FunctionNameEntryIndex())); 209 } 210 211 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 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 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 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 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 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 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 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 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 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 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 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 384 int ScopeInfo::ParameterEntriesIndex() { 385 ASSERT(length() > 0); 386 return kVariablePartIndex; 387 } 388 389 390 int ScopeInfo::StackLocalEntriesIndex() { 391 return ParameterEntriesIndex() + ParameterCount(); 392 } 393 394 395 int ScopeInfo::ContextLocalNameEntriesIndex() { 396 return StackLocalEntriesIndex() + StackLocalCount(); 397 } 398 399 400 int ScopeInfo::ContextLocalInfoEntriesIndex() { 401 return ContextLocalNameEntriesIndex() + ContextLocalCount(); 402 } 403 404 405 int ScopeInfo::FunctionNameEntryIndex() { 406 return ContextLocalInfoEntriesIndex() + ContextLocalCount(); 407 } 408 409 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 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 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 457 void ContextSlotCache::Clear() { 458 for (int index = 0; index < kLength; index++) keys_[index].data = NULL; 459 } 460 461 462 #ifdef DEBUG 463 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 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 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 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