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