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/ast/scopes.h"
6
7 #include "src/accessors.h"
8 #include "src/ast/scopeinfo.h"
9 #include "src/bootstrapper.h"
10 #include "src/messages.h"
11 #include "src/parsing/parser.h" // for ParseInfo
12
13 namespace v8 {
14 namespace internal {
15
16 // ----------------------------------------------------------------------------
17 // Implementation of LocalsMap
18 //
19 // Note: We are storing the handle locations as key values in the hash map.
20 // When inserting a new variable via Declare(), we rely on the fact that
21 // the handle location remains alive for the duration of that variable
22 // use. Because a Variable holding a handle with the same location exists
23 // this is ensured.
24
VariableMap(Zone * zone)25 VariableMap::VariableMap(Zone* zone)
26 : ZoneHashMap(ZoneHashMap::PointersMatch, 8, ZoneAllocationPolicy(zone)),
27 zone_(zone) {}
~VariableMap()28 VariableMap::~VariableMap() {}
29
30
Declare(Scope * scope,const AstRawString * name,VariableMode mode,Variable::Kind kind,InitializationFlag initialization_flag,MaybeAssignedFlag maybe_assigned_flag,int declaration_group_start)31 Variable* VariableMap::Declare(Scope* scope, const AstRawString* name,
32 VariableMode mode, Variable::Kind kind,
33 InitializationFlag initialization_flag,
34 MaybeAssignedFlag maybe_assigned_flag,
35 int declaration_group_start) {
36 // AstRawStrings are unambiguous, i.e., the same string is always represented
37 // by the same AstRawString*.
38 // FIXME(marja): fix the type of Lookup.
39 Entry* p =
40 ZoneHashMap::LookupOrInsert(const_cast<AstRawString*>(name), name->hash(),
41 ZoneAllocationPolicy(zone()));
42 if (p->value == NULL) {
43 // The variable has not been declared yet -> insert it.
44 DCHECK(p->key == name);
45 if (kind == Variable::CLASS) {
46 p->value = new (zone())
47 ClassVariable(scope, name, mode, initialization_flag,
48 maybe_assigned_flag, declaration_group_start);
49 } else {
50 p->value = new (zone()) Variable(
51 scope, name, mode, kind, initialization_flag, maybe_assigned_flag);
52 }
53 }
54 return reinterpret_cast<Variable*>(p->value);
55 }
56
57
Lookup(const AstRawString * name)58 Variable* VariableMap::Lookup(const AstRawString* name) {
59 Entry* p = ZoneHashMap::Lookup(const_cast<AstRawString*>(name), name->hash());
60 if (p != NULL) {
61 DCHECK(reinterpret_cast<const AstRawString*>(p->key) == name);
62 DCHECK(p->value != NULL);
63 return reinterpret_cast<Variable*>(p->value);
64 }
65 return NULL;
66 }
67
68
SloppyBlockFunctionMap(Zone * zone)69 SloppyBlockFunctionMap::SloppyBlockFunctionMap(Zone* zone)
70 : ZoneHashMap(ZoneHashMap::PointersMatch, 8, ZoneAllocationPolicy(zone)),
71 zone_(zone) {}
~SloppyBlockFunctionMap()72 SloppyBlockFunctionMap::~SloppyBlockFunctionMap() {}
73
74
Declare(const AstRawString * name,SloppyBlockFunctionStatement * stmt)75 void SloppyBlockFunctionMap::Declare(const AstRawString* name,
76 SloppyBlockFunctionStatement* stmt) {
77 // AstRawStrings are unambiguous, i.e., the same string is always represented
78 // by the same AstRawString*.
79 Entry* p =
80 ZoneHashMap::LookupOrInsert(const_cast<AstRawString*>(name), name->hash(),
81 ZoneAllocationPolicy(zone_));
82 if (p->value == nullptr) {
83 p->value = new (zone_->New(sizeof(Vector))) Vector(zone_);
84 }
85 Vector* delegates = static_cast<Vector*>(p->value);
86 delegates->push_back(stmt);
87 }
88
89
90 // ----------------------------------------------------------------------------
91 // Implementation of Scope
92
Scope(Zone * zone,Scope * outer_scope,ScopeType scope_type,AstValueFactory * ast_value_factory,FunctionKind function_kind)93 Scope::Scope(Zone* zone, Scope* outer_scope, ScopeType scope_type,
94 AstValueFactory* ast_value_factory, FunctionKind function_kind)
95 : inner_scopes_(4, zone),
96 variables_(zone),
97 temps_(4, zone),
98 params_(4, zone),
99 unresolved_(16, zone),
100 decls_(4, zone),
101 module_descriptor_(
102 scope_type == MODULE_SCOPE ? ModuleDescriptor::New(zone) : NULL),
103 sloppy_block_function_map_(zone),
104 already_resolved_(false),
105 ast_value_factory_(ast_value_factory),
106 zone_(zone),
107 class_declaration_group_start_(-1) {
108 SetDefaults(scope_type, outer_scope, Handle<ScopeInfo>::null(),
109 function_kind);
110 // The outermost scope must be a script scope.
111 DCHECK(scope_type == SCRIPT_SCOPE || outer_scope != NULL);
112 DCHECK(!HasIllegalRedeclaration());
113 }
114
115
Scope(Zone * zone,Scope * inner_scope,ScopeType scope_type,Handle<ScopeInfo> scope_info,AstValueFactory * value_factory)116 Scope::Scope(Zone* zone, Scope* inner_scope, ScopeType scope_type,
117 Handle<ScopeInfo> scope_info, AstValueFactory* value_factory)
118 : inner_scopes_(4, zone),
119 variables_(zone),
120 temps_(4, zone),
121 params_(4, zone),
122 unresolved_(16, zone),
123 decls_(4, zone),
124 module_descriptor_(NULL),
125 sloppy_block_function_map_(zone),
126 already_resolved_(true),
127 ast_value_factory_(value_factory),
128 zone_(zone),
129 class_declaration_group_start_(-1) {
130 SetDefaults(scope_type, NULL, scope_info);
131 if (!scope_info.is_null()) {
132 num_heap_slots_ = scope_info_->ContextLength();
133 }
134 // Ensure at least MIN_CONTEXT_SLOTS to indicate a materialized context.
135 num_heap_slots_ = Max(num_heap_slots_,
136 static_cast<int>(Context::MIN_CONTEXT_SLOTS));
137 AddInnerScope(inner_scope);
138 }
139
140
Scope(Zone * zone,Scope * inner_scope,const AstRawString * catch_variable_name,AstValueFactory * value_factory)141 Scope::Scope(Zone* zone, Scope* inner_scope,
142 const AstRawString* catch_variable_name,
143 AstValueFactory* value_factory)
144 : inner_scopes_(1, zone),
145 variables_(zone),
146 temps_(0, zone),
147 params_(0, zone),
148 unresolved_(0, zone),
149 decls_(0, zone),
150 module_descriptor_(NULL),
151 sloppy_block_function_map_(zone),
152 already_resolved_(true),
153 ast_value_factory_(value_factory),
154 zone_(zone),
155 class_declaration_group_start_(-1) {
156 SetDefaults(CATCH_SCOPE, NULL, Handle<ScopeInfo>::null());
157 AddInnerScope(inner_scope);
158 ++num_var_or_const_;
159 num_heap_slots_ = Context::MIN_CONTEXT_SLOTS;
160 Variable* variable = variables_.Declare(this,
161 catch_variable_name,
162 VAR,
163 Variable::NORMAL,
164 kCreatedInitialized);
165 AllocateHeapSlot(variable);
166 }
167
168
SetDefaults(ScopeType scope_type,Scope * outer_scope,Handle<ScopeInfo> scope_info,FunctionKind function_kind)169 void Scope::SetDefaults(ScopeType scope_type, Scope* outer_scope,
170 Handle<ScopeInfo> scope_info,
171 FunctionKind function_kind) {
172 outer_scope_ = outer_scope;
173 scope_type_ = scope_type;
174 is_declaration_scope_ =
175 is_eval_scope() || is_function_scope() ||
176 is_module_scope() || is_script_scope();
177 function_kind_ = function_kind;
178 scope_name_ = ast_value_factory_->empty_string();
179 dynamics_ = nullptr;
180 receiver_ = nullptr;
181 new_target_ = nullptr;
182 function_ = nullptr;
183 arguments_ = nullptr;
184 this_function_ = nullptr;
185 illegal_redecl_ = nullptr;
186 scope_inside_with_ = false;
187 scope_contains_with_ = false;
188 scope_calls_eval_ = false;
189 scope_uses_arguments_ = false;
190 scope_uses_super_property_ = false;
191 asm_module_ = false;
192 asm_function_ = outer_scope != NULL && outer_scope->asm_module_;
193 // Inherit the language mode from the parent scope.
194 language_mode_ = outer_scope != NULL ? outer_scope->language_mode_ : SLOPPY;
195 outer_scope_calls_sloppy_eval_ = false;
196 inner_scope_calls_eval_ = false;
197 scope_nonlinear_ = false;
198 force_eager_compilation_ = false;
199 force_context_allocation_ = (outer_scope != NULL && !is_function_scope())
200 ? outer_scope->has_forced_context_allocation() : false;
201 num_var_or_const_ = 0;
202 num_stack_slots_ = 0;
203 num_heap_slots_ = 0;
204 num_global_slots_ = 0;
205 arity_ = 0;
206 has_simple_parameters_ = true;
207 rest_parameter_ = NULL;
208 rest_index_ = -1;
209 scope_info_ = scope_info;
210 start_position_ = RelocInfo::kNoPosition;
211 end_position_ = RelocInfo::kNoPosition;
212 if (!scope_info.is_null()) {
213 scope_calls_eval_ = scope_info->CallsEval();
214 language_mode_ = scope_info->language_mode();
215 is_declaration_scope_ = scope_info->is_declaration_scope();
216 function_kind_ = scope_info->function_kind();
217 }
218 }
219
220
DeserializeScopeChain(Isolate * isolate,Zone * zone,Context * context,Scope * script_scope)221 Scope* Scope::DeserializeScopeChain(Isolate* isolate, Zone* zone,
222 Context* context, Scope* script_scope) {
223 // Reconstruct the outer scope chain from a closure's context chain.
224 Scope* current_scope = NULL;
225 Scope* innermost_scope = NULL;
226 bool contains_with = false;
227 while (!context->IsNativeContext()) {
228 if (context->IsWithContext()) {
229 Scope* with_scope = new (zone)
230 Scope(zone, current_scope, WITH_SCOPE, Handle<ScopeInfo>::null(),
231 script_scope->ast_value_factory_);
232 current_scope = with_scope;
233 // All the inner scopes are inside a with.
234 contains_with = true;
235 for (Scope* s = innermost_scope; s != NULL; s = s->outer_scope()) {
236 s->scope_inside_with_ = true;
237 }
238 } else if (context->IsScriptContext()) {
239 ScopeInfo* scope_info = context->scope_info();
240 current_scope = new (zone) Scope(zone, current_scope, SCRIPT_SCOPE,
241 Handle<ScopeInfo>(scope_info),
242 script_scope->ast_value_factory_);
243 } else if (context->IsModuleContext()) {
244 ScopeInfo* scope_info = context->module()->scope_info();
245 current_scope = new (zone) Scope(zone, current_scope, MODULE_SCOPE,
246 Handle<ScopeInfo>(scope_info),
247 script_scope->ast_value_factory_);
248 } else if (context->IsFunctionContext()) {
249 ScopeInfo* scope_info = context->closure()->shared()->scope_info();
250 current_scope = new (zone) Scope(zone, current_scope, FUNCTION_SCOPE,
251 Handle<ScopeInfo>(scope_info),
252 script_scope->ast_value_factory_);
253 if (scope_info->IsAsmFunction()) current_scope->asm_function_ = true;
254 if (scope_info->IsAsmModule()) current_scope->asm_module_ = true;
255 } else if (context->IsBlockContext()) {
256 ScopeInfo* scope_info = context->scope_info();
257 current_scope = new (zone)
258 Scope(zone, current_scope, BLOCK_SCOPE, Handle<ScopeInfo>(scope_info),
259 script_scope->ast_value_factory_);
260 } else {
261 DCHECK(context->IsCatchContext());
262 String* name = context->catch_name();
263 current_scope = new (zone) Scope(
264 zone, current_scope,
265 script_scope->ast_value_factory_->GetString(Handle<String>(name)),
266 script_scope->ast_value_factory_);
267 }
268 if (contains_with) current_scope->RecordWithStatement();
269 if (innermost_scope == NULL) innermost_scope = current_scope;
270
271 // Forget about a with when we move to a context for a different function.
272 if (context->previous()->closure() != context->closure()) {
273 contains_with = false;
274 }
275 context = context->previous();
276 }
277
278 script_scope->AddInnerScope(current_scope);
279 script_scope->PropagateScopeInfo(false);
280 return (innermost_scope == NULL) ? script_scope : innermost_scope;
281 }
282
283
Analyze(ParseInfo * info)284 bool Scope::Analyze(ParseInfo* info) {
285 DCHECK(info->literal() != NULL);
286 DCHECK(info->scope() == NULL);
287 Scope* scope = info->literal()->scope();
288 Scope* top = scope;
289
290 // Traverse the scope tree up to the first unresolved scope or the global
291 // scope and start scope resolution and variable allocation from that scope.
292 while (!top->is_script_scope() &&
293 !top->outer_scope()->already_resolved()) {
294 top = top->outer_scope();
295 }
296
297 // Allocate the variables.
298 {
299 AstNodeFactory ast_node_factory(info->ast_value_factory());
300 if (!top->AllocateVariables(info, &ast_node_factory)) {
301 DCHECK(top->pending_error_handler_.has_pending_error());
302 top->pending_error_handler_.ThrowPendingError(info->isolate(),
303 info->script());
304 return false;
305 }
306 }
307
308 #ifdef DEBUG
309 if (info->script_is_native() ? FLAG_print_builtin_scopes
310 : FLAG_print_scopes) {
311 scope->Print();
312 }
313 #endif
314
315 info->set_scope(scope);
316 return true;
317 }
318
319
Initialize()320 void Scope::Initialize() {
321 DCHECK(!already_resolved());
322
323 // Add this scope as a new inner scope of the outer scope.
324 if (outer_scope_ != NULL) {
325 outer_scope_->inner_scopes_.Add(this, zone());
326 scope_inside_with_ = outer_scope_->scope_inside_with_ || is_with_scope();
327 } else {
328 scope_inside_with_ = is_with_scope();
329 }
330
331 // Declare convenience variables and the receiver.
332 if (is_declaration_scope() && has_this_declaration()) {
333 bool subclass_constructor = IsSubclassConstructor(function_kind_);
334 Variable* var = variables_.Declare(
335 this, ast_value_factory_->this_string(),
336 subclass_constructor ? CONST : VAR, Variable::THIS,
337 subclass_constructor ? kNeedsInitialization : kCreatedInitialized);
338 receiver_ = var;
339 }
340
341 if (is_function_scope() && !is_arrow_scope()) {
342 // Declare 'arguments' variable which exists in all non arrow functions.
343 // Note that it might never be accessed, in which case it won't be
344 // allocated during variable allocation.
345 variables_.Declare(this, ast_value_factory_->arguments_string(), VAR,
346 Variable::ARGUMENTS, kCreatedInitialized);
347
348 variables_.Declare(this, ast_value_factory_->new_target_string(), CONST,
349 Variable::NORMAL, kCreatedInitialized);
350
351 if (IsConciseMethod(function_kind_) || IsClassConstructor(function_kind_) ||
352 IsAccessorFunction(function_kind_)) {
353 variables_.Declare(this, ast_value_factory_->this_function_string(),
354 CONST, Variable::NORMAL, kCreatedInitialized);
355 }
356 }
357 }
358
359
FinalizeBlockScope()360 Scope* Scope::FinalizeBlockScope() {
361 DCHECK(is_block_scope());
362 DCHECK(temps_.is_empty());
363 DCHECK(params_.is_empty());
364
365 if (num_var_or_const() > 0 ||
366 (is_declaration_scope() && calls_sloppy_eval())) {
367 return this;
368 }
369
370 // Remove this scope from outer scope.
371 outer_scope()->RemoveInnerScope(this);
372
373 // Reparent inner scopes.
374 for (int i = 0; i < inner_scopes_.length(); i++) {
375 outer_scope()->AddInnerScope(inner_scopes_[i]);
376 }
377
378 // Move unresolved variables
379 for (int i = 0; i < unresolved_.length(); i++) {
380 outer_scope()->unresolved_.Add(unresolved_[i], zone());
381 }
382
383 PropagateUsageFlagsToScope(outer_scope_);
384
385 return NULL;
386 }
387
388
ReplaceOuterScope(Scope * outer)389 void Scope::ReplaceOuterScope(Scope* outer) {
390 DCHECK_NOT_NULL(outer);
391 DCHECK_NOT_NULL(outer_scope_);
392 DCHECK(!already_resolved());
393 DCHECK(!outer->already_resolved());
394 DCHECK(!outer_scope_->already_resolved());
395 outer_scope_->RemoveInnerScope(this);
396 outer->AddInnerScope(this);
397 outer_scope_ = outer;
398 }
399
400
PropagateUsageFlagsToScope(Scope * other)401 void Scope::PropagateUsageFlagsToScope(Scope* other) {
402 DCHECK_NOT_NULL(other);
403 DCHECK(!already_resolved());
404 DCHECK(!other->already_resolved());
405 if (uses_arguments()) other->RecordArgumentsUsage();
406 if (uses_super_property()) other->RecordSuperPropertyUsage();
407 if (calls_eval()) other->RecordEvalCall();
408 if (scope_contains_with_) other->RecordWithStatement();
409 }
410
411
LookupLocal(const AstRawString * name)412 Variable* Scope::LookupLocal(const AstRawString* name) {
413 Variable* result = variables_.Lookup(name);
414 if (result != NULL || scope_info_.is_null()) {
415 return result;
416 }
417 Handle<String> name_handle = name->string();
418 // The Scope is backed up by ScopeInfo. This means it cannot operate in a
419 // heap-independent mode, and all strings must be internalized immediately. So
420 // it's ok to get the Handle<String> here.
421 // If we have a serialized scope info, we might find the variable there.
422 // There should be no local slot with the given name.
423 DCHECK(scope_info_->StackSlotIndex(*name_handle) < 0 || is_block_scope());
424
425 // Check context slot lookup.
426 VariableMode mode;
427 VariableLocation location = VariableLocation::CONTEXT;
428 InitializationFlag init_flag;
429 MaybeAssignedFlag maybe_assigned_flag;
430 int index = ScopeInfo::ContextSlotIndex(scope_info_, name_handle, &mode,
431 &init_flag, &maybe_assigned_flag);
432 if (index < 0) {
433 location = VariableLocation::GLOBAL;
434 index = ScopeInfo::ContextGlobalSlotIndex(scope_info_, name_handle, &mode,
435 &init_flag, &maybe_assigned_flag);
436 }
437 if (index < 0) {
438 // Check parameters.
439 index = scope_info_->ParameterIndex(*name_handle);
440 if (index < 0) return NULL;
441
442 mode = DYNAMIC;
443 location = VariableLocation::LOOKUP;
444 init_flag = kCreatedInitialized;
445 // Be conservative and flag parameters as maybe assigned. Better information
446 // would require ScopeInfo to serialize the maybe_assigned bit also for
447 // parameters.
448 maybe_assigned_flag = kMaybeAssigned;
449 } else {
450 DCHECK(location != VariableLocation::GLOBAL ||
451 (is_script_scope() && IsDeclaredVariableMode(mode) &&
452 !IsLexicalVariableMode(mode)));
453 }
454
455 Variable::Kind kind = Variable::NORMAL;
456 if (location == VariableLocation::CONTEXT &&
457 index == scope_info_->ReceiverContextSlotIndex()) {
458 kind = Variable::THIS;
459 }
460 // TODO(marja, rossberg): Correctly declare FUNCTION, CLASS, NEW_TARGET, and
461 // ARGUMENTS bindings as their corresponding Variable::Kind.
462
463 Variable* var = variables_.Declare(this, name, mode, kind, init_flag,
464 maybe_assigned_flag);
465 var->AllocateTo(location, index);
466 return var;
467 }
468
469
LookupFunctionVar(const AstRawString * name,AstNodeFactory * factory)470 Variable* Scope::LookupFunctionVar(const AstRawString* name,
471 AstNodeFactory* factory) {
472 if (function_ != NULL && function_->proxy()->raw_name() == name) {
473 return function_->proxy()->var();
474 } else if (!scope_info_.is_null()) {
475 // If we are backed by a scope info, try to lookup the variable there.
476 VariableMode mode;
477 int index = scope_info_->FunctionContextSlotIndex(*(name->string()), &mode);
478 if (index < 0) return NULL;
479 Variable* var = new (zone())
480 Variable(this, name, mode, Variable::NORMAL, kCreatedInitialized);
481 VariableProxy* proxy = factory->NewVariableProxy(var);
482 VariableDeclaration* declaration = factory->NewVariableDeclaration(
483 proxy, mode, this, RelocInfo::kNoPosition);
484 DeclareFunctionVar(declaration);
485 var->AllocateTo(VariableLocation::CONTEXT, index);
486 return var;
487 } else {
488 return NULL;
489 }
490 }
491
492
Lookup(const AstRawString * name)493 Variable* Scope::Lookup(const AstRawString* name) {
494 for (Scope* scope = this;
495 scope != NULL;
496 scope = scope->outer_scope()) {
497 Variable* var = scope->LookupLocal(name);
498 if (var != NULL) return var;
499 }
500 return NULL;
501 }
502
503
DeclareParameter(const AstRawString * name,VariableMode mode,bool is_optional,bool is_rest,bool * is_duplicate)504 Variable* Scope::DeclareParameter(
505 const AstRawString* name, VariableMode mode,
506 bool is_optional, bool is_rest, bool* is_duplicate) {
507 DCHECK(!already_resolved());
508 DCHECK(is_function_scope());
509 DCHECK(!is_optional || !is_rest);
510 Variable* var;
511 if (mode == TEMPORARY) {
512 var = NewTemporary(name);
513 } else {
514 var = variables_.Declare(this, name, mode, Variable::NORMAL,
515 kCreatedInitialized);
516 // TODO(wingo): Avoid O(n^2) check.
517 *is_duplicate = IsDeclaredParameter(name);
518 }
519 if (!is_optional && !is_rest && arity_ == params_.length()) {
520 ++arity_;
521 }
522 if (is_rest) {
523 DCHECK_NULL(rest_parameter_);
524 rest_parameter_ = var;
525 rest_index_ = num_parameters();
526 }
527 params_.Add(var, zone());
528 return var;
529 }
530
531
DeclareLocal(const AstRawString * name,VariableMode mode,InitializationFlag init_flag,Variable::Kind kind,MaybeAssignedFlag maybe_assigned_flag,int declaration_group_start)532 Variable* Scope::DeclareLocal(const AstRawString* name, VariableMode mode,
533 InitializationFlag init_flag, Variable::Kind kind,
534 MaybeAssignedFlag maybe_assigned_flag,
535 int declaration_group_start) {
536 DCHECK(!already_resolved());
537 // This function handles VAR, LET, and CONST modes. DYNAMIC variables are
538 // introduces during variable allocation, and TEMPORARY variables are
539 // allocated via NewTemporary().
540 DCHECK(IsDeclaredVariableMode(mode));
541 ++num_var_or_const_;
542 return variables_.Declare(this, name, mode, kind, init_flag,
543 maybe_assigned_flag, declaration_group_start);
544 }
545
546
DeclareDynamicGlobal(const AstRawString * name)547 Variable* Scope::DeclareDynamicGlobal(const AstRawString* name) {
548 DCHECK(is_script_scope());
549 return variables_.Declare(this,
550 name,
551 DYNAMIC_GLOBAL,
552 Variable::NORMAL,
553 kCreatedInitialized);
554 }
555
556
RemoveUnresolved(VariableProxy * var)557 bool Scope::RemoveUnresolved(VariableProxy* var) {
558 // Most likely (always?) any variable we want to remove
559 // was just added before, so we search backwards.
560 for (int i = unresolved_.length(); i-- > 0;) {
561 if (unresolved_[i] == var) {
562 unresolved_.Remove(i);
563 return true;
564 }
565 }
566 return false;
567 }
568
569
NewTemporary(const AstRawString * name)570 Variable* Scope::NewTemporary(const AstRawString* name) {
571 DCHECK(!already_resolved());
572 Scope* scope = this->ClosureScope();
573 Variable* var = new(zone()) Variable(scope,
574 name,
575 TEMPORARY,
576 Variable::NORMAL,
577 kCreatedInitialized);
578 scope->AddTemporary(var);
579 return var;
580 }
581
582
RemoveTemporary(Variable * var)583 bool Scope::RemoveTemporary(Variable* var) {
584 // Most likely (always?) any temporary variable we want to remove
585 // was just added before, so we search backwards.
586 for (int i = temps_.length(); i-- > 0;) {
587 if (temps_[i] == var) {
588 temps_.Remove(i);
589 return true;
590 }
591 }
592 return false;
593 }
594
595
AddDeclaration(Declaration * declaration)596 void Scope::AddDeclaration(Declaration* declaration) {
597 decls_.Add(declaration, zone());
598 }
599
600
SetIllegalRedeclaration(Expression * expression)601 void Scope::SetIllegalRedeclaration(Expression* expression) {
602 // Record only the first illegal redeclaration.
603 if (!HasIllegalRedeclaration()) {
604 illegal_redecl_ = expression;
605 }
606 DCHECK(HasIllegalRedeclaration());
607 }
608
609
GetIllegalRedeclaration()610 Expression* Scope::GetIllegalRedeclaration() {
611 DCHECK(HasIllegalRedeclaration());
612 return illegal_redecl_;
613 }
614
615
CheckConflictingVarDeclarations()616 Declaration* Scope::CheckConflictingVarDeclarations() {
617 int length = decls_.length();
618 for (int i = 0; i < length; i++) {
619 Declaration* decl = decls_[i];
620 // We don't create a separate scope to hold the function name of a function
621 // expression, so we have to make sure not to consider it when checking for
622 // conflicts (since it's conceptually "outside" the declaration scope).
623 if (is_function_scope() && decl == function()) continue;
624 if (IsLexicalVariableMode(decl->mode()) && !is_block_scope()) continue;
625 const AstRawString* name = decl->proxy()->raw_name();
626
627 // Iterate through all scopes until and including the declaration scope.
628 Scope* previous = NULL;
629 Scope* current = decl->scope();
630 // Lexical vs lexical conflicts within the same scope have already been
631 // captured in Parser::Declare. The only conflicts we still need to check
632 // are lexical vs VAR, or any declarations within a declaration block scope
633 // vs lexical declarations in its surrounding (function) scope.
634 if (IsLexicalVariableMode(decl->mode())) current = current->outer_scope_;
635 do {
636 // There is a conflict if there exists a non-VAR binding.
637 Variable* other_var = current->variables_.Lookup(name);
638 if (other_var != NULL && IsLexicalVariableMode(other_var->mode())) {
639 return decl;
640 }
641 previous = current;
642 current = current->outer_scope_;
643 } while (!previous->is_declaration_scope());
644 }
645 return NULL;
646 }
647
648
649 class VarAndOrder {
650 public:
VarAndOrder(Variable * var,int order)651 VarAndOrder(Variable* var, int order) : var_(var), order_(order) { }
var() const652 Variable* var() const { return var_; }
order() const653 int order() const { return order_; }
Compare(const VarAndOrder * a,const VarAndOrder * b)654 static int Compare(const VarAndOrder* a, const VarAndOrder* b) {
655 return a->order_ - b->order_;
656 }
657
658 private:
659 Variable* var_;
660 int order_;
661 };
662
663
CollectStackAndContextLocals(ZoneList<Variable * > * stack_locals,ZoneList<Variable * > * context_locals,ZoneList<Variable * > * context_globals,ZoneList<Variable * > * strong_mode_free_variables)664 void Scope::CollectStackAndContextLocals(
665 ZoneList<Variable*>* stack_locals, ZoneList<Variable*>* context_locals,
666 ZoneList<Variable*>* context_globals,
667 ZoneList<Variable*>* strong_mode_free_variables) {
668 DCHECK(stack_locals != NULL);
669 DCHECK(context_locals != NULL);
670 DCHECK(context_globals != NULL);
671
672 // Collect temporaries which are always allocated on the stack, unless the
673 // context as a whole has forced context allocation.
674 for (int i = 0; i < temps_.length(); i++) {
675 Variable* var = temps_[i];
676 if (var->is_used()) {
677 if (var->IsContextSlot()) {
678 DCHECK(has_forced_context_allocation());
679 context_locals->Add(var, zone());
680 } else if (var->IsStackLocal()) {
681 stack_locals->Add(var, zone());
682 } else {
683 DCHECK(var->IsParameter());
684 }
685 }
686 }
687
688 // Collect declared local variables.
689 ZoneList<VarAndOrder> vars(variables_.occupancy(), zone());
690 for (VariableMap::Entry* p = variables_.Start();
691 p != NULL;
692 p = variables_.Next(p)) {
693 Variable* var = reinterpret_cast<Variable*>(p->value);
694 if (strong_mode_free_variables && var->has_strong_mode_reference() &&
695 var->mode() == DYNAMIC_GLOBAL) {
696 strong_mode_free_variables->Add(var, zone());
697 }
698
699 if (var->is_used()) {
700 vars.Add(VarAndOrder(var, p->order), zone());
701 }
702 }
703 vars.Sort(VarAndOrder::Compare);
704 int var_count = vars.length();
705 for (int i = 0; i < var_count; i++) {
706 Variable* var = vars[i].var();
707 if (var->IsStackLocal()) {
708 stack_locals->Add(var, zone());
709 } else if (var->IsContextSlot()) {
710 context_locals->Add(var, zone());
711 } else if (var->IsGlobalSlot()) {
712 context_globals->Add(var, zone());
713 }
714 }
715 }
716
717
AllocateVariables(ParseInfo * info,AstNodeFactory * factory)718 bool Scope::AllocateVariables(ParseInfo* info, AstNodeFactory* factory) {
719 // 1) Propagate scope information.
720 bool outer_scope_calls_sloppy_eval = false;
721 if (outer_scope_ != NULL) {
722 outer_scope_calls_sloppy_eval =
723 outer_scope_->outer_scope_calls_sloppy_eval() |
724 outer_scope_->calls_sloppy_eval();
725 }
726 PropagateScopeInfo(outer_scope_calls_sloppy_eval);
727
728 // 2) Resolve variables.
729 if (!ResolveVariablesRecursively(info, factory)) return false;
730
731 // 3) Allocate variables.
732 AllocateVariablesRecursively(info->isolate());
733
734 return true;
735 }
736
737
HasTrivialContext() const738 bool Scope::HasTrivialContext() const {
739 // A function scope has a trivial context if it always is the global
740 // context. We iteratively scan out the context chain to see if
741 // there is anything that makes this scope non-trivial; otherwise we
742 // return true.
743 for (const Scope* scope = this; scope != NULL; scope = scope->outer_scope_) {
744 if (scope->is_eval_scope()) return false;
745 if (scope->scope_inside_with_) return false;
746 if (scope->ContextLocalCount() > 0) return false;
747 if (scope->ContextGlobalCount() > 0) return false;
748 }
749 return true;
750 }
751
752
HasTrivialOuterContext() const753 bool Scope::HasTrivialOuterContext() const {
754 Scope* outer = outer_scope_;
755 if (outer == NULL) return true;
756 // Note that the outer context may be trivial in general, but the current
757 // scope may be inside a 'with' statement in which case the outer context
758 // for this scope is not trivial.
759 return !scope_inside_with_ && outer->HasTrivialContext();
760 }
761
762
AllowsLazyParsing() const763 bool Scope::AllowsLazyParsing() const {
764 // If we are inside a block scope, we must parse eagerly to find out how
765 // to allocate variables on the block scope. At this point, declarations may
766 // not have yet been parsed.
767 for (const Scope* scope = this; scope != NULL; scope = scope->outer_scope_) {
768 if (scope->is_block_scope()) return false;
769 }
770 return AllowsLazyCompilation();
771 }
772
773
AllowsLazyCompilation() const774 bool Scope::AllowsLazyCompilation() const { return !force_eager_compilation_; }
775
776
AllowsLazyCompilationWithoutContext() const777 bool Scope::AllowsLazyCompilationWithoutContext() const {
778 return !force_eager_compilation_ && HasTrivialOuterContext();
779 }
780
781
ContextChainLength(Scope * scope)782 int Scope::ContextChainLength(Scope* scope) {
783 int n = 0;
784 for (Scope* s = this; s != scope; s = s->outer_scope_) {
785 DCHECK(s != NULL); // scope must be in the scope chain
786 if (s->NeedsContext()) n++;
787 }
788 return n;
789 }
790
791
MaxNestedContextChainLength()792 int Scope::MaxNestedContextChainLength() {
793 int max_context_chain_length = 0;
794 for (int i = 0; i < inner_scopes_.length(); i++) {
795 Scope* scope = inner_scopes_[i];
796 max_context_chain_length = std::max(scope->MaxNestedContextChainLength(),
797 max_context_chain_length);
798 }
799 if (NeedsContext()) {
800 max_context_chain_length += 1;
801 }
802 return max_context_chain_length;
803 }
804
805
DeclarationScope()806 Scope* Scope::DeclarationScope() {
807 Scope* scope = this;
808 while (!scope->is_declaration_scope()) {
809 scope = scope->outer_scope();
810 }
811 return scope;
812 }
813
814
ClosureScope()815 Scope* Scope::ClosureScope() {
816 Scope* scope = this;
817 while (!scope->is_declaration_scope() || scope->is_block_scope()) {
818 scope = scope->outer_scope();
819 }
820 return scope;
821 }
822
823
ReceiverScope()824 Scope* Scope::ReceiverScope() {
825 Scope* scope = this;
826 while (!scope->is_script_scope() &&
827 (!scope->is_function_scope() || scope->is_arrow_scope())) {
828 scope = scope->outer_scope();
829 }
830 return scope;
831 }
832
833
834
GetScopeInfo(Isolate * isolate)835 Handle<ScopeInfo> Scope::GetScopeInfo(Isolate* isolate) {
836 if (scope_info_.is_null()) {
837 scope_info_ = ScopeInfo::Create(isolate, zone(), this);
838 }
839 return scope_info_;
840 }
841
842
GetNestedScopeChain(Isolate * isolate,List<Handle<ScopeInfo>> * chain,int position)843 void Scope::GetNestedScopeChain(Isolate* isolate,
844 List<Handle<ScopeInfo> >* chain, int position) {
845 if (!is_eval_scope()) chain->Add(Handle<ScopeInfo>(GetScopeInfo(isolate)));
846
847 for (int i = 0; i < inner_scopes_.length(); i++) {
848 Scope* scope = inner_scopes_[i];
849 int beg_pos = scope->start_position();
850 int end_pos = scope->end_position();
851 DCHECK(beg_pos >= 0 && end_pos >= 0);
852 if (beg_pos <= position && position < end_pos) {
853 scope->GetNestedScopeChain(isolate, chain, position);
854 return;
855 }
856 }
857 }
858
859
CollectNonLocals(HashMap * non_locals)860 void Scope::CollectNonLocals(HashMap* non_locals) {
861 // Collect non-local variables referenced in the scope.
862 // TODO(yangguo): store non-local variables explicitly if we can no longer
863 // rely on unresolved_ to find them.
864 for (int i = 0; i < unresolved_.length(); i++) {
865 VariableProxy* proxy = unresolved_[i];
866 if (proxy->is_resolved() && proxy->var()->IsStackAllocated()) continue;
867 Handle<String> name = proxy->name();
868 void* key = reinterpret_cast<void*>(name.location());
869 HashMap::Entry* entry = non_locals->LookupOrInsert(key, name->Hash());
870 entry->value = key;
871 }
872 for (int i = 0; i < inner_scopes_.length(); i++) {
873 inner_scopes_[i]->CollectNonLocals(non_locals);
874 }
875 }
876
877
ReportMessage(int start_position,int end_position,MessageTemplate::Template message,const AstRawString * arg)878 void Scope::ReportMessage(int start_position, int end_position,
879 MessageTemplate::Template message,
880 const AstRawString* arg) {
881 // Propagate the error to the topmost scope targeted by this scope analysis
882 // phase.
883 Scope* top = this;
884 while (!top->is_script_scope() && !top->outer_scope()->already_resolved()) {
885 top = top->outer_scope();
886 }
887
888 top->pending_error_handler_.ReportMessageAt(start_position, end_position,
889 message, arg, kReferenceError);
890 }
891
892
893 #ifdef DEBUG
Header(ScopeType scope_type,FunctionKind function_kind,bool is_declaration_scope)894 static const char* Header(ScopeType scope_type, FunctionKind function_kind,
895 bool is_declaration_scope) {
896 switch (scope_type) {
897 case EVAL_SCOPE: return "eval";
898 // TODO(adamk): Should we print concise method scopes specially?
899 case FUNCTION_SCOPE:
900 return IsArrowFunction(function_kind) ? "arrow" : "function";
901 case MODULE_SCOPE: return "module";
902 case SCRIPT_SCOPE: return "global";
903 case CATCH_SCOPE: return "catch";
904 case BLOCK_SCOPE: return is_declaration_scope ? "varblock" : "block";
905 case WITH_SCOPE: return "with";
906 }
907 UNREACHABLE();
908 return NULL;
909 }
910
911
Indent(int n,const char * str)912 static void Indent(int n, const char* str) {
913 PrintF("%*s%s", n, "", str);
914 }
915
916
PrintName(const AstRawString * name)917 static void PrintName(const AstRawString* name) {
918 PrintF("%.*s", name->length(), name->raw_data());
919 }
920
921
PrintLocation(Variable * var)922 static void PrintLocation(Variable* var) {
923 switch (var->location()) {
924 case VariableLocation::UNALLOCATED:
925 break;
926 case VariableLocation::PARAMETER:
927 PrintF("parameter[%d]", var->index());
928 break;
929 case VariableLocation::LOCAL:
930 PrintF("local[%d]", var->index());
931 break;
932 case VariableLocation::CONTEXT:
933 PrintF("context[%d]", var->index());
934 break;
935 case VariableLocation::GLOBAL:
936 PrintF("global[%d]", var->index());
937 break;
938 case VariableLocation::LOOKUP:
939 PrintF("lookup");
940 break;
941 }
942 }
943
944
PrintVar(int indent,Variable * var)945 static void PrintVar(int indent, Variable* var) {
946 if (var->is_used() || !var->IsUnallocated()) {
947 Indent(indent, Variable::Mode2String(var->mode()));
948 PrintF(" ");
949 if (var->raw_name()->IsEmpty())
950 PrintF(".%p", reinterpret_cast<void*>(var));
951 else
952 PrintName(var->raw_name());
953 PrintF("; // ");
954 PrintLocation(var);
955 bool comma = !var->IsUnallocated();
956 if (var->has_forced_context_allocation()) {
957 if (comma) PrintF(", ");
958 PrintF("forced context allocation");
959 comma = true;
960 }
961 if (var->maybe_assigned() == kMaybeAssigned) {
962 if (comma) PrintF(", ");
963 PrintF("maybe assigned");
964 }
965 PrintF("\n");
966 }
967 }
968
969
PrintMap(int indent,VariableMap * map)970 static void PrintMap(int indent, VariableMap* map) {
971 for (VariableMap::Entry* p = map->Start(); p != NULL; p = map->Next(p)) {
972 Variable* var = reinterpret_cast<Variable*>(p->value);
973 if (var == NULL) {
974 Indent(indent, "<?>\n");
975 } else {
976 PrintVar(indent, var);
977 }
978 }
979 }
980
981
Print(int n)982 void Scope::Print(int n) {
983 int n0 = (n > 0 ? n : 0);
984 int n1 = n0 + 2; // indentation
985
986 // Print header.
987 Indent(n0, Header(scope_type_, function_kind_, is_declaration_scope()));
988 if (scope_name_ != nullptr && !scope_name_->IsEmpty()) {
989 PrintF(" ");
990 PrintName(scope_name_);
991 }
992
993 // Print parameters, if any.
994 if (is_function_scope()) {
995 PrintF(" (");
996 for (int i = 0; i < params_.length(); i++) {
997 if (i > 0) PrintF(", ");
998 const AstRawString* name = params_[i]->raw_name();
999 if (name->IsEmpty())
1000 PrintF(".%p", reinterpret_cast<void*>(params_[i]));
1001 else
1002 PrintName(name);
1003 }
1004 PrintF(")");
1005 }
1006
1007 PrintF(" { // (%d, %d)\n", start_position(), end_position());
1008
1009 // Function name, if any (named function literals, only).
1010 if (function_ != NULL) {
1011 Indent(n1, "// (local) function name: ");
1012 PrintName(function_->proxy()->raw_name());
1013 PrintF("\n");
1014 }
1015
1016 // Scope info.
1017 if (HasTrivialOuterContext()) {
1018 Indent(n1, "// scope has trivial outer context\n");
1019 }
1020 if (is_strong(language_mode())) {
1021 Indent(n1, "// strong mode scope\n");
1022 } else if (is_strict(language_mode())) {
1023 Indent(n1, "// strict mode scope\n");
1024 }
1025 if (scope_inside_with_) Indent(n1, "// scope inside 'with'\n");
1026 if (scope_contains_with_) Indent(n1, "// scope contains 'with'\n");
1027 if (scope_calls_eval_) Indent(n1, "// scope calls 'eval'\n");
1028 if (scope_uses_arguments_) Indent(n1, "// scope uses 'arguments'\n");
1029 if (scope_uses_super_property_)
1030 Indent(n1, "// scope uses 'super' property\n");
1031 if (outer_scope_calls_sloppy_eval_) {
1032 Indent(n1, "// outer scope calls 'eval' in sloppy context\n");
1033 }
1034 if (inner_scope_calls_eval_) Indent(n1, "// inner scope calls 'eval'\n");
1035 if (num_stack_slots_ > 0) {
1036 Indent(n1, "// ");
1037 PrintF("%d stack slots\n", num_stack_slots_);
1038 }
1039 if (num_heap_slots_ > 0) {
1040 Indent(n1, "// ");
1041 PrintF("%d heap slots (including %d global slots)\n", num_heap_slots_,
1042 num_global_slots_);
1043 }
1044
1045 // Print locals.
1046 if (function_ != NULL) {
1047 Indent(n1, "// function var:\n");
1048 PrintVar(n1, function_->proxy()->var());
1049 }
1050
1051 if (temps_.length() > 0) {
1052 Indent(n1, "// temporary vars:\n");
1053 for (int i = 0; i < temps_.length(); i++) {
1054 PrintVar(n1, temps_[i]);
1055 }
1056 }
1057
1058 if (variables_.Start() != NULL) {
1059 Indent(n1, "// local vars:\n");
1060 PrintMap(n1, &variables_);
1061 }
1062
1063 if (dynamics_ != NULL) {
1064 Indent(n1, "// dynamic vars:\n");
1065 PrintMap(n1, dynamics_->GetMap(DYNAMIC));
1066 PrintMap(n1, dynamics_->GetMap(DYNAMIC_LOCAL));
1067 PrintMap(n1, dynamics_->GetMap(DYNAMIC_GLOBAL));
1068 }
1069
1070 // Print inner scopes (disable by providing negative n).
1071 if (n >= 0) {
1072 for (int i = 0; i < inner_scopes_.length(); i++) {
1073 PrintF("\n");
1074 inner_scopes_[i]->Print(n1);
1075 }
1076 }
1077
1078 Indent(n0, "}\n");
1079 }
1080 #endif // DEBUG
1081
1082
NonLocal(const AstRawString * name,VariableMode mode)1083 Variable* Scope::NonLocal(const AstRawString* name, VariableMode mode) {
1084 if (dynamics_ == NULL) dynamics_ = new (zone()) DynamicScopePart(zone());
1085 VariableMap* map = dynamics_->GetMap(mode);
1086 Variable* var = map->Lookup(name);
1087 if (var == NULL) {
1088 // Declare a new non-local.
1089 InitializationFlag init_flag = (mode == VAR)
1090 ? kCreatedInitialized : kNeedsInitialization;
1091 var = map->Declare(NULL,
1092 name,
1093 mode,
1094 Variable::NORMAL,
1095 init_flag);
1096 // Allocate it by giving it a dynamic lookup.
1097 var->AllocateTo(VariableLocation::LOOKUP, -1);
1098 }
1099 return var;
1100 }
1101
1102
LookupRecursive(VariableProxy * proxy,BindingKind * binding_kind,AstNodeFactory * factory)1103 Variable* Scope::LookupRecursive(VariableProxy* proxy,
1104 BindingKind* binding_kind,
1105 AstNodeFactory* factory) {
1106 DCHECK(binding_kind != NULL);
1107 if (already_resolved() && is_with_scope()) {
1108 // Short-cut: if the scope is deserialized from a scope info, variable
1109 // allocation is already fixed. We can simply return with dynamic lookup.
1110 *binding_kind = DYNAMIC_LOOKUP;
1111 return NULL;
1112 }
1113
1114 // Try to find the variable in this scope.
1115 Variable* var = LookupLocal(proxy->raw_name());
1116
1117 // We found a variable and we are done. (Even if there is an 'eval' in
1118 // this scope which introduces the same variable again, the resulting
1119 // variable remains the same.)
1120 if (var != NULL) {
1121 *binding_kind = BOUND;
1122 return var;
1123 }
1124
1125 // We did not find a variable locally. Check against the function variable,
1126 // if any. We can do this for all scopes, since the function variable is
1127 // only present - if at all - for function scopes.
1128 *binding_kind = UNBOUND;
1129 var = LookupFunctionVar(proxy->raw_name(), factory);
1130 if (var != NULL) {
1131 *binding_kind = BOUND;
1132 } else if (outer_scope_ != NULL) {
1133 var = outer_scope_->LookupRecursive(proxy, binding_kind, factory);
1134 if (*binding_kind == BOUND && (is_function_scope() || is_with_scope())) {
1135 var->ForceContextAllocation();
1136 }
1137 } else {
1138 DCHECK(is_script_scope());
1139 }
1140
1141 // "this" can't be shadowed by "eval"-introduced bindings or by "with" scopes.
1142 // TODO(wingo): There are other variables in this category; add them.
1143 bool name_can_be_shadowed = var == nullptr || !var->is_this();
1144
1145 if (is_with_scope() && name_can_be_shadowed) {
1146 DCHECK(!already_resolved());
1147 // The current scope is a with scope, so the variable binding can not be
1148 // statically resolved. However, note that it was necessary to do a lookup
1149 // in the outer scope anyway, because if a binding exists in an outer scope,
1150 // the associated variable has to be marked as potentially being accessed
1151 // from inside of an inner with scope (the property may not be in the 'with'
1152 // object).
1153 if (var != NULL && proxy->is_assigned()) var->set_maybe_assigned();
1154 *binding_kind = DYNAMIC_LOOKUP;
1155 return NULL;
1156 } else if (calls_sloppy_eval() && !is_script_scope() &&
1157 name_can_be_shadowed) {
1158 // A variable binding may have been found in an outer scope, but the current
1159 // scope makes a sloppy 'eval' call, so the found variable may not be
1160 // the correct one (the 'eval' may introduce a binding with the same name).
1161 // In that case, change the lookup result to reflect this situation.
1162 if (*binding_kind == BOUND) {
1163 *binding_kind = BOUND_EVAL_SHADOWED;
1164 } else if (*binding_kind == UNBOUND) {
1165 *binding_kind = UNBOUND_EVAL_SHADOWED;
1166 }
1167 }
1168 return var;
1169 }
1170
1171
ResolveVariable(ParseInfo * info,VariableProxy * proxy,AstNodeFactory * factory)1172 bool Scope::ResolveVariable(ParseInfo* info, VariableProxy* proxy,
1173 AstNodeFactory* factory) {
1174 DCHECK(info->script_scope()->is_script_scope());
1175
1176 // If the proxy is already resolved there's nothing to do
1177 // (functions and consts may be resolved by the parser).
1178 if (proxy->is_resolved()) return true;
1179
1180 // Otherwise, try to resolve the variable.
1181 BindingKind binding_kind;
1182 Variable* var = LookupRecursive(proxy, &binding_kind, factory);
1183
1184 #ifdef DEBUG
1185 if (info->script_is_native()) {
1186 // To avoid polluting the global object in native scripts
1187 // - Variables must not be allocated to the global scope.
1188 CHECK_NOT_NULL(outer_scope());
1189 // - Variables must be bound locally or unallocated.
1190 if (BOUND != binding_kind) {
1191 // The following variable name may be minified. If so, disable
1192 // minification in js2c.py for better output.
1193 Handle<String> name = proxy->raw_name()->string();
1194 V8_Fatal(__FILE__, __LINE__, "Unbound variable: '%s' in native script.",
1195 name->ToCString().get());
1196 }
1197 VariableLocation location = var->location();
1198 CHECK(location == VariableLocation::LOCAL ||
1199 location == VariableLocation::CONTEXT ||
1200 location == VariableLocation::PARAMETER ||
1201 location == VariableLocation::UNALLOCATED);
1202 }
1203 #endif
1204
1205 switch (binding_kind) {
1206 case BOUND:
1207 // We found a variable binding.
1208 if (is_strong(language_mode())) {
1209 if (!CheckStrongModeDeclaration(proxy, var)) return false;
1210 }
1211 break;
1212
1213 case BOUND_EVAL_SHADOWED:
1214 // We either found a variable binding that might be shadowed by eval or
1215 // gave up on it (e.g. by encountering a local with the same in the outer
1216 // scope which was not promoted to a context, this can happen if we use
1217 // debugger to evaluate arbitrary expressions at a break point).
1218 if (var->IsGlobalObjectProperty()) {
1219 var = NonLocal(proxy->raw_name(), DYNAMIC_GLOBAL);
1220 } else if (var->is_dynamic()) {
1221 var = NonLocal(proxy->raw_name(), DYNAMIC);
1222 } else {
1223 Variable* invalidated = var;
1224 var = NonLocal(proxy->raw_name(), DYNAMIC_LOCAL);
1225 var->set_local_if_not_shadowed(invalidated);
1226 }
1227 break;
1228
1229 case UNBOUND:
1230 // No binding has been found. Declare a variable on the global object.
1231 var = info->script_scope()->DeclareDynamicGlobal(proxy->raw_name());
1232 break;
1233
1234 case UNBOUND_EVAL_SHADOWED:
1235 // No binding has been found. But some scope makes a sloppy 'eval' call.
1236 var = NonLocal(proxy->raw_name(), DYNAMIC_GLOBAL);
1237 break;
1238
1239 case DYNAMIC_LOOKUP:
1240 // The variable could not be resolved statically.
1241 var = NonLocal(proxy->raw_name(), DYNAMIC);
1242 break;
1243 }
1244
1245 DCHECK(var != NULL);
1246 if (proxy->is_assigned()) var->set_maybe_assigned();
1247
1248 if (is_strong(language_mode())) {
1249 // Record that the variable is referred to from strong mode. Also, record
1250 // the position.
1251 var->RecordStrongModeReference(proxy->position(), proxy->end_position());
1252 }
1253
1254 proxy->BindTo(var);
1255
1256 return true;
1257 }
1258
1259
CheckStrongModeDeclaration(VariableProxy * proxy,Variable * var)1260 bool Scope::CheckStrongModeDeclaration(VariableProxy* proxy, Variable* var) {
1261 // Check for declaration-after use (for variables) in strong mode. Note that
1262 // we can only do this in the case where we have seen the declaration. And we
1263 // always allow referencing functions (for now).
1264
1265 // This might happen during lazy compilation; we don't keep track of
1266 // initializer positions for variables stored in ScopeInfo, so we cannot check
1267 // bindings against them. TODO(marja, rossberg): remove this hack.
1268 if (var->initializer_position() == RelocInfo::kNoPosition) return true;
1269
1270 // Allow referencing the class name from methods of that class, even though
1271 // the initializer position for class names is only after the body.
1272 Scope* scope = this;
1273 while (scope) {
1274 if (scope->ClassVariableForMethod() == var) return true;
1275 scope = scope->outer_scope();
1276 }
1277
1278 // Allow references from methods to classes declared later, if we detect no
1279 // problematic dependency cycles. Note that we can be inside multiple methods
1280 // at the same time, and it's enough if we find one where the reference is
1281 // allowed.
1282 if (var->is_class() &&
1283 var->AsClassVariable()->declaration_group_start() >= 0) {
1284 for (scope = this; scope && scope != var->scope();
1285 scope = scope->outer_scope()) {
1286 ClassVariable* class_var = scope->ClassVariableForMethod();
1287 // A method is referring to some other class, possibly declared
1288 // later. Referring to a class declared earlier is always OK and covered
1289 // by the code outside this if. Here we only need to allow special cases
1290 // for referring to a class which is declared later.
1291
1292 // Referring to a class C declared later is OK under the following
1293 // circumstances:
1294
1295 // 1. The class declarations are in a consecutive group with no other
1296 // declarations or statements in between, and
1297
1298 // 2. There is no dependency cycle where the first edge is an
1299 // initialization time dependency (computed property name or extends
1300 // clause) from C to something that depends on this class directly or
1301 // transitively.
1302 if (class_var &&
1303 class_var->declaration_group_start() ==
1304 var->AsClassVariable()->declaration_group_start()) {
1305 return true;
1306 }
1307
1308 // TODO(marja,rossberg): implement the dependency cycle detection. Here we
1309 // undershoot the target and allow referring to any class in the same
1310 // consectuive declaration group.
1311
1312 // The cycle detection can work roughly like this: 1) detect init-time
1313 // references here (they are free variables which are inside the class
1314 // scope but not inside a method scope - no parser changes needed to
1315 // detect them) 2) if we encounter an init-time reference here, allow it,
1316 // but record it for a later dependency cycle check 3) also record
1317 // non-init-time references here 4) after scope analysis is done, analyse
1318 // the dependency cycles: an illegal cycle is one starting with an
1319 // init-time reference and leading back to the starting point with either
1320 // non-init-time and init-time references.
1321 }
1322 }
1323
1324 // If both the use and the declaration are inside an eval scope (possibly
1325 // indirectly), or one of them is, we need to check whether they are inside
1326 // the same eval scope or different ones.
1327
1328 // TODO(marja,rossberg): Detect errors across different evals (depends on the
1329 // future of eval in strong mode).
1330 const Scope* eval_for_use = NearestOuterEvalScope();
1331 const Scope* eval_for_declaration = var->scope()->NearestOuterEvalScope();
1332
1333 if (proxy->position() != RelocInfo::kNoPosition &&
1334 proxy->position() < var->initializer_position() && !var->is_function() &&
1335 eval_for_use == eval_for_declaration) {
1336 DCHECK(proxy->end_position() != RelocInfo::kNoPosition);
1337 ReportMessage(proxy->position(), proxy->end_position(),
1338 MessageTemplate::kStrongUseBeforeDeclaration,
1339 proxy->raw_name());
1340 return false;
1341 }
1342 return true;
1343 }
1344
1345
ClassVariableForMethod() const1346 ClassVariable* Scope::ClassVariableForMethod() const {
1347 // TODO(marja, rossberg): This fails to find a class variable in the following
1348 // cases:
1349 // let A = class { ... }
1350 // It needs to be investigated whether this causes any practical problems.
1351 if (!is_function_scope()) return nullptr;
1352 if (IsInObjectLiteral(function_kind_)) return nullptr;
1353 if (!IsConciseMethod(function_kind_) && !IsClassConstructor(function_kind_) &&
1354 !IsAccessorFunction(function_kind_)) {
1355 return nullptr;
1356 }
1357 DCHECK_NOT_NULL(outer_scope_);
1358 // The class scope contains at most one variable, the class name.
1359 DCHECK(outer_scope_->variables_.occupancy() <= 1);
1360 if (outer_scope_->variables_.occupancy() == 0) return nullptr;
1361 VariableMap::Entry* p = outer_scope_->variables_.Start();
1362 Variable* var = reinterpret_cast<Variable*>(p->value);
1363 if (!var->is_class()) return nullptr;
1364 return var->AsClassVariable();
1365 }
1366
1367
ResolveVariablesRecursively(ParseInfo * info,AstNodeFactory * factory)1368 bool Scope::ResolveVariablesRecursively(ParseInfo* info,
1369 AstNodeFactory* factory) {
1370 DCHECK(info->script_scope()->is_script_scope());
1371
1372 // Resolve unresolved variables for this scope.
1373 for (int i = 0; i < unresolved_.length(); i++) {
1374 if (!ResolveVariable(info, unresolved_[i], factory)) return false;
1375 }
1376
1377 // Resolve unresolved variables for inner scopes.
1378 for (int i = 0; i < inner_scopes_.length(); i++) {
1379 if (!inner_scopes_[i]->ResolveVariablesRecursively(info, factory))
1380 return false;
1381 }
1382
1383 return true;
1384 }
1385
1386
PropagateScopeInfo(bool outer_scope_calls_sloppy_eval)1387 void Scope::PropagateScopeInfo(bool outer_scope_calls_sloppy_eval ) {
1388 if (outer_scope_calls_sloppy_eval) {
1389 outer_scope_calls_sloppy_eval_ = true;
1390 }
1391
1392 bool calls_sloppy_eval =
1393 this->calls_sloppy_eval() || outer_scope_calls_sloppy_eval_;
1394 for (int i = 0; i < inner_scopes_.length(); i++) {
1395 Scope* inner = inner_scopes_[i];
1396 inner->PropagateScopeInfo(calls_sloppy_eval);
1397 if (inner->scope_calls_eval_ || inner->inner_scope_calls_eval_) {
1398 inner_scope_calls_eval_ = true;
1399 }
1400 if (inner->force_eager_compilation_) {
1401 force_eager_compilation_ = true;
1402 }
1403 if (asm_module_ && inner->scope_type() == FUNCTION_SCOPE) {
1404 inner->asm_function_ = true;
1405 }
1406 }
1407 }
1408
1409
MustAllocate(Variable * var)1410 bool Scope::MustAllocate(Variable* var) {
1411 // Give var a read/write use if there is a chance it might be accessed
1412 // via an eval() call. This is only possible if the variable has a
1413 // visible name.
1414 if ((var->is_this() || !var->raw_name()->IsEmpty()) &&
1415 (var->has_forced_context_allocation() || scope_calls_eval_ ||
1416 inner_scope_calls_eval_ || scope_contains_with_ || is_catch_scope() ||
1417 is_block_scope() || is_module_scope() || is_script_scope())) {
1418 var->set_is_used();
1419 if (scope_calls_eval_ || inner_scope_calls_eval_) var->set_maybe_assigned();
1420 }
1421 // Global variables do not need to be allocated.
1422 return !var->IsGlobalObjectProperty() && var->is_used();
1423 }
1424
1425
MustAllocateInContext(Variable * var)1426 bool Scope::MustAllocateInContext(Variable* var) {
1427 // If var is accessed from an inner scope, or if there is a possibility
1428 // that it might be accessed from the current or an inner scope (through
1429 // an eval() call or a runtime with lookup), it must be allocated in the
1430 // context.
1431 //
1432 // Exceptions: If the scope as a whole has forced context allocation, all
1433 // variables will have context allocation, even temporaries. Otherwise
1434 // temporary variables are always stack-allocated. Catch-bound variables are
1435 // always context-allocated.
1436 if (has_forced_context_allocation()) return true;
1437 if (var->mode() == TEMPORARY) return false;
1438 if (is_catch_scope() || is_module_scope()) return true;
1439 if (is_script_scope() && IsLexicalVariableMode(var->mode())) return true;
1440 return var->has_forced_context_allocation() ||
1441 scope_calls_eval_ ||
1442 inner_scope_calls_eval_ ||
1443 scope_contains_with_;
1444 }
1445
1446
HasArgumentsParameter(Isolate * isolate)1447 bool Scope::HasArgumentsParameter(Isolate* isolate) {
1448 for (int i = 0; i < params_.length(); i++) {
1449 if (params_[i]->name().is_identical_to(
1450 isolate->factory()->arguments_string())) {
1451 return true;
1452 }
1453 }
1454 return false;
1455 }
1456
1457
AllocateStackSlot(Variable * var)1458 void Scope::AllocateStackSlot(Variable* var) {
1459 if (is_block_scope()) {
1460 outer_scope()->DeclarationScope()->AllocateStackSlot(var);
1461 } else {
1462 var->AllocateTo(VariableLocation::LOCAL, num_stack_slots_++);
1463 }
1464 }
1465
1466
AllocateHeapSlot(Variable * var)1467 void Scope::AllocateHeapSlot(Variable* var) {
1468 var->AllocateTo(VariableLocation::CONTEXT, num_heap_slots_++);
1469 }
1470
1471
AllocateParameterLocals(Isolate * isolate)1472 void Scope::AllocateParameterLocals(Isolate* isolate) {
1473 DCHECK(is_function_scope());
1474 Variable* arguments = LookupLocal(ast_value_factory_->arguments_string());
1475 // Functions have 'arguments' declared implicitly in all non arrow functions.
1476 DCHECK(arguments != nullptr || is_arrow_scope());
1477
1478 bool uses_sloppy_arguments = false;
1479
1480 if (arguments != nullptr && MustAllocate(arguments) &&
1481 !HasArgumentsParameter(isolate)) {
1482 // 'arguments' is used. Unless there is also a parameter called
1483 // 'arguments', we must be conservative and allocate all parameters to
1484 // the context assuming they will be captured by the arguments object.
1485 // If we have a parameter named 'arguments', a (new) value is always
1486 // assigned to it via the function invocation. Then 'arguments' denotes
1487 // that specific parameter value and cannot be used to access the
1488 // parameters, which is why we don't need to allocate an arguments
1489 // object in that case.
1490
1491 // We are using 'arguments'. Tell the code generator that is needs to
1492 // allocate the arguments object by setting 'arguments_'.
1493 arguments_ = arguments;
1494
1495 // In strict mode 'arguments' does not alias formal parameters.
1496 // Therefore in strict mode we allocate parameters as if 'arguments'
1497 // were not used.
1498 // If the parameter list is not simple, arguments isn't sloppy either.
1499 uses_sloppy_arguments =
1500 is_sloppy(language_mode()) && has_simple_parameters();
1501 }
1502
1503 if (rest_parameter_ && !MustAllocate(rest_parameter_)) {
1504 rest_parameter_ = NULL;
1505 }
1506
1507 // The same parameter may occur multiple times in the parameters_ list.
1508 // If it does, and if it is not copied into the context object, it must
1509 // receive the highest parameter index for that parameter; thus iteration
1510 // order is relevant!
1511 for (int i = params_.length() - 1; i >= 0; --i) {
1512 Variable* var = params_[i];
1513 if (var == rest_parameter_) continue;
1514
1515 DCHECK(var->scope() == this);
1516 if (uses_sloppy_arguments || has_forced_context_allocation()) {
1517 // Force context allocation of the parameter.
1518 var->ForceContextAllocation();
1519 }
1520 AllocateParameter(var, i);
1521 }
1522 }
1523
1524
AllocateParameter(Variable * var,int index)1525 void Scope::AllocateParameter(Variable* var, int index) {
1526 if (MustAllocate(var)) {
1527 if (MustAllocateInContext(var)) {
1528 DCHECK(var->IsUnallocated() || var->IsContextSlot());
1529 if (var->IsUnallocated()) {
1530 AllocateHeapSlot(var);
1531 }
1532 } else {
1533 DCHECK(var->IsUnallocated() || var->IsParameter());
1534 if (var->IsUnallocated()) {
1535 var->AllocateTo(VariableLocation::PARAMETER, index);
1536 }
1537 }
1538 } else {
1539 DCHECK(!var->IsGlobalSlot());
1540 }
1541 }
1542
1543
AllocateReceiver()1544 void Scope::AllocateReceiver() {
1545 DCHECK_NOT_NULL(receiver());
1546 DCHECK_EQ(receiver()->scope(), this);
1547
1548 if (has_forced_context_allocation()) {
1549 // Force context allocation of the receiver.
1550 receiver()->ForceContextAllocation();
1551 }
1552 AllocateParameter(receiver(), -1);
1553 }
1554
1555
AllocateNonParameterLocal(Isolate * isolate,Variable * var)1556 void Scope::AllocateNonParameterLocal(Isolate* isolate, Variable* var) {
1557 DCHECK(var->scope() == this);
1558 DCHECK(!var->IsVariable(isolate->factory()->dot_result_string()) ||
1559 !var->IsStackLocal());
1560 if (var->IsUnallocated() && MustAllocate(var)) {
1561 if (MustAllocateInContext(var)) {
1562 AllocateHeapSlot(var);
1563 } else {
1564 AllocateStackSlot(var);
1565 }
1566 }
1567 }
1568
1569
AllocateDeclaredGlobal(Isolate * isolate,Variable * var)1570 void Scope::AllocateDeclaredGlobal(Isolate* isolate, Variable* var) {
1571 DCHECK(var->scope() == this);
1572 DCHECK(!var->IsVariable(isolate->factory()->dot_result_string()) ||
1573 !var->IsStackLocal());
1574 if (var->IsUnallocated()) {
1575 if (var->IsStaticGlobalObjectProperty()) {
1576 DCHECK_EQ(-1, var->index());
1577 DCHECK(var->name()->IsString());
1578 var->AllocateTo(VariableLocation::GLOBAL, num_heap_slots_++);
1579 num_global_slots_++;
1580 } else {
1581 // There must be only DYNAMIC_GLOBAL in the script scope.
1582 DCHECK(!is_script_scope() || DYNAMIC_GLOBAL == var->mode());
1583 }
1584 }
1585 }
1586
1587
AllocateNonParameterLocalsAndDeclaredGlobals(Isolate * isolate)1588 void Scope::AllocateNonParameterLocalsAndDeclaredGlobals(Isolate* isolate) {
1589 // All variables that have no rewrite yet are non-parameter locals.
1590 for (int i = 0; i < temps_.length(); i++) {
1591 AllocateNonParameterLocal(isolate, temps_[i]);
1592 }
1593
1594 ZoneList<VarAndOrder> vars(variables_.occupancy(), zone());
1595 for (VariableMap::Entry* p = variables_.Start();
1596 p != NULL;
1597 p = variables_.Next(p)) {
1598 Variable* var = reinterpret_cast<Variable*>(p->value);
1599 vars.Add(VarAndOrder(var, p->order), zone());
1600 }
1601 vars.Sort(VarAndOrder::Compare);
1602 int var_count = vars.length();
1603 for (int i = 0; i < var_count; i++) {
1604 AllocateNonParameterLocal(isolate, vars[i].var());
1605 }
1606
1607 if (FLAG_global_var_shortcuts) {
1608 for (int i = 0; i < var_count; i++) {
1609 AllocateDeclaredGlobal(isolate, vars[i].var());
1610 }
1611 }
1612
1613 // For now, function_ must be allocated at the very end. If it gets
1614 // allocated in the context, it must be the last slot in the context,
1615 // because of the current ScopeInfo implementation (see
1616 // ScopeInfo::ScopeInfo(FunctionScope* scope) constructor).
1617 if (function_ != nullptr) {
1618 AllocateNonParameterLocal(isolate, function_->proxy()->var());
1619 }
1620
1621 if (rest_parameter_ != nullptr) {
1622 AllocateNonParameterLocal(isolate, rest_parameter_);
1623 }
1624
1625 Variable* new_target_var =
1626 LookupLocal(ast_value_factory_->new_target_string());
1627 if (new_target_var != nullptr && MustAllocate(new_target_var)) {
1628 new_target_ = new_target_var;
1629 }
1630
1631 Variable* this_function_var =
1632 LookupLocal(ast_value_factory_->this_function_string());
1633 if (this_function_var != nullptr && MustAllocate(this_function_var)) {
1634 this_function_ = this_function_var;
1635 }
1636 }
1637
1638
AllocateVariablesRecursively(Isolate * isolate)1639 void Scope::AllocateVariablesRecursively(Isolate* isolate) {
1640 if (!already_resolved()) {
1641 num_stack_slots_ = 0;
1642 }
1643 // Allocate variables for inner scopes.
1644 for (int i = 0; i < inner_scopes_.length(); i++) {
1645 inner_scopes_[i]->AllocateVariablesRecursively(isolate);
1646 }
1647
1648 // If scope is already resolved, we still need to allocate
1649 // variables in inner scopes which might not had been resolved yet.
1650 if (already_resolved()) return;
1651 // The number of slots required for variables.
1652 num_heap_slots_ = Context::MIN_CONTEXT_SLOTS;
1653
1654 // Allocate variables for this scope.
1655 // Parameters must be allocated first, if any.
1656 if (is_function_scope()) AllocateParameterLocals(isolate);
1657 if (has_this_declaration()) AllocateReceiver();
1658 AllocateNonParameterLocalsAndDeclaredGlobals(isolate);
1659
1660 // Force allocation of a context for this scope if necessary. For a 'with'
1661 // scope and for a function scope that makes an 'eval' call we need a context,
1662 // even if no local variables were statically allocated in the scope.
1663 // Likewise for modules.
1664 bool must_have_context =
1665 is_with_scope() || is_module_scope() ||
1666 (is_function_scope() && calls_sloppy_eval()) ||
1667 (is_block_scope() && is_declaration_scope() && calls_sloppy_eval());
1668
1669 // If we didn't allocate any locals in the local context, then we only
1670 // need the minimal number of slots if we must have a context.
1671 if (num_heap_slots_ == Context::MIN_CONTEXT_SLOTS && !must_have_context) {
1672 num_heap_slots_ = 0;
1673 }
1674
1675 // Allocation done.
1676 DCHECK(num_heap_slots_ == 0 || num_heap_slots_ >= Context::MIN_CONTEXT_SLOTS);
1677 }
1678
1679
StackLocalCount() const1680 int Scope::StackLocalCount() const {
1681 return num_stack_slots() -
1682 (function_ != NULL && function_->proxy()->var()->IsStackLocal() ? 1 : 0);
1683 }
1684
1685
ContextLocalCount() const1686 int Scope::ContextLocalCount() const {
1687 if (num_heap_slots() == 0) return 0;
1688 bool is_function_var_in_context =
1689 function_ != NULL && function_->proxy()->var()->IsContextSlot();
1690 return num_heap_slots() - Context::MIN_CONTEXT_SLOTS - num_global_slots() -
1691 (is_function_var_in_context ? 1 : 0);
1692 }
1693
1694
ContextGlobalCount() const1695 int Scope::ContextGlobalCount() const { return num_global_slots(); }
1696
1697 } // namespace internal
1698 } // namespace v8
1699