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