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 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 151 ScopeInfo* ScopeInfo::Empty(Isolate* isolate) { 152 return reinterpret_cast<ScopeInfo*>(isolate->heap()->empty_fixed_array()); 153 } 154 155 156 ScopeType ScopeInfo::scope_type() { 157 ASSERT(length() > 0); 158 return ScopeTypeField::decode(Flags()); 159 } 160 161 162 bool ScopeInfo::CallsEval() { 163 return length() > 0 && CallsEvalField::decode(Flags()); 164 } 165 166 167 LanguageMode ScopeInfo::language_mode() { 168 return length() > 0 ? LanguageModeField::decode(Flags()) : CLASSIC_MODE; 169 } 170 171 172 int ScopeInfo::LocalCount() { 173 return StackLocalCount() + ContextLocalCount(); 174 } 175 176 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 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 206 bool ScopeInfo::HasFunctionName() { 207 if (length() > 0) { 208 return NONE != FunctionVariableField::decode(Flags()); 209 } else { 210 return false; 211 } 212 } 213 214 215 bool ScopeInfo::HasHeapAllocatedLocals() { 216 if (length() > 0) { 217 return ContextLocalCount() > 0; 218 } else { 219 return false; 220 } 221 } 222 223 224 bool ScopeInfo::HasContext() { 225 return ContextLength() > 0; 226 } 227 228 229 String* ScopeInfo::FunctionName() { 230 ASSERT(HasFunctionName()); 231 return String::cast(get(FunctionNameEntryIndex())); 232 } 233 234 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 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 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 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 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 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 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 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 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 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 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 388 int ScopeInfo::ParameterEntriesIndex() { 389 ASSERT(length() > 0); 390 return kVariablePartIndex; 391 } 392 393 394 int ScopeInfo::StackLocalEntriesIndex() { 395 return ParameterEntriesIndex() + ParameterCount(); 396 } 397 398 399 int ScopeInfo::ContextLocalNameEntriesIndex() { 400 return StackLocalEntriesIndex() + StackLocalCount(); 401 } 402 403 404 int ScopeInfo::ContextLocalInfoEntriesIndex() { 405 return ContextLocalNameEntriesIndex() + ContextLocalCount(); 406 } 407 408 409 int ScopeInfo::FunctionNameEntryIndex() { 410 return ContextLocalInfoEntriesIndex() + ContextLocalCount(); 411 } 412 413 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 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 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 460 void ContextSlotCache::Clear() { 461 for (int index = 0; index < kLength; index++) keys_[index].data = NULL; 462 } 463 464 465 #ifdef DEBUG 466 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 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 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 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