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