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
VariableMap(Zone * zone)27 VariableMap::VariableMap(Zone* zone)
28 : ZoneHashMap(ZoneHashMap::PointersMatch, 8, ZoneAllocationPolicy(zone)),
29 zone_(zone) {}
~VariableMap()30 VariableMap::~VariableMap() {}
31
32
Declare(Scope * scope,const AstRawString * name,VariableMode mode,bool is_valid_lhs,Variable::Kind kind,InitializationFlag initialization_flag,MaybeAssignedFlag maybe_assigned_flag,Interface * interface)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
Lookup(const AstRawString * name)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
Scope(Scope * outer_scope,ScopeType scope_type,AstValueFactory * ast_value_factory,Zone * zone)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
Scope(Scope * inner_scope,ScopeType scope_type,Handle<ScopeInfo> scope_info,AstValueFactory * value_factory,Zone * zone)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
Scope(Scope * inner_scope,const AstRawString * catch_variable_name,AstValueFactory * value_factory,Zone * zone)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
SetDefaults(ScopeType scope_type,Scope * outer_scope,Handle<ScopeInfo> scope_info)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
DeserializeScopeChain(Context * context,Scope * global_scope,Zone * zone)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
Analyze(CompilationInfo * info)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
Initialize()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
FinalizeBlockScope()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
LookupLocal(const AstRawString * name)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
LookupFunctionVar(const AstRawString * name,AstNodeFactory<AstNullVisitor> * factory)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
Lookup(const AstRawString * name)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
DeclareParameter(const AstRawString * name,VariableMode mode)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
DeclareLocal(const AstRawString * name,VariableMode mode,InitializationFlag init_flag,MaybeAssignedFlag maybe_assigned_flag,Interface * interface)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
DeclareDynamicGlobal(const AstRawString * name)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
RemoveUnresolved(VariableProxy * var)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
NewInternal(const AstRawString * name)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
NewTemporary(const AstRawString * name)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
AddDeclaration(Declaration * declaration)525 void Scope::AddDeclaration(Declaration* declaration) {
526 decls_.Add(declaration, zone());
527 }
528
529
SetIllegalRedeclaration(Expression * expression)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
VisitIllegalRedeclaration(AstVisitor * visitor)539 void Scope::VisitIllegalRedeclaration(AstVisitor* visitor) {
540 DCHECK(HasIllegalRedeclaration());
541 illegal_redecl_->Accept(visitor);
542 }
543
544
CheckConflictingVarDeclarations()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:
VarAndOrder(Variable * var,int order)571 VarAndOrder(Variable* var, int order) : var_(var), order_(order) { }
var() const572 Variable* var() const { return var_; }
order() const573 int order() const { return order_; }
Compare(const VarAndOrder * a,const VarAndOrder * b)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
CollectStackAndContextLocals(ZoneList<Variable * > * stack_locals,ZoneList<Variable * > * context_locals)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
AllocateVariables(CompilationInfo * info,AstNodeFactory<AstNullVisitor> * factory)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
HasTrivialContext() const663 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
HasTrivialOuterContext() const677 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
HasLazyCompilableOuterContext() const687 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
AllowsLazyCompilation() const705 bool Scope::AllowsLazyCompilation() const {
706 return !force_eager_compilation_ && HasLazyCompilableOuterContext();
707 }
708
709
AllowsLazyCompilationWithoutContext() const710 bool Scope::AllowsLazyCompilationWithoutContext() const {
711 return !force_eager_compilation_ && HasTrivialOuterContext();
712 }
713
714
ContextChainLength(Scope * scope)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
GlobalScope()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
DeclarationScope()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
GetScopeInfo()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
GetNestedScopeChain(List<Handle<ScopeInfo>> * chain,int position)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
Header(ScopeType scope_type)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
Indent(int n,const char * str)788 static void Indent(int n, const char* str) {
789 PrintF("%*s%s", n, "", str);
790 }
791
792
PrintName(const AstRawString * name)793 static void PrintName(const AstRawString* name) {
794 PrintF("%.*s", name->length(), name->raw_data());
795 }
796
797
PrintLocation(Variable * var)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
PrintVar(int indent,Variable * var)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
PrintMap(int indent,VariableMap * map)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
Print(int n)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
NonLocal(const AstRawString * name,VariableMode mode)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
LookupRecursive(VariableProxy * proxy,BindingKind * binding_kind,AstNodeFactory<AstNullVisitor> * factory)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
ResolveVariable(CompilationInfo * info,VariableProxy * proxy,AstNodeFactory<AstNullVisitor> * factory)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
ResolveVariablesRecursively(CompilationInfo * info,AstNodeFactory<AstNullVisitor> * factory)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
PropagateScopeInfo(bool outer_scope_calls_sloppy_eval)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
MustAllocate(Variable * var)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
MustAllocateInContext(Variable * var)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
HasArgumentsParameter()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
AllocateStackSlot(Variable * var)1233 void Scope::AllocateStackSlot(Variable* var) {
1234 var->AllocateTo(Variable::LOCAL, num_stack_slots_++);
1235 }
1236
1237
AllocateHeapSlot(Variable * var)1238 void Scope::AllocateHeapSlot(Variable* var) {
1239 var->AllocateTo(Variable::CONTEXT, num_heap_slots_++);
1240 }
1241
1242
AllocateParameterLocals()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
AllocateNonParameterLocal(Variable * var)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
AllocateNonParameterLocals()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
AllocateVariablesRecursively()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
AllocateModulesRecursively(Scope * host_scope)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
StackLocalCount() const1399 int Scope::StackLocalCount() const {
1400 return num_stack_slots() -
1401 (function_ != NULL && function_->proxy()->var()->IsStackLocal() ? 1 : 0);
1402 }
1403
1404
ContextLocalCount() const1405 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