1 // Copyright 2012 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 "v8.h" 29 30 #include "scopes.h" 31 32 #include "accessors.h" 33 #include "bootstrapper.h" 34 #include "compiler.h" 35 #include "messages.h" 36 #include "scopeinfo.h" 37 38 #include "allocation-inl.h" 39 40 namespace v8 { 41 namespace internal { 42 43 // ---------------------------------------------------------------------------- 44 // Implementation of LocalsMap 45 // 46 // Note: We are storing the handle locations as key values in the hash map. 47 // When inserting a new variable via Declare(), we rely on the fact that 48 // the handle location remains alive for the duration of that variable 49 // use. Because a Variable holding a handle with the same location exists 50 // this is ensured. 51 52 static bool Match(void* key1, void* key2) { 53 String* name1 = *reinterpret_cast<String**>(key1); 54 String* name2 = *reinterpret_cast<String**>(key2); 55 ASSERT(name1->IsInternalizedString()); 56 ASSERT(name2->IsInternalizedString()); 57 return name1 == name2; 58 } 59 60 61 VariableMap::VariableMap(Zone* zone) 62 : ZoneHashMap(Match, 8, ZoneAllocationPolicy(zone)), 63 zone_(zone) {} 64 VariableMap::~VariableMap() {} 65 66 67 Variable* VariableMap::Declare( 68 Scope* scope, 69 Handle<String> name, 70 VariableMode mode, 71 bool is_valid_lhs, 72 Variable::Kind kind, 73 InitializationFlag initialization_flag, 74 Interface* interface) { 75 Entry* p = ZoneHashMap::Lookup(name.location(), name->Hash(), true, 76 ZoneAllocationPolicy(zone())); 77 if (p->value == NULL) { 78 // The variable has not been declared yet -> insert it. 79 ASSERT(p->key == name.location()); 80 p->value = new(zone()) Variable(scope, 81 name, 82 mode, 83 is_valid_lhs, 84 kind, 85 initialization_flag, 86 interface); 87 } 88 return reinterpret_cast<Variable*>(p->value); 89 } 90 91 92 Variable* VariableMap::Lookup(Handle<String> name) { 93 Entry* p = ZoneHashMap::Lookup(name.location(), name->Hash(), false, 94 ZoneAllocationPolicy(NULL)); 95 if (p != NULL) { 96 ASSERT(*reinterpret_cast<String**>(p->key) == *name); 97 ASSERT(p->value != NULL); 98 return reinterpret_cast<Variable*>(p->value); 99 } 100 return NULL; 101 } 102 103 104 // ---------------------------------------------------------------------------- 105 // Implementation of Scope 106 107 Scope::Scope(Scope* outer_scope, ScopeType scope_type, Zone* zone) 108 : isolate_(zone->isolate()), 109 inner_scopes_(4, zone), 110 variables_(zone), 111 internals_(4, zone), 112 temps_(4, zone), 113 params_(4, zone), 114 unresolved_(16, zone), 115 decls_(4, zone), 116 interface_(FLAG_harmony_modules && 117 (scope_type == MODULE_SCOPE || scope_type == GLOBAL_SCOPE) 118 ? Interface::NewModule(zone) : NULL), 119 already_resolved_(false), 120 zone_(zone) { 121 SetDefaults(scope_type, outer_scope, Handle<ScopeInfo>::null()); 122 // The outermost scope must be a global scope. 123 ASSERT(scope_type == GLOBAL_SCOPE || outer_scope != NULL); 124 ASSERT(!HasIllegalRedeclaration()); 125 } 126 127 128 Scope::Scope(Scope* inner_scope, 129 ScopeType scope_type, 130 Handle<ScopeInfo> scope_info, 131 Zone* zone) 132 : isolate_(Isolate::Current()), 133 inner_scopes_(4, zone), 134 variables_(zone), 135 internals_(4, zone), 136 temps_(4, zone), 137 params_(4, zone), 138 unresolved_(16, zone), 139 decls_(4, zone), 140 interface_(NULL), 141 already_resolved_(true), 142 zone_(zone) { 143 SetDefaults(scope_type, NULL, scope_info); 144 if (!scope_info.is_null()) { 145 num_heap_slots_ = scope_info_->ContextLength(); 146 } 147 // Ensure at least MIN_CONTEXT_SLOTS to indicate a materialized context. 148 num_heap_slots_ = Max(num_heap_slots_, 149 static_cast<int>(Context::MIN_CONTEXT_SLOTS)); 150 AddInnerScope(inner_scope); 151 } 152 153 154 Scope::Scope(Scope* inner_scope, Handle<String> catch_variable_name, Zone* zone) 155 : isolate_(Isolate::Current()), 156 inner_scopes_(1, zone), 157 variables_(zone), 158 internals_(0, zone), 159 temps_(0, zone), 160 params_(0, zone), 161 unresolved_(0, zone), 162 decls_(0, zone), 163 interface_(NULL), 164 already_resolved_(true), 165 zone_(zone) { 166 SetDefaults(CATCH_SCOPE, NULL, Handle<ScopeInfo>::null()); 167 AddInnerScope(inner_scope); 168 ++num_var_or_const_; 169 num_heap_slots_ = Context::MIN_CONTEXT_SLOTS; 170 Variable* variable = variables_.Declare(this, 171 catch_variable_name, 172 VAR, 173 true, // Valid left-hand side. 174 Variable::NORMAL, 175 kCreatedInitialized); 176 AllocateHeapSlot(variable); 177 } 178 179 180 void Scope::SetDefaults(ScopeType scope_type, 181 Scope* outer_scope, 182 Handle<ScopeInfo> scope_info) { 183 outer_scope_ = outer_scope; 184 scope_type_ = scope_type; 185 scope_name_ = isolate_->factory()->empty_string(); 186 dynamics_ = NULL; 187 receiver_ = NULL; 188 function_ = NULL; 189 arguments_ = NULL; 190 illegal_redecl_ = NULL; 191 scope_inside_with_ = false; 192 scope_contains_with_ = false; 193 scope_calls_eval_ = false; 194 // Inherit the strict mode from the parent scope. 195 language_mode_ = (outer_scope != NULL) 196 ? outer_scope->language_mode_ : CLASSIC_MODE; 197 outer_scope_calls_non_strict_eval_ = false; 198 inner_scope_calls_eval_ = false; 199 force_eager_compilation_ = false; 200 force_context_allocation_ = (outer_scope != NULL && !is_function_scope()) 201 ? outer_scope->has_forced_context_allocation() : false; 202 num_var_or_const_ = 0; 203 num_stack_slots_ = 0; 204 num_heap_slots_ = 0; 205 num_modules_ = 0; 206 module_var_ = NULL, 207 scope_info_ = scope_info; 208 start_position_ = RelocInfo::kNoPosition; 209 end_position_ = RelocInfo::kNoPosition; 210 if (!scope_info.is_null()) { 211 scope_calls_eval_ = scope_info->CallsEval(); 212 language_mode_ = scope_info->language_mode(); 213 } 214 } 215 216 217 Scope* Scope::DeserializeScopeChain(Context* context, Scope* global_scope, 218 Zone* zone) { 219 // Reconstruct the outer scope chain from a closure's context chain. 220 Scope* current_scope = NULL; 221 Scope* innermost_scope = NULL; 222 bool contains_with = false; 223 while (!context->IsNativeContext()) { 224 if (context->IsWithContext()) { 225 Scope* with_scope = new(zone) Scope(current_scope, 226 WITH_SCOPE, 227 Handle<ScopeInfo>::null(), 228 zone); 229 current_scope = with_scope; 230 // All the inner scopes are inside a with. 231 contains_with = true; 232 for (Scope* s = innermost_scope; s != NULL; s = s->outer_scope()) { 233 s->scope_inside_with_ = true; 234 } 235 } else if (context->IsGlobalContext()) { 236 ScopeInfo* scope_info = ScopeInfo::cast(context->extension()); 237 current_scope = new(zone) Scope(current_scope, 238 GLOBAL_SCOPE, 239 Handle<ScopeInfo>(scope_info), 240 zone); 241 } else if (context->IsModuleContext()) { 242 ScopeInfo* scope_info = ScopeInfo::cast(context->module()->scope_info()); 243 current_scope = new(zone) Scope(current_scope, 244 MODULE_SCOPE, 245 Handle<ScopeInfo>(scope_info), 246 zone); 247 } else if (context->IsFunctionContext()) { 248 ScopeInfo* scope_info = context->closure()->shared()->scope_info(); 249 current_scope = new(zone) Scope(current_scope, 250 FUNCTION_SCOPE, 251 Handle<ScopeInfo>(scope_info), 252 zone); 253 } else if (context->IsBlockContext()) { 254 ScopeInfo* scope_info = ScopeInfo::cast(context->extension()); 255 current_scope = new(zone) Scope(current_scope, 256 BLOCK_SCOPE, 257 Handle<ScopeInfo>(scope_info), 258 zone); 259 } else { 260 ASSERT(context->IsCatchContext()); 261 String* name = String::cast(context->extension()); 262 current_scope = new(zone) Scope( 263 current_scope, Handle<String>(name), zone); 264 } 265 if (contains_with) current_scope->RecordWithStatement(); 266 if (innermost_scope == NULL) innermost_scope = current_scope; 267 268 // Forget about a with when we move to a context for a different function. 269 if (context->previous()->closure() != context->closure()) { 270 contains_with = false; 271 } 272 context = context->previous(); 273 } 274 275 global_scope->AddInnerScope(current_scope); 276 global_scope->PropagateScopeInfo(false); 277 return (innermost_scope == NULL) ? global_scope : innermost_scope; 278 } 279 280 281 bool Scope::Analyze(CompilationInfo* info) { 282 ASSERT(info->function() != NULL); 283 Scope* scope = info->function()->scope(); 284 Scope* top = scope; 285 286 // Traverse the scope tree up to the first unresolved scope or the global 287 // scope and start scope resolution and variable allocation from that scope. 288 while (!top->is_global_scope() && 289 !top->outer_scope()->already_resolved()) { 290 top = top->outer_scope(); 291 } 292 293 // Allocate the variables. 294 { 295 AstNodeFactory<AstNullVisitor> ast_node_factory(info->isolate(), 296 info->zone()); 297 if (!top->AllocateVariables(info, &ast_node_factory)) return false; 298 } 299 300 #ifdef DEBUG 301 if (info->isolate()->bootstrapper()->IsActive() 302 ? FLAG_print_builtin_scopes 303 : FLAG_print_scopes) { 304 scope->Print(); 305 } 306 307 if (FLAG_harmony_modules && FLAG_print_interfaces && top->is_global_scope()) { 308 PrintF("global : "); 309 top->interface()->Print(); 310 } 311 #endif 312 313 info->SetScope(scope); 314 return true; 315 } 316 317 318 void Scope::Initialize() { 319 ASSERT(!already_resolved()); 320 321 // Add this scope as a new inner scope of the outer scope. 322 if (outer_scope_ != NULL) { 323 outer_scope_->inner_scopes_.Add(this, zone()); 324 scope_inside_with_ = outer_scope_->scope_inside_with_ || is_with_scope(); 325 } else { 326 scope_inside_with_ = is_with_scope(); 327 } 328 329 // Declare convenience variables. 330 // Declare and allocate receiver (even for the global scope, and even 331 // if naccesses_ == 0). 332 // NOTE: When loading parameters in the global scope, we must take 333 // care not to access them as properties of the global object, but 334 // instead load them directly from the stack. Currently, the only 335 // such parameter is 'this' which is passed on the stack when 336 // invoking scripts 337 if (is_declaration_scope()) { 338 Variable* var = 339 variables_.Declare(this, 340 isolate_->factory()->this_string(), 341 VAR, 342 false, 343 Variable::THIS, 344 kCreatedInitialized); 345 var->AllocateTo(Variable::PARAMETER, -1); 346 receiver_ = var; 347 } else { 348 ASSERT(outer_scope() != NULL); 349 receiver_ = outer_scope()->receiver(); 350 } 351 352 if (is_function_scope()) { 353 // Declare 'arguments' variable which exists in all functions. 354 // Note that it might never be accessed, in which case it won't be 355 // allocated during variable allocation. 356 variables_.Declare(this, 357 isolate_->factory()->arguments_string(), 358 VAR, 359 true, 360 Variable::ARGUMENTS, 361 kCreatedInitialized); 362 } 363 } 364 365 366 Scope* Scope::FinalizeBlockScope() { 367 ASSERT(is_block_scope()); 368 ASSERT(internals_.is_empty()); 369 ASSERT(temps_.is_empty()); 370 ASSERT(params_.is_empty()); 371 372 if (num_var_or_const() > 0) return this; 373 374 // Remove this scope from outer scope. 375 for (int i = 0; i < outer_scope_->inner_scopes_.length(); i++) { 376 if (outer_scope_->inner_scopes_[i] == this) { 377 outer_scope_->inner_scopes_.Remove(i); 378 break; 379 } 380 } 381 382 // Reparent inner scopes. 383 for (int i = 0; i < inner_scopes_.length(); i++) { 384 outer_scope()->AddInnerScope(inner_scopes_[i]); 385 } 386 387 // Move unresolved variables 388 for (int i = 0; i < unresolved_.length(); i++) { 389 outer_scope()->unresolved_.Add(unresolved_[i], zone()); 390 } 391 392 return NULL; 393 } 394 395 396 Variable* Scope::LocalLookup(Handle<String> name) { 397 Variable* result = variables_.Lookup(name); 398 if (result != NULL || scope_info_.is_null()) { 399 return result; 400 } 401 // If we have a serialized scope info, we might find the variable there. 402 // There should be no local slot with the given name. 403 ASSERT(scope_info_->StackSlotIndex(*name) < 0); 404 405 // Check context slot lookup. 406 VariableMode mode; 407 Variable::Location location = Variable::CONTEXT; 408 InitializationFlag init_flag; 409 int index = scope_info_->ContextSlotIndex(*name, &mode, &init_flag); 410 if (index < 0) { 411 // Check parameters. 412 index = scope_info_->ParameterIndex(*name); 413 if (index < 0) return NULL; 414 415 mode = DYNAMIC; 416 location = Variable::LOOKUP; 417 init_flag = kCreatedInitialized; 418 } 419 420 Variable* var = variables_.Declare(this, name, mode, true, Variable::NORMAL, 421 init_flag); 422 var->AllocateTo(location, index); 423 return var; 424 } 425 426 427 Variable* Scope::LookupFunctionVar(Handle<String> name, 428 AstNodeFactory<AstNullVisitor>* factory) { 429 if (function_ != NULL && function_->proxy()->name().is_identical_to(name)) { 430 return function_->proxy()->var(); 431 } else if (!scope_info_.is_null()) { 432 // If we are backed by a scope info, try to lookup the variable there. 433 VariableMode mode; 434 int index = scope_info_->FunctionContextSlotIndex(*name, &mode); 435 if (index < 0) return NULL; 436 Variable* var = new(zone()) Variable( 437 this, name, mode, true /* is valid LHS */, 438 Variable::NORMAL, kCreatedInitialized); 439 VariableProxy* proxy = factory->NewVariableProxy(var); 440 VariableDeclaration* declaration = 441 factory->NewVariableDeclaration(proxy, mode, this); 442 DeclareFunctionVar(declaration); 443 var->AllocateTo(Variable::CONTEXT, index); 444 return var; 445 } else { 446 return NULL; 447 } 448 } 449 450 451 Variable* Scope::Lookup(Handle<String> name) { 452 for (Scope* scope = this; 453 scope != NULL; 454 scope = scope->outer_scope()) { 455 Variable* var = scope->LocalLookup(name); 456 if (var != NULL) return var; 457 } 458 return NULL; 459 } 460 461 462 void Scope::DeclareParameter(Handle<String> name, VariableMode mode) { 463 ASSERT(!already_resolved()); 464 ASSERT(is_function_scope()); 465 Variable* var = variables_.Declare(this, name, mode, true, Variable::NORMAL, 466 kCreatedInitialized); 467 params_.Add(var, zone()); 468 } 469 470 471 Variable* Scope::DeclareLocal(Handle<String> name, 472 VariableMode mode, 473 InitializationFlag init_flag, 474 Interface* interface) { 475 ASSERT(!already_resolved()); 476 // This function handles VAR and CONST modes. DYNAMIC variables are 477 // introduces during variable allocation, INTERNAL variables are allocated 478 // explicitly, and TEMPORARY variables are allocated via NewTemporary(). 479 ASSERT(IsDeclaredVariableMode(mode)); 480 ++num_var_or_const_; 481 return variables_.Declare( 482 this, name, mode, true, Variable::NORMAL, init_flag, interface); 483 } 484 485 486 Variable* Scope::DeclareDynamicGlobal(Handle<String> name) { 487 ASSERT(is_global_scope()); 488 return variables_.Declare(this, 489 name, 490 DYNAMIC_GLOBAL, 491 true, 492 Variable::NORMAL, 493 kCreatedInitialized); 494 } 495 496 497 void Scope::RemoveUnresolved(VariableProxy* var) { 498 // Most likely (always?) any variable we want to remove 499 // was just added before, so we search backwards. 500 for (int i = unresolved_.length(); i-- > 0;) { 501 if (unresolved_[i] == var) { 502 unresolved_.Remove(i); 503 return; 504 } 505 } 506 } 507 508 509 Variable* Scope::NewInternal(Handle<String> name) { 510 ASSERT(!already_resolved()); 511 Variable* var = new(zone()) Variable(this, 512 name, 513 INTERNAL, 514 false, 515 Variable::NORMAL, 516 kCreatedInitialized); 517 internals_.Add(var, zone()); 518 return var; 519 } 520 521 522 Variable* Scope::NewTemporary(Handle<String> name) { 523 ASSERT(!already_resolved()); 524 Variable* var = new(zone()) Variable(this, 525 name, 526 TEMPORARY, 527 true, 528 Variable::NORMAL, 529 kCreatedInitialized); 530 temps_.Add(var, zone()); 531 return var; 532 } 533 534 535 void Scope::AddDeclaration(Declaration* declaration) { 536 decls_.Add(declaration, zone()); 537 } 538 539 540 void Scope::SetIllegalRedeclaration(Expression* expression) { 541 // Record only the first illegal redeclaration. 542 if (!HasIllegalRedeclaration()) { 543 illegal_redecl_ = expression; 544 } 545 ASSERT(HasIllegalRedeclaration()); 546 } 547 548 549 void Scope::VisitIllegalRedeclaration(AstVisitor* visitor) { 550 ASSERT(HasIllegalRedeclaration()); 551 illegal_redecl_->Accept(visitor); 552 } 553 554 555 Declaration* Scope::CheckConflictingVarDeclarations() { 556 int length = decls_.length(); 557 for (int i = 0; i < length; i++) { 558 Declaration* decl = decls_[i]; 559 if (decl->mode() != VAR) continue; 560 Handle<String> name = decl->proxy()->name(); 561 562 // Iterate through all scopes until and including the declaration scope. 563 Scope* previous = NULL; 564 Scope* current = decl->scope(); 565 do { 566 // There is a conflict if there exists a non-VAR binding. 567 Variable* other_var = current->variables_.Lookup(name); 568 if (other_var != NULL && other_var->mode() != VAR) { 569 return decl; 570 } 571 previous = current; 572 current = current->outer_scope_; 573 } while (!previous->is_declaration_scope()); 574 } 575 return NULL; 576 } 577 578 579 class VarAndOrder { 580 public: 581 VarAndOrder(Variable* var, int order) : var_(var), order_(order) { } 582 Variable* var() const { return var_; } 583 int order() const { return order_; } 584 static int Compare(const VarAndOrder* a, const VarAndOrder* b) { 585 return a->order_ - b->order_; 586 } 587 588 private: 589 Variable* var_; 590 int order_; 591 }; 592 593 594 void Scope::CollectStackAndContextLocals(ZoneList<Variable*>* stack_locals, 595 ZoneList<Variable*>* context_locals) { 596 ASSERT(stack_locals != NULL); 597 ASSERT(context_locals != NULL); 598 599 // Collect internals which are always allocated on the heap. 600 for (int i = 0; i < internals_.length(); i++) { 601 Variable* var = internals_[i]; 602 if (var->is_used()) { 603 ASSERT(var->IsContextSlot()); 604 context_locals->Add(var, zone()); 605 } 606 } 607 608 // Collect temporaries which are always allocated on the stack, unless the 609 // context as a whole has forced context allocation. 610 for (int i = 0; i < temps_.length(); i++) { 611 Variable* var = temps_[i]; 612 if (var->is_used()) { 613 if (var->IsContextSlot()) { 614 ASSERT(has_forced_context_allocation()); 615 context_locals->Add(var, zone()); 616 } else { 617 ASSERT(var->IsStackLocal()); 618 stack_locals->Add(var, zone()); 619 } 620 } 621 } 622 623 // Collect declared local variables. 624 ZoneList<VarAndOrder> vars(variables_.occupancy(), zone()); 625 for (VariableMap::Entry* p = variables_.Start(); 626 p != NULL; 627 p = variables_.Next(p)) { 628 Variable* var = reinterpret_cast<Variable*>(p->value); 629 if (var->is_used()) { 630 vars.Add(VarAndOrder(var, p->order), zone()); 631 } 632 } 633 vars.Sort(VarAndOrder::Compare); 634 int var_count = vars.length(); 635 for (int i = 0; i < var_count; i++) { 636 Variable* var = vars[i].var(); 637 if (var->IsStackLocal()) { 638 stack_locals->Add(var, zone()); 639 } else if (var->IsContextSlot()) { 640 context_locals->Add(var, zone()); 641 } 642 } 643 } 644 645 646 bool Scope::AllocateVariables(CompilationInfo* info, 647 AstNodeFactory<AstNullVisitor>* factory) { 648 // 1) Propagate scope information. 649 bool outer_scope_calls_non_strict_eval = false; 650 if (outer_scope_ != NULL) { 651 outer_scope_calls_non_strict_eval = 652 outer_scope_->outer_scope_calls_non_strict_eval() | 653 outer_scope_->calls_non_strict_eval(); 654 } 655 PropagateScopeInfo(outer_scope_calls_non_strict_eval); 656 657 // 2) Allocate module instances. 658 if (FLAG_harmony_modules && (is_global_scope() || is_module_scope())) { 659 ASSERT(num_modules_ == 0); 660 AllocateModulesRecursively(this); 661 } 662 663 // 3) Resolve variables. 664 if (!ResolveVariablesRecursively(info, factory)) return false; 665 666 // 4) Allocate variables. 667 AllocateVariablesRecursively(); 668 669 return true; 670 } 671 672 673 bool Scope::HasTrivialContext() const { 674 // A function scope has a trivial context if it always is the global 675 // context. We iteratively scan out the context chain to see if 676 // there is anything that makes this scope non-trivial; otherwise we 677 // return true. 678 for (const Scope* scope = this; scope != NULL; scope = scope->outer_scope_) { 679 if (scope->is_eval_scope()) return false; 680 if (scope->scope_inside_with_) return false; 681 if (scope->num_heap_slots_ > 0) return false; 682 } 683 return true; 684 } 685 686 687 bool Scope::HasTrivialOuterContext() const { 688 Scope* outer = outer_scope_; 689 if (outer == NULL) return true; 690 // Note that the outer context may be trivial in general, but the current 691 // scope may be inside a 'with' statement in which case the outer context 692 // for this scope is not trivial. 693 return !scope_inside_with_ && outer->HasTrivialContext(); 694 } 695 696 697 bool Scope::HasLazyCompilableOuterContext() const { 698 Scope* outer = outer_scope_; 699 if (outer == NULL) return true; 700 // We have to prevent lazy compilation if this scope is inside a with scope 701 // and all declaration scopes between them have empty contexts. Such 702 // declaration scopes may become invisible during scope info deserialization. 703 outer = outer->DeclarationScope(); 704 bool found_non_trivial_declarations = false; 705 for (const Scope* scope = outer; scope != NULL; scope = scope->outer_scope_) { 706 if (scope->is_with_scope() && !found_non_trivial_declarations) return false; 707 if (scope->is_declaration_scope() && scope->num_heap_slots() > 0) { 708 found_non_trivial_declarations = true; 709 } 710 } 711 return true; 712 } 713 714 715 bool Scope::AllowsLazyCompilation() const { 716 return !force_eager_compilation_ && HasLazyCompilableOuterContext(); 717 } 718 719 720 bool Scope::AllowsLazyCompilationWithoutContext() const { 721 return !force_eager_compilation_ && HasTrivialOuterContext(); 722 } 723 724 725 int Scope::ContextChainLength(Scope* scope) { 726 int n = 0; 727 for (Scope* s = this; s != scope; s = s->outer_scope_) { 728 ASSERT(s != NULL); // scope must be in the scope chain 729 if (s->is_with_scope() || s->num_heap_slots() > 0) n++; 730 // Catch and module scopes always have heap slots. 731 ASSERT(!s->is_catch_scope() || s->num_heap_slots() > 0); 732 ASSERT(!s->is_module_scope() || s->num_heap_slots() > 0); 733 } 734 return n; 735 } 736 737 738 Scope* Scope::GlobalScope() { 739 Scope* scope = this; 740 while (!scope->is_global_scope()) { 741 scope = scope->outer_scope(); 742 } 743 return scope; 744 } 745 746 747 Scope* Scope::DeclarationScope() { 748 Scope* scope = this; 749 while (!scope->is_declaration_scope()) { 750 scope = scope->outer_scope(); 751 } 752 return scope; 753 } 754 755 756 Handle<ScopeInfo> Scope::GetScopeInfo() { 757 if (scope_info_.is_null()) { 758 scope_info_ = ScopeInfo::Create(this, zone()); 759 } 760 return scope_info_; 761 } 762 763 764 void Scope::GetNestedScopeChain( 765 List<Handle<ScopeInfo> >* chain, 766 int position) { 767 if (!is_eval_scope()) chain->Add(Handle<ScopeInfo>(GetScopeInfo())); 768 769 for (int i = 0; i < inner_scopes_.length(); i++) { 770 Scope* scope = inner_scopes_[i]; 771 int beg_pos = scope->start_position(); 772 int end_pos = scope->end_position(); 773 ASSERT(beg_pos >= 0 && end_pos >= 0); 774 if (beg_pos <= position && position < end_pos) { 775 scope->GetNestedScopeChain(chain, position); 776 return; 777 } 778 } 779 } 780 781 782 #ifdef DEBUG 783 static const char* Header(ScopeType scope_type) { 784 switch (scope_type) { 785 case EVAL_SCOPE: return "eval"; 786 case FUNCTION_SCOPE: return "function"; 787 case MODULE_SCOPE: return "module"; 788 case GLOBAL_SCOPE: return "global"; 789 case CATCH_SCOPE: return "catch"; 790 case BLOCK_SCOPE: return "block"; 791 case WITH_SCOPE: return "with"; 792 } 793 UNREACHABLE(); 794 return NULL; 795 } 796 797 798 static void Indent(int n, const char* str) { 799 PrintF("%*s%s", n, "", str); 800 } 801 802 803 static void PrintName(Handle<String> name) { 804 SmartArrayPointer<char> s = name->ToCString(DISALLOW_NULLS); 805 PrintF("%s", *s); 806 } 807 808 809 static void PrintLocation(Variable* var) { 810 switch (var->location()) { 811 case Variable::UNALLOCATED: 812 break; 813 case Variable::PARAMETER: 814 PrintF("parameter[%d]", var->index()); 815 break; 816 case Variable::LOCAL: 817 PrintF("local[%d]", var->index()); 818 break; 819 case Variable::CONTEXT: 820 PrintF("context[%d]", var->index()); 821 break; 822 case Variable::LOOKUP: 823 PrintF("lookup"); 824 break; 825 } 826 } 827 828 829 static void PrintVar(int indent, Variable* var) { 830 if (var->is_used() || !var->IsUnallocated()) { 831 Indent(indent, Variable::Mode2String(var->mode())); 832 PrintF(" "); 833 PrintName(var->name()); 834 PrintF("; // "); 835 PrintLocation(var); 836 if (var->has_forced_context_allocation()) { 837 if (!var->IsUnallocated()) PrintF(", "); 838 PrintF("forced context allocation"); 839 } 840 PrintF("\n"); 841 } 842 } 843 844 845 static void PrintMap(int indent, VariableMap* map) { 846 for (VariableMap::Entry* p = map->Start(); p != NULL; p = map->Next(p)) { 847 Variable* var = reinterpret_cast<Variable*>(p->value); 848 PrintVar(indent, var); 849 } 850 } 851 852 853 void Scope::Print(int n) { 854 int n0 = (n > 0 ? n : 0); 855 int n1 = n0 + 2; // indentation 856 857 // Print header. 858 Indent(n0, Header(scope_type_)); 859 if (scope_name_->length() > 0) { 860 PrintF(" "); 861 PrintName(scope_name_); 862 } 863 864 // Print parameters, if any. 865 if (is_function_scope()) { 866 PrintF(" ("); 867 for (int i = 0; i < params_.length(); i++) { 868 if (i > 0) PrintF(", "); 869 PrintName(params_[i]->name()); 870 } 871 PrintF(")"); 872 } 873 874 PrintF(" { // (%d, %d)\n", start_position(), end_position()); 875 876 // Function name, if any (named function literals, only). 877 if (function_ != NULL) { 878 Indent(n1, "// (local) function name: "); 879 PrintName(function_->proxy()->name()); 880 PrintF("\n"); 881 } 882 883 // Scope info. 884 if (HasTrivialOuterContext()) { 885 Indent(n1, "// scope has trivial outer context\n"); 886 } 887 switch (language_mode()) { 888 case CLASSIC_MODE: 889 break; 890 case STRICT_MODE: 891 Indent(n1, "// strict mode scope\n"); 892 break; 893 case EXTENDED_MODE: 894 Indent(n1, "// extended mode scope\n"); 895 break; 896 } 897 if (scope_inside_with_) Indent(n1, "// scope inside 'with'\n"); 898 if (scope_contains_with_) Indent(n1, "// scope contains 'with'\n"); 899 if (scope_calls_eval_) Indent(n1, "// scope calls 'eval'\n"); 900 if (outer_scope_calls_non_strict_eval_) { 901 Indent(n1, "// outer scope calls 'eval' in non-strict context\n"); 902 } 903 if (inner_scope_calls_eval_) Indent(n1, "// inner scope calls 'eval'\n"); 904 if (num_stack_slots_ > 0) { Indent(n1, "// "); 905 PrintF("%d stack slots\n", num_stack_slots_); } 906 if (num_heap_slots_ > 0) { Indent(n1, "// "); 907 PrintF("%d heap slots\n", num_heap_slots_); } 908 909 // Print locals. 910 Indent(n1, "// function var\n"); 911 if (function_ != NULL) { 912 PrintVar(n1, function_->proxy()->var()); 913 } 914 915 Indent(n1, "// temporary vars\n"); 916 for (int i = 0; i < temps_.length(); i++) { 917 PrintVar(n1, temps_[i]); 918 } 919 920 Indent(n1, "// internal vars\n"); 921 for (int i = 0; i < internals_.length(); i++) { 922 PrintVar(n1, internals_[i]); 923 } 924 925 Indent(n1, "// local vars\n"); 926 PrintMap(n1, &variables_); 927 928 Indent(n1, "// dynamic vars\n"); 929 if (dynamics_ != NULL) { 930 PrintMap(n1, dynamics_->GetMap(DYNAMIC)); 931 PrintMap(n1, dynamics_->GetMap(DYNAMIC_LOCAL)); 932 PrintMap(n1, dynamics_->GetMap(DYNAMIC_GLOBAL)); 933 } 934 935 // Print inner scopes (disable by providing negative n). 936 if (n >= 0) { 937 for (int i = 0; i < inner_scopes_.length(); i++) { 938 PrintF("\n"); 939 inner_scopes_[i]->Print(n1); 940 } 941 } 942 943 Indent(n0, "}\n"); 944 } 945 #endif // DEBUG 946 947 948 Variable* Scope::NonLocal(Handle<String> name, VariableMode mode) { 949 if (dynamics_ == NULL) dynamics_ = new(zone()) DynamicScopePart(zone()); 950 VariableMap* map = dynamics_->GetMap(mode); 951 Variable* var = map->Lookup(name); 952 if (var == NULL) { 953 // Declare a new non-local. 954 InitializationFlag init_flag = (mode == VAR) 955 ? kCreatedInitialized : kNeedsInitialization; 956 var = map->Declare(NULL, 957 name, 958 mode, 959 true, 960 Variable::NORMAL, 961 init_flag); 962 // Allocate it by giving it a dynamic lookup. 963 var->AllocateTo(Variable::LOOKUP, -1); 964 } 965 return var; 966 } 967 968 969 Variable* Scope::LookupRecursive(Handle<String> name, 970 BindingKind* binding_kind, 971 AstNodeFactory<AstNullVisitor>* factory) { 972 ASSERT(binding_kind != NULL); 973 if (already_resolved() && is_with_scope()) { 974 // Short-cut: if the scope is deserialized from a scope info, variable 975 // allocation is already fixed. We can simply return with dynamic lookup. 976 *binding_kind = DYNAMIC_LOOKUP; 977 return NULL; 978 } 979 980 // Try to find the variable in this scope. 981 Variable* var = LocalLookup(name); 982 983 // We found a variable and we are done. (Even if there is an 'eval' in 984 // this scope which introduces the same variable again, the resulting 985 // variable remains the same.) 986 if (var != NULL) { 987 *binding_kind = BOUND; 988 return var; 989 } 990 991 // We did not find a variable locally. Check against the function variable, 992 // if any. We can do this for all scopes, since the function variable is 993 // only present - if at all - for function scopes. 994 *binding_kind = UNBOUND; 995 var = LookupFunctionVar(name, factory); 996 if (var != NULL) { 997 *binding_kind = BOUND; 998 } else if (outer_scope_ != NULL) { 999 var = outer_scope_->LookupRecursive(name, binding_kind, factory); 1000 if (*binding_kind == BOUND && (is_function_scope() || is_with_scope())) { 1001 var->ForceContextAllocation(); 1002 } 1003 } else { 1004 ASSERT(is_global_scope()); 1005 } 1006 1007 if (is_with_scope()) { 1008 ASSERT(!already_resolved()); 1009 // The current scope is a with scope, so the variable binding can not be 1010 // statically resolved. However, note that it was necessary to do a lookup 1011 // in the outer scope anyway, because if a binding exists in an outer scope, 1012 // the associated variable has to be marked as potentially being accessed 1013 // from inside of an inner with scope (the property may not be in the 'with' 1014 // object). 1015 *binding_kind = DYNAMIC_LOOKUP; 1016 return NULL; 1017 } else if (calls_non_strict_eval()) { 1018 // A variable binding may have been found in an outer scope, but the current 1019 // scope makes a non-strict 'eval' call, so the found variable may not be 1020 // the correct one (the 'eval' may introduce a binding with the same name). 1021 // In that case, change the lookup result to reflect this situation. 1022 if (*binding_kind == BOUND) { 1023 *binding_kind = BOUND_EVAL_SHADOWED; 1024 } else if (*binding_kind == UNBOUND) { 1025 *binding_kind = UNBOUND_EVAL_SHADOWED; 1026 } 1027 } 1028 return var; 1029 } 1030 1031 1032 bool Scope::ResolveVariable(CompilationInfo* info, 1033 VariableProxy* proxy, 1034 AstNodeFactory<AstNullVisitor>* factory) { 1035 ASSERT(info->global_scope()->is_global_scope()); 1036 1037 // If the proxy is already resolved there's nothing to do 1038 // (functions and consts may be resolved by the parser). 1039 if (proxy->var() != NULL) return true; 1040 1041 // Otherwise, try to resolve the variable. 1042 BindingKind binding_kind; 1043 Variable* var = LookupRecursive(proxy->name(), &binding_kind, factory); 1044 switch (binding_kind) { 1045 case BOUND: 1046 // We found a variable binding. 1047 break; 1048 1049 case BOUND_EVAL_SHADOWED: 1050 // We either found a variable binding that might be shadowed by eval or 1051 // gave up on it (e.g. by encountering a local with the same in the outer 1052 // scope which was not promoted to a context, this can happen if we use 1053 // debugger to evaluate arbitrary expressions at a break point). 1054 if (var->IsGlobalObjectProperty()) { 1055 var = NonLocal(proxy->name(), DYNAMIC_GLOBAL); 1056 } else if (var->is_dynamic()) { 1057 var = NonLocal(proxy->name(), DYNAMIC); 1058 } else { 1059 Variable* invalidated = var; 1060 var = NonLocal(proxy->name(), DYNAMIC_LOCAL); 1061 var->set_local_if_not_shadowed(invalidated); 1062 } 1063 break; 1064 1065 case UNBOUND: 1066 // No binding has been found. Declare a variable on the global object. 1067 var = info->global_scope()->DeclareDynamicGlobal(proxy->name()); 1068 break; 1069 1070 case UNBOUND_EVAL_SHADOWED: 1071 // No binding has been found. But some scope makes a 1072 // non-strict 'eval' call. 1073 var = NonLocal(proxy->name(), DYNAMIC_GLOBAL); 1074 break; 1075 1076 case DYNAMIC_LOOKUP: 1077 // The variable could not be resolved statically. 1078 var = NonLocal(proxy->name(), DYNAMIC); 1079 break; 1080 } 1081 1082 ASSERT(var != NULL); 1083 1084 if (FLAG_harmony_scoping && is_extended_mode() && 1085 var->is_const_mode() && proxy->IsLValue()) { 1086 // Assignment to const. Throw a syntax error. 1087 MessageLocation location( 1088 info->script(), proxy->position(), proxy->position()); 1089 Isolate* isolate = Isolate::Current(); 1090 Factory* factory = isolate->factory(); 1091 Handle<JSArray> array = factory->NewJSArray(0); 1092 Handle<Object> result = 1093 factory->NewSyntaxError("harmony_const_assign", array); 1094 isolate->Throw(*result, &location); 1095 return false; 1096 } 1097 1098 if (FLAG_harmony_modules) { 1099 bool ok; 1100 #ifdef DEBUG 1101 if (FLAG_print_interface_details) 1102 PrintF("# Resolve %s:\n", var->name()->ToAsciiArray()); 1103 #endif 1104 proxy->interface()->Unify(var->interface(), zone(), &ok); 1105 if (!ok) { 1106 #ifdef DEBUG 1107 if (FLAG_print_interfaces) { 1108 PrintF("SCOPES TYPE ERROR\n"); 1109 PrintF("proxy: "); 1110 proxy->interface()->Print(); 1111 PrintF("var: "); 1112 var->interface()->Print(); 1113 } 1114 #endif 1115 1116 // Inconsistent use of module. Throw a syntax error. 1117 // TODO(rossberg): generate more helpful error message. 1118 MessageLocation location( 1119 info->script(), proxy->position(), proxy->position()); 1120 Isolate* isolate = Isolate::Current(); 1121 Factory* factory = isolate->factory(); 1122 Handle<JSArray> array = factory->NewJSArray(1); 1123 USE(JSObject::SetElement(array, 0, var->name(), NONE, kStrictMode)); 1124 Handle<Object> result = 1125 factory->NewSyntaxError("module_type_error", array); 1126 isolate->Throw(*result, &location); 1127 return false; 1128 } 1129 } 1130 1131 proxy->BindTo(var); 1132 1133 return true; 1134 } 1135 1136 1137 bool Scope::ResolveVariablesRecursively( 1138 CompilationInfo* info, 1139 AstNodeFactory<AstNullVisitor>* factory) { 1140 ASSERT(info->global_scope()->is_global_scope()); 1141 1142 // Resolve unresolved variables for this scope. 1143 for (int i = 0; i < unresolved_.length(); i++) { 1144 if (!ResolveVariable(info, unresolved_[i], factory)) return false; 1145 } 1146 1147 // Resolve unresolved variables for inner scopes. 1148 for (int i = 0; i < inner_scopes_.length(); i++) { 1149 if (!inner_scopes_[i]->ResolveVariablesRecursively(info, factory)) 1150 return false; 1151 } 1152 1153 return true; 1154 } 1155 1156 1157 bool Scope::PropagateScopeInfo(bool outer_scope_calls_non_strict_eval ) { 1158 if (outer_scope_calls_non_strict_eval) { 1159 outer_scope_calls_non_strict_eval_ = true; 1160 } 1161 1162 bool calls_non_strict_eval = 1163 this->calls_non_strict_eval() || outer_scope_calls_non_strict_eval_; 1164 for (int i = 0; i < inner_scopes_.length(); i++) { 1165 Scope* inner_scope = inner_scopes_[i]; 1166 if (inner_scope->PropagateScopeInfo(calls_non_strict_eval)) { 1167 inner_scope_calls_eval_ = true; 1168 } 1169 if (inner_scope->force_eager_compilation_) { 1170 force_eager_compilation_ = true; 1171 } 1172 } 1173 1174 return scope_calls_eval_ || inner_scope_calls_eval_; 1175 } 1176 1177 1178 bool Scope::MustAllocate(Variable* var) { 1179 // Give var a read/write use if there is a chance it might be accessed 1180 // via an eval() call. This is only possible if the variable has a 1181 // visible name. 1182 if ((var->is_this() || var->name()->length() > 0) && 1183 (var->has_forced_context_allocation() || 1184 scope_calls_eval_ || 1185 inner_scope_calls_eval_ || 1186 scope_contains_with_ || 1187 is_catch_scope() || 1188 is_block_scope() || 1189 is_module_scope() || 1190 is_global_scope())) { 1191 var->set_is_used(true); 1192 } 1193 // Global variables do not need to be allocated. 1194 return !var->IsGlobalObjectProperty() && var->is_used(); 1195 } 1196 1197 1198 bool Scope::MustAllocateInContext(Variable* var) { 1199 // If var is accessed from an inner scope, or if there is a possibility 1200 // that it might be accessed from the current or an inner scope (through 1201 // an eval() call or a runtime with lookup), it must be allocated in the 1202 // context. 1203 // 1204 // Exceptions: If the scope as a whole has forced context allocation, all 1205 // variables will have context allocation, even temporaries. Otherwise 1206 // temporary variables are always stack-allocated. Catch-bound variables are 1207 // always context-allocated. 1208 if (has_forced_context_allocation()) return true; 1209 if (var->mode() == TEMPORARY) return false; 1210 if (var->mode() == INTERNAL) return true; 1211 if (is_catch_scope() || is_block_scope() || is_module_scope()) return true; 1212 if (is_global_scope() && IsLexicalVariableMode(var->mode())) return true; 1213 return var->has_forced_context_allocation() || 1214 scope_calls_eval_ || 1215 inner_scope_calls_eval_ || 1216 scope_contains_with_; 1217 } 1218 1219 1220 bool Scope::HasArgumentsParameter() { 1221 for (int i = 0; i < params_.length(); i++) { 1222 if (params_[i]->name().is_identical_to( 1223 isolate_->factory()->arguments_string())) { 1224 return true; 1225 } 1226 } 1227 return false; 1228 } 1229 1230 1231 void Scope::AllocateStackSlot(Variable* var) { 1232 var->AllocateTo(Variable::LOCAL, num_stack_slots_++); 1233 } 1234 1235 1236 void Scope::AllocateHeapSlot(Variable* var) { 1237 var->AllocateTo(Variable::CONTEXT, num_heap_slots_++); 1238 } 1239 1240 1241 void Scope::AllocateParameterLocals() { 1242 ASSERT(is_function_scope()); 1243 Variable* arguments = LocalLookup(isolate_->factory()->arguments_string()); 1244 ASSERT(arguments != NULL); // functions have 'arguments' declared implicitly 1245 1246 bool uses_nonstrict_arguments = false; 1247 1248 if (MustAllocate(arguments) && !HasArgumentsParameter()) { 1249 // 'arguments' is used. Unless there is also a parameter called 1250 // 'arguments', we must be conservative and allocate all parameters to 1251 // the context assuming they will be captured by the arguments object. 1252 // If we have a parameter named 'arguments', a (new) value is always 1253 // assigned to it via the function invocation. Then 'arguments' denotes 1254 // that specific parameter value and cannot be used to access the 1255 // parameters, which is why we don't need to allocate an arguments 1256 // object in that case. 1257 1258 // We are using 'arguments'. Tell the code generator that is needs to 1259 // allocate the arguments object by setting 'arguments_'. 1260 arguments_ = arguments; 1261 1262 // In strict mode 'arguments' does not alias formal parameters. 1263 // Therefore in strict mode we allocate parameters as if 'arguments' 1264 // were not used. 1265 uses_nonstrict_arguments = is_classic_mode(); 1266 } 1267 1268 // The same parameter may occur multiple times in the parameters_ list. 1269 // If it does, and if it is not copied into the context object, it must 1270 // receive the highest parameter index for that parameter; thus iteration 1271 // order is relevant! 1272 for (int i = params_.length() - 1; i >= 0; --i) { 1273 Variable* var = params_[i]; 1274 ASSERT(var->scope() == this); 1275 if (uses_nonstrict_arguments) { 1276 // Force context allocation of the parameter. 1277 var->ForceContextAllocation(); 1278 } 1279 1280 if (MustAllocate(var)) { 1281 if (MustAllocateInContext(var)) { 1282 ASSERT(var->IsUnallocated() || var->IsContextSlot()); 1283 if (var->IsUnallocated()) { 1284 AllocateHeapSlot(var); 1285 } 1286 } else { 1287 ASSERT(var->IsUnallocated() || var->IsParameter()); 1288 if (var->IsUnallocated()) { 1289 var->AllocateTo(Variable::PARAMETER, i); 1290 } 1291 } 1292 } 1293 } 1294 } 1295 1296 1297 void Scope::AllocateNonParameterLocal(Variable* var) { 1298 ASSERT(var->scope() == this); 1299 ASSERT(!var->IsVariable(isolate_->factory()->result_string()) || 1300 !var->IsStackLocal()); 1301 if (var->IsUnallocated() && MustAllocate(var)) { 1302 if (MustAllocateInContext(var)) { 1303 AllocateHeapSlot(var); 1304 } else { 1305 AllocateStackSlot(var); 1306 } 1307 } 1308 } 1309 1310 1311 void Scope::AllocateNonParameterLocals() { 1312 // All variables that have no rewrite yet are non-parameter locals. 1313 for (int i = 0; i < temps_.length(); i++) { 1314 AllocateNonParameterLocal(temps_[i]); 1315 } 1316 1317 for (int i = 0; i < internals_.length(); i++) { 1318 AllocateNonParameterLocal(internals_[i]); 1319 } 1320 1321 ZoneList<VarAndOrder> vars(variables_.occupancy(), zone()); 1322 for (VariableMap::Entry* p = variables_.Start(); 1323 p != NULL; 1324 p = variables_.Next(p)) { 1325 Variable* var = reinterpret_cast<Variable*>(p->value); 1326 vars.Add(VarAndOrder(var, p->order), zone()); 1327 } 1328 vars.Sort(VarAndOrder::Compare); 1329 int var_count = vars.length(); 1330 for (int i = 0; i < var_count; i++) { 1331 AllocateNonParameterLocal(vars[i].var()); 1332 } 1333 1334 // For now, function_ must be allocated at the very end. If it gets 1335 // allocated in the context, it must be the last slot in the context, 1336 // because of the current ScopeInfo implementation (see 1337 // ScopeInfo::ScopeInfo(FunctionScope* scope) constructor). 1338 if (function_ != NULL) { 1339 AllocateNonParameterLocal(function_->proxy()->var()); 1340 } 1341 } 1342 1343 1344 void Scope::AllocateVariablesRecursively() { 1345 // Allocate variables for inner scopes. 1346 for (int i = 0; i < inner_scopes_.length(); i++) { 1347 inner_scopes_[i]->AllocateVariablesRecursively(); 1348 } 1349 1350 // If scope is already resolved, we still need to allocate 1351 // variables in inner scopes which might not had been resolved yet. 1352 if (already_resolved()) return; 1353 // The number of slots required for variables. 1354 num_stack_slots_ = 0; 1355 num_heap_slots_ = Context::MIN_CONTEXT_SLOTS; 1356 1357 // Allocate variables for this scope. 1358 // Parameters must be allocated first, if any. 1359 if (is_function_scope()) AllocateParameterLocals(); 1360 AllocateNonParameterLocals(); 1361 1362 // Force allocation of a context for this scope if necessary. For a 'with' 1363 // scope and for a function scope that makes an 'eval' call we need a context, 1364 // even if no local variables were statically allocated in the scope. 1365 // Likewise for modules. 1366 bool must_have_context = is_with_scope() || is_module_scope() || 1367 (is_function_scope() && calls_eval()); 1368 1369 // If we didn't allocate any locals in the local context, then we only 1370 // need the minimal number of slots if we must have a context. 1371 if (num_heap_slots_ == Context::MIN_CONTEXT_SLOTS && !must_have_context) { 1372 num_heap_slots_ = 0; 1373 } 1374 1375 // Allocation done. 1376 ASSERT(num_heap_slots_ == 0 || num_heap_slots_ >= Context::MIN_CONTEXT_SLOTS); 1377 } 1378 1379 1380 void Scope::AllocateModulesRecursively(Scope* host_scope) { 1381 if (already_resolved()) return; 1382 if (is_module_scope()) { 1383 ASSERT(interface_->IsFrozen()); 1384 Handle<String> name = isolate_->factory()->InternalizeOneByteString( 1385 STATIC_ASCII_VECTOR(".module")); 1386 ASSERT(module_var_ == NULL); 1387 module_var_ = host_scope->NewInternal(name); 1388 ++host_scope->num_modules_; 1389 } 1390 1391 for (int i = 0; i < inner_scopes_.length(); i++) { 1392 Scope* inner_scope = inner_scopes_.at(i); 1393 inner_scope->AllocateModulesRecursively(host_scope); 1394 } 1395 } 1396 1397 1398 int Scope::StackLocalCount() const { 1399 return num_stack_slots() - 1400 (function_ != NULL && function_->proxy()->var()->IsStackLocal() ? 1 : 0); 1401 } 1402 1403 1404 int Scope::ContextLocalCount() const { 1405 if (num_heap_slots() == 0) return 0; 1406 return num_heap_slots() - Context::MIN_CONTEXT_SLOTS - 1407 (function_ != NULL && function_->proxy()->var()->IsContextSlot() ? 1 : 0); 1408 } 1409 1410 } } // namespace v8::internal 1411