blob: 77c5d628f7ec86ca5de28a318b754d2d80f1d790 [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001// 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
13namespace v8 {
14namespace 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
25VariableMap::VariableMap(Zone* zone)
26 : ZoneHashMap(ZoneHashMap::PointersMatch, 8, ZoneAllocationPolicy(zone)),
27 zone_(zone) {}
28VariableMap::~VariableMap() {}
29
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000030Variable* VariableMap::Declare(Scope* scope, const AstRawString* name,
31 VariableMode mode, Variable::Kind kind,
32 InitializationFlag initialization_flag,
Ben Murdoch097c5b22016-05-18 11:27:45 +010033 MaybeAssignedFlag maybe_assigned_flag) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000034 // AstRawStrings are unambiguous, i.e., the same string is always represented
35 // by the same AstRawString*.
36 // FIXME(marja): fix the type of Lookup.
37 Entry* p =
38 ZoneHashMap::LookupOrInsert(const_cast<AstRawString*>(name), name->hash(),
39 ZoneAllocationPolicy(zone()));
40 if (p->value == NULL) {
41 // The variable has not been declared yet -> insert it.
42 DCHECK(p->key == name);
Ben Murdoch097c5b22016-05-18 11:27:45 +010043 p->value = new (zone()) Variable(scope, name, mode, kind,
44 initialization_flag, maybe_assigned_flag);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000045 }
46 return reinterpret_cast<Variable*>(p->value);
47}
48
49
50Variable* VariableMap::Lookup(const AstRawString* name) {
51 Entry* p = ZoneHashMap::Lookup(const_cast<AstRawString*>(name), name->hash());
52 if (p != NULL) {
53 DCHECK(reinterpret_cast<const AstRawString*>(p->key) == name);
54 DCHECK(p->value != NULL);
55 return reinterpret_cast<Variable*>(p->value);
56 }
57 return NULL;
58}
59
60
61SloppyBlockFunctionMap::SloppyBlockFunctionMap(Zone* zone)
62 : ZoneHashMap(ZoneHashMap::PointersMatch, 8, ZoneAllocationPolicy(zone)),
63 zone_(zone) {}
64SloppyBlockFunctionMap::~SloppyBlockFunctionMap() {}
65
66
67void SloppyBlockFunctionMap::Declare(const AstRawString* name,
68 SloppyBlockFunctionStatement* stmt) {
69 // AstRawStrings are unambiguous, i.e., the same string is always represented
70 // by the same AstRawString*.
71 Entry* p =
72 ZoneHashMap::LookupOrInsert(const_cast<AstRawString*>(name), name->hash(),
73 ZoneAllocationPolicy(zone_));
74 if (p->value == nullptr) {
75 p->value = new (zone_->New(sizeof(Vector))) Vector(zone_);
76 }
77 Vector* delegates = static_cast<Vector*>(p->value);
78 delegates->push_back(stmt);
79}
80
81
82// ----------------------------------------------------------------------------
83// Implementation of Scope
84
85Scope::Scope(Zone* zone, Scope* outer_scope, ScopeType scope_type,
86 AstValueFactory* ast_value_factory, FunctionKind function_kind)
87 : inner_scopes_(4, zone),
88 variables_(zone),
89 temps_(4, zone),
90 params_(4, zone),
91 unresolved_(16, zone),
92 decls_(4, zone),
93 module_descriptor_(
94 scope_type == MODULE_SCOPE ? ModuleDescriptor::New(zone) : NULL),
95 sloppy_block_function_map_(zone),
96 already_resolved_(false),
97 ast_value_factory_(ast_value_factory),
Ben Murdoch097c5b22016-05-18 11:27:45 +010098 zone_(zone) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000099 SetDefaults(scope_type, outer_scope, Handle<ScopeInfo>::null(),
100 function_kind);
101 // The outermost scope must be a script scope.
102 DCHECK(scope_type == SCRIPT_SCOPE || outer_scope != NULL);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000103}
104
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000105Scope::Scope(Zone* zone, Scope* inner_scope, ScopeType scope_type,
106 Handle<ScopeInfo> scope_info, AstValueFactory* value_factory)
107 : inner_scopes_(4, zone),
108 variables_(zone),
109 temps_(4, zone),
110 params_(4, zone),
111 unresolved_(16, zone),
112 decls_(4, zone),
113 module_descriptor_(NULL),
114 sloppy_block_function_map_(zone),
115 already_resolved_(true),
116 ast_value_factory_(value_factory),
Ben Murdoch097c5b22016-05-18 11:27:45 +0100117 zone_(zone) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000118 SetDefaults(scope_type, NULL, scope_info);
119 if (!scope_info.is_null()) {
120 num_heap_slots_ = scope_info_->ContextLength();
121 }
122 // Ensure at least MIN_CONTEXT_SLOTS to indicate a materialized context.
123 num_heap_slots_ = Max(num_heap_slots_,
124 static_cast<int>(Context::MIN_CONTEXT_SLOTS));
125 AddInnerScope(inner_scope);
126}
127
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000128Scope::Scope(Zone* zone, Scope* inner_scope,
129 const AstRawString* catch_variable_name,
130 AstValueFactory* value_factory)
131 : inner_scopes_(1, zone),
132 variables_(zone),
133 temps_(0, zone),
134 params_(0, zone),
135 unresolved_(0, zone),
136 decls_(0, zone),
137 module_descriptor_(NULL),
138 sloppy_block_function_map_(zone),
139 already_resolved_(true),
140 ast_value_factory_(value_factory),
Ben Murdoch097c5b22016-05-18 11:27:45 +0100141 zone_(zone) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000142 SetDefaults(CATCH_SCOPE, NULL, Handle<ScopeInfo>::null());
143 AddInnerScope(inner_scope);
144 ++num_var_or_const_;
145 num_heap_slots_ = Context::MIN_CONTEXT_SLOTS;
146 Variable* variable = variables_.Declare(this,
147 catch_variable_name,
148 VAR,
149 Variable::NORMAL,
150 kCreatedInitialized);
151 AllocateHeapSlot(variable);
152}
153
154
155void Scope::SetDefaults(ScopeType scope_type, Scope* outer_scope,
156 Handle<ScopeInfo> scope_info,
157 FunctionKind function_kind) {
158 outer_scope_ = outer_scope;
159 scope_type_ = scope_type;
160 is_declaration_scope_ =
161 is_eval_scope() || is_function_scope() ||
162 is_module_scope() || is_script_scope();
163 function_kind_ = function_kind;
164 scope_name_ = ast_value_factory_->empty_string();
165 dynamics_ = nullptr;
166 receiver_ = nullptr;
167 new_target_ = nullptr;
168 function_ = nullptr;
169 arguments_ = nullptr;
170 this_function_ = nullptr;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000171 scope_inside_with_ = false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000172 scope_calls_eval_ = false;
173 scope_uses_arguments_ = false;
174 scope_uses_super_property_ = false;
175 asm_module_ = false;
176 asm_function_ = outer_scope != NULL && outer_scope->asm_module_;
177 // Inherit the language mode from the parent scope.
Ben Murdochc5610432016-08-08 18:44:38 +0100178 language_mode_ =
179 is_module_scope()
180 ? STRICT
181 : (outer_scope != NULL ? outer_scope->language_mode_ : SLOPPY);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000182 outer_scope_calls_sloppy_eval_ = false;
183 inner_scope_calls_eval_ = false;
184 scope_nonlinear_ = false;
185 force_eager_compilation_ = false;
186 force_context_allocation_ = (outer_scope != NULL && !is_function_scope())
187 ? outer_scope->has_forced_context_allocation() : false;
188 num_var_or_const_ = 0;
189 num_stack_slots_ = 0;
190 num_heap_slots_ = 0;
191 num_global_slots_ = 0;
192 arity_ = 0;
193 has_simple_parameters_ = true;
194 rest_parameter_ = NULL;
195 rest_index_ = -1;
196 scope_info_ = scope_info;
197 start_position_ = RelocInfo::kNoPosition;
198 end_position_ = RelocInfo::kNoPosition;
Ben Murdochc5610432016-08-08 18:44:38 +0100199 is_hidden_ = false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000200 if (!scope_info.is_null()) {
201 scope_calls_eval_ = scope_info->CallsEval();
202 language_mode_ = scope_info->language_mode();
203 is_declaration_scope_ = scope_info->is_declaration_scope();
204 function_kind_ = scope_info->function_kind();
205 }
206}
207
208
209Scope* Scope::DeserializeScopeChain(Isolate* isolate, Zone* zone,
210 Context* context, Scope* script_scope) {
211 // Reconstruct the outer scope chain from a closure's context chain.
212 Scope* current_scope = NULL;
213 Scope* innermost_scope = NULL;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000214 while (!context->IsNativeContext()) {
Ben Murdochda12d292016-06-02 14:46:10 +0100215 if (context->IsWithContext() || context->IsDebugEvaluateContext()) {
216 // For scope analysis, debug-evaluate is equivalent to a with scope.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000217 Scope* with_scope = new (zone)
218 Scope(zone, current_scope, WITH_SCOPE, Handle<ScopeInfo>::null(),
219 script_scope->ast_value_factory_);
220 current_scope = with_scope;
221 // All the inner scopes are inside a with.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000222 for (Scope* s = innermost_scope; s != NULL; s = s->outer_scope()) {
223 s->scope_inside_with_ = true;
224 }
225 } else if (context->IsScriptContext()) {
226 ScopeInfo* scope_info = context->scope_info();
227 current_scope = new (zone) Scope(zone, current_scope, SCRIPT_SCOPE,
228 Handle<ScopeInfo>(scope_info),
229 script_scope->ast_value_factory_);
230 } else if (context->IsModuleContext()) {
231 ScopeInfo* scope_info = context->module()->scope_info();
232 current_scope = new (zone) Scope(zone, current_scope, MODULE_SCOPE,
233 Handle<ScopeInfo>(scope_info),
234 script_scope->ast_value_factory_);
235 } else if (context->IsFunctionContext()) {
236 ScopeInfo* scope_info = context->closure()->shared()->scope_info();
237 current_scope = new (zone) Scope(zone, current_scope, FUNCTION_SCOPE,
238 Handle<ScopeInfo>(scope_info),
239 script_scope->ast_value_factory_);
240 if (scope_info->IsAsmFunction()) current_scope->asm_function_ = true;
241 if (scope_info->IsAsmModule()) current_scope->asm_module_ = true;
242 } else if (context->IsBlockContext()) {
243 ScopeInfo* scope_info = context->scope_info();
244 current_scope = new (zone)
245 Scope(zone, current_scope, BLOCK_SCOPE, Handle<ScopeInfo>(scope_info),
246 script_scope->ast_value_factory_);
247 } else {
248 DCHECK(context->IsCatchContext());
249 String* name = context->catch_name();
250 current_scope = new (zone) Scope(
251 zone, current_scope,
252 script_scope->ast_value_factory_->GetString(Handle<String>(name)),
253 script_scope->ast_value_factory_);
254 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000255 if (innermost_scope == NULL) innermost_scope = current_scope;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000256 context = context->previous();
257 }
258
259 script_scope->AddInnerScope(current_scope);
260 script_scope->PropagateScopeInfo(false);
261 return (innermost_scope == NULL) ? script_scope : innermost_scope;
262}
263
264
265bool Scope::Analyze(ParseInfo* info) {
266 DCHECK(info->literal() != NULL);
267 DCHECK(info->scope() == NULL);
268 Scope* scope = info->literal()->scope();
269 Scope* top = scope;
270
271 // Traverse the scope tree up to the first unresolved scope or the global
272 // scope and start scope resolution and variable allocation from that scope.
273 while (!top->is_script_scope() &&
274 !top->outer_scope()->already_resolved()) {
275 top = top->outer_scope();
276 }
277
278 // Allocate the variables.
279 {
280 AstNodeFactory ast_node_factory(info->ast_value_factory());
281 if (!top->AllocateVariables(info, &ast_node_factory)) {
282 DCHECK(top->pending_error_handler_.has_pending_error());
283 top->pending_error_handler_.ThrowPendingError(info->isolate(),
284 info->script());
285 return false;
286 }
287 }
288
289#ifdef DEBUG
290 if (info->script_is_native() ? FLAG_print_builtin_scopes
291 : FLAG_print_scopes) {
292 scope->Print();
293 }
Ben Murdochc5610432016-08-08 18:44:38 +0100294 scope->CheckScopePositions();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000295#endif
296
297 info->set_scope(scope);
298 return true;
299}
300
301
302void Scope::Initialize() {
303 DCHECK(!already_resolved());
304
305 // Add this scope as a new inner scope of the outer scope.
306 if (outer_scope_ != NULL) {
307 outer_scope_->inner_scopes_.Add(this, zone());
308 scope_inside_with_ = outer_scope_->scope_inside_with_ || is_with_scope();
309 } else {
310 scope_inside_with_ = is_with_scope();
311 }
312
313 // Declare convenience variables and the receiver.
314 if (is_declaration_scope() && has_this_declaration()) {
315 bool subclass_constructor = IsSubclassConstructor(function_kind_);
316 Variable* var = variables_.Declare(
317 this, ast_value_factory_->this_string(),
318 subclass_constructor ? CONST : VAR, Variable::THIS,
319 subclass_constructor ? kNeedsInitialization : kCreatedInitialized);
320 receiver_ = var;
321 }
322
323 if (is_function_scope() && !is_arrow_scope()) {
324 // Declare 'arguments' variable which exists in all non arrow functions.
325 // Note that it might never be accessed, in which case it won't be
326 // allocated during variable allocation.
327 variables_.Declare(this, ast_value_factory_->arguments_string(), VAR,
328 Variable::ARGUMENTS, kCreatedInitialized);
329
330 variables_.Declare(this, ast_value_factory_->new_target_string(), CONST,
331 Variable::NORMAL, kCreatedInitialized);
332
333 if (IsConciseMethod(function_kind_) || IsClassConstructor(function_kind_) ||
334 IsAccessorFunction(function_kind_)) {
335 variables_.Declare(this, ast_value_factory_->this_function_string(),
336 CONST, Variable::NORMAL, kCreatedInitialized);
337 }
338 }
339}
340
341
342Scope* Scope::FinalizeBlockScope() {
343 DCHECK(is_block_scope());
344 DCHECK(temps_.is_empty());
345 DCHECK(params_.is_empty());
346
347 if (num_var_or_const() > 0 ||
348 (is_declaration_scope() && calls_sloppy_eval())) {
349 return this;
350 }
351
352 // Remove this scope from outer scope.
353 outer_scope()->RemoveInnerScope(this);
354
355 // Reparent inner scopes.
356 for (int i = 0; i < inner_scopes_.length(); i++) {
357 outer_scope()->AddInnerScope(inner_scopes_[i]);
358 }
359
360 // Move unresolved variables
361 for (int i = 0; i < unresolved_.length(); i++) {
362 outer_scope()->unresolved_.Add(unresolved_[i], zone());
363 }
364
365 PropagateUsageFlagsToScope(outer_scope_);
366
367 return NULL;
368}
369
370
371void Scope::ReplaceOuterScope(Scope* outer) {
372 DCHECK_NOT_NULL(outer);
373 DCHECK_NOT_NULL(outer_scope_);
374 DCHECK(!already_resolved());
375 DCHECK(!outer->already_resolved());
376 DCHECK(!outer_scope_->already_resolved());
377 outer_scope_->RemoveInnerScope(this);
378 outer->AddInnerScope(this);
379 outer_scope_ = outer;
380}
381
382
383void Scope::PropagateUsageFlagsToScope(Scope* other) {
384 DCHECK_NOT_NULL(other);
385 DCHECK(!already_resolved());
386 DCHECK(!other->already_resolved());
387 if (uses_arguments()) other->RecordArgumentsUsage();
388 if (uses_super_property()) other->RecordSuperPropertyUsage();
389 if (calls_eval()) other->RecordEvalCall();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000390}
391
392
393Variable* Scope::LookupLocal(const AstRawString* name) {
394 Variable* result = variables_.Lookup(name);
395 if (result != NULL || scope_info_.is_null()) {
396 return result;
397 }
398 Handle<String> name_handle = name->string();
399 // The Scope is backed up by ScopeInfo. This means it cannot operate in a
400 // heap-independent mode, and all strings must be internalized immediately. So
401 // it's ok to get the Handle<String> here.
402 // If we have a serialized scope info, we might find the variable there.
403 // There should be no local slot with the given name.
404 DCHECK(scope_info_->StackSlotIndex(*name_handle) < 0 || is_block_scope());
405
406 // Check context slot lookup.
407 VariableMode mode;
408 VariableLocation location = VariableLocation::CONTEXT;
409 InitializationFlag init_flag;
410 MaybeAssignedFlag maybe_assigned_flag;
411 int index = ScopeInfo::ContextSlotIndex(scope_info_, name_handle, &mode,
412 &init_flag, &maybe_assigned_flag);
413 if (index < 0) {
414 location = VariableLocation::GLOBAL;
415 index = ScopeInfo::ContextGlobalSlotIndex(scope_info_, name_handle, &mode,
416 &init_flag, &maybe_assigned_flag);
417 }
418 if (index < 0) {
419 // Check parameters.
420 index = scope_info_->ParameterIndex(*name_handle);
421 if (index < 0) return NULL;
422
423 mode = DYNAMIC;
424 location = VariableLocation::LOOKUP;
425 init_flag = kCreatedInitialized;
426 // Be conservative and flag parameters as maybe assigned. Better information
427 // would require ScopeInfo to serialize the maybe_assigned bit also for
428 // parameters.
429 maybe_assigned_flag = kMaybeAssigned;
430 } else {
431 DCHECK(location != VariableLocation::GLOBAL ||
432 (is_script_scope() && IsDeclaredVariableMode(mode) &&
433 !IsLexicalVariableMode(mode)));
434 }
435
436 Variable::Kind kind = Variable::NORMAL;
437 if (location == VariableLocation::CONTEXT &&
438 index == scope_info_->ReceiverContextSlotIndex()) {
439 kind = Variable::THIS;
440 }
441 // TODO(marja, rossberg): Correctly declare FUNCTION, CLASS, NEW_TARGET, and
442 // ARGUMENTS bindings as their corresponding Variable::Kind.
443
444 Variable* var = variables_.Declare(this, name, mode, kind, init_flag,
445 maybe_assigned_flag);
446 var->AllocateTo(location, index);
447 return var;
448}
449
450
451Variable* Scope::LookupFunctionVar(const AstRawString* name,
452 AstNodeFactory* factory) {
453 if (function_ != NULL && function_->proxy()->raw_name() == name) {
454 return function_->proxy()->var();
455 } else if (!scope_info_.is_null()) {
456 // If we are backed by a scope info, try to lookup the variable there.
457 VariableMode mode;
458 int index = scope_info_->FunctionContextSlotIndex(*(name->string()), &mode);
459 if (index < 0) return NULL;
460 Variable* var = new (zone())
461 Variable(this, name, mode, Variable::NORMAL, kCreatedInitialized);
462 VariableProxy* proxy = factory->NewVariableProxy(var);
463 VariableDeclaration* declaration = factory->NewVariableDeclaration(
464 proxy, mode, this, RelocInfo::kNoPosition);
465 DeclareFunctionVar(declaration);
466 var->AllocateTo(VariableLocation::CONTEXT, index);
467 return var;
468 } else {
469 return NULL;
470 }
471}
472
473
474Variable* Scope::Lookup(const AstRawString* name) {
475 for (Scope* scope = this;
476 scope != NULL;
477 scope = scope->outer_scope()) {
478 Variable* var = scope->LookupLocal(name);
479 if (var != NULL) return var;
480 }
481 return NULL;
482}
483
484
485Variable* Scope::DeclareParameter(
486 const AstRawString* name, VariableMode mode,
487 bool is_optional, bool is_rest, bool* is_duplicate) {
488 DCHECK(!already_resolved());
489 DCHECK(is_function_scope());
490 DCHECK(!is_optional || !is_rest);
491 Variable* var;
492 if (mode == TEMPORARY) {
493 var = NewTemporary(name);
494 } else {
495 var = variables_.Declare(this, name, mode, Variable::NORMAL,
496 kCreatedInitialized);
497 // TODO(wingo): Avoid O(n^2) check.
498 *is_duplicate = IsDeclaredParameter(name);
499 }
500 if (!is_optional && !is_rest && arity_ == params_.length()) {
501 ++arity_;
502 }
503 if (is_rest) {
504 DCHECK_NULL(rest_parameter_);
505 rest_parameter_ = var;
506 rest_index_ = num_parameters();
507 }
508 params_.Add(var, zone());
509 return var;
510}
511
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000512Variable* Scope::DeclareLocal(const AstRawString* name, VariableMode mode,
513 InitializationFlag init_flag, Variable::Kind kind,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100514 MaybeAssignedFlag maybe_assigned_flag) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000515 DCHECK(!already_resolved());
516 // This function handles VAR, LET, and CONST modes. DYNAMIC variables are
Ben Murdoch097c5b22016-05-18 11:27:45 +0100517 // introduced during variable allocation, and TEMPORARY variables are
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000518 // allocated via NewTemporary().
519 DCHECK(IsDeclaredVariableMode(mode));
520 ++num_var_or_const_;
521 return variables_.Declare(this, name, mode, kind, init_flag,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100522 maybe_assigned_flag);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000523}
524
525
526Variable* Scope::DeclareDynamicGlobal(const AstRawString* name) {
527 DCHECK(is_script_scope());
528 return variables_.Declare(this,
529 name,
530 DYNAMIC_GLOBAL,
531 Variable::NORMAL,
532 kCreatedInitialized);
533}
534
535
536bool Scope::RemoveUnresolved(VariableProxy* var) {
537 // Most likely (always?) any variable we want to remove
538 // was just added before, so we search backwards.
539 for (int i = unresolved_.length(); i-- > 0;) {
540 if (unresolved_[i] == var) {
541 unresolved_.Remove(i);
542 return true;
543 }
544 }
545 return false;
546}
547
548
549Variable* Scope::NewTemporary(const AstRawString* name) {
550 DCHECK(!already_resolved());
551 Scope* scope = this->ClosureScope();
552 Variable* var = new(zone()) Variable(scope,
553 name,
554 TEMPORARY,
555 Variable::NORMAL,
556 kCreatedInitialized);
557 scope->AddTemporary(var);
558 return var;
559}
560
Ben Murdochc5610432016-08-08 18:44:38 +0100561int Scope::RemoveTemporary(Variable* var) {
562 DCHECK_NOT_NULL(var);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100563 // Temporaries are only placed in ClosureScopes.
564 DCHECK_EQ(ClosureScope(), this);
565 DCHECK_EQ(var->scope()->ClosureScope(), var->scope());
566 // If the temporary is not here, return quickly.
567 if (var->scope() != this) return -1;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000568 // Most likely (always?) any temporary variable we want to remove
569 // was just added before, so we search backwards.
570 for (int i = temps_.length(); i-- > 0;) {
571 if (temps_[i] == var) {
Ben Murdochc5610432016-08-08 18:44:38 +0100572 // Don't shrink temps_, as callers of this method expect
573 // the returned indices to be unique per-scope.
574 temps_[i] = nullptr;
575 return i;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000576 }
577 }
Ben Murdochc5610432016-08-08 18:44:38 +0100578 return -1;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000579}
580
581
582void Scope::AddDeclaration(Declaration* declaration) {
583 decls_.Add(declaration, zone());
584}
585
586
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000587Declaration* Scope::CheckConflictingVarDeclarations() {
588 int length = decls_.length();
589 for (int i = 0; i < length; i++) {
590 Declaration* decl = decls_[i];
591 // We don't create a separate scope to hold the function name of a function
592 // expression, so we have to make sure not to consider it when checking for
593 // conflicts (since it's conceptually "outside" the declaration scope).
594 if (is_function_scope() && decl == function()) continue;
595 if (IsLexicalVariableMode(decl->mode()) && !is_block_scope()) continue;
596 const AstRawString* name = decl->proxy()->raw_name();
597
598 // Iterate through all scopes until and including the declaration scope.
599 Scope* previous = NULL;
600 Scope* current = decl->scope();
601 // Lexical vs lexical conflicts within the same scope have already been
602 // captured in Parser::Declare. The only conflicts we still need to check
603 // are lexical vs VAR, or any declarations within a declaration block scope
604 // vs lexical declarations in its surrounding (function) scope.
605 if (IsLexicalVariableMode(decl->mode())) current = current->outer_scope_;
606 do {
607 // There is a conflict if there exists a non-VAR binding.
608 Variable* other_var = current->variables_.Lookup(name);
609 if (other_var != NULL && IsLexicalVariableMode(other_var->mode())) {
610 return decl;
611 }
612 previous = current;
613 current = current->outer_scope_;
614 } while (!previous->is_declaration_scope());
615 }
616 return NULL;
617}
618
619
620class VarAndOrder {
621 public:
622 VarAndOrder(Variable* var, int order) : var_(var), order_(order) { }
623 Variable* var() const { return var_; }
624 int order() const { return order_; }
625 static int Compare(const VarAndOrder* a, const VarAndOrder* b) {
626 return a->order_ - b->order_;
627 }
628
629 private:
630 Variable* var_;
631 int order_;
632};
633
Ben Murdoch097c5b22016-05-18 11:27:45 +0100634void Scope::CollectStackAndContextLocals(ZoneList<Variable*>* stack_locals,
635 ZoneList<Variable*>* context_locals,
636 ZoneList<Variable*>* context_globals) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000637 DCHECK(stack_locals != NULL);
638 DCHECK(context_locals != NULL);
639 DCHECK(context_globals != NULL);
640
641 // Collect temporaries which are always allocated on the stack, unless the
642 // context as a whole has forced context allocation.
643 for (int i = 0; i < temps_.length(); i++) {
644 Variable* var = temps_[i];
Ben Murdochc5610432016-08-08 18:44:38 +0100645 if (var == nullptr) continue;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000646 if (var->is_used()) {
647 if (var->IsContextSlot()) {
648 DCHECK(has_forced_context_allocation());
649 context_locals->Add(var, zone());
650 } else if (var->IsStackLocal()) {
651 stack_locals->Add(var, zone());
652 } else {
653 DCHECK(var->IsParameter());
654 }
655 }
656 }
657
658 // Collect declared local variables.
659 ZoneList<VarAndOrder> vars(variables_.occupancy(), zone());
660 for (VariableMap::Entry* p = variables_.Start();
661 p != NULL;
662 p = variables_.Next(p)) {
663 Variable* var = reinterpret_cast<Variable*>(p->value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000664 if (var->is_used()) {
665 vars.Add(VarAndOrder(var, p->order), zone());
666 }
667 }
668 vars.Sort(VarAndOrder::Compare);
669 int var_count = vars.length();
670 for (int i = 0; i < var_count; i++) {
671 Variable* var = vars[i].var();
672 if (var->IsStackLocal()) {
673 stack_locals->Add(var, zone());
674 } else if (var->IsContextSlot()) {
675 context_locals->Add(var, zone());
676 } else if (var->IsGlobalSlot()) {
677 context_globals->Add(var, zone());
678 }
679 }
680}
681
682
683bool Scope::AllocateVariables(ParseInfo* info, AstNodeFactory* factory) {
684 // 1) Propagate scope information.
685 bool outer_scope_calls_sloppy_eval = false;
686 if (outer_scope_ != NULL) {
687 outer_scope_calls_sloppy_eval =
688 outer_scope_->outer_scope_calls_sloppy_eval() |
689 outer_scope_->calls_sloppy_eval();
690 }
691 PropagateScopeInfo(outer_scope_calls_sloppy_eval);
692
693 // 2) Resolve variables.
694 if (!ResolveVariablesRecursively(info, factory)) return false;
695
696 // 3) Allocate variables.
697 AllocateVariablesRecursively(info->isolate());
698
699 return true;
700}
701
702
703bool Scope::HasTrivialContext() const {
704 // A function scope has a trivial context if it always is the global
705 // context. We iteratively scan out the context chain to see if
706 // there is anything that makes this scope non-trivial; otherwise we
707 // return true.
708 for (const Scope* scope = this; scope != NULL; scope = scope->outer_scope_) {
709 if (scope->is_eval_scope()) return false;
710 if (scope->scope_inside_with_) return false;
711 if (scope->ContextLocalCount() > 0) return false;
712 if (scope->ContextGlobalCount() > 0) return false;
713 }
714 return true;
715}
716
717
718bool Scope::HasTrivialOuterContext() const {
719 Scope* outer = outer_scope_;
720 if (outer == NULL) return true;
721 // Note that the outer context may be trivial in general, but the current
722 // scope may be inside a 'with' statement in which case the outer context
723 // for this scope is not trivial.
724 return !scope_inside_with_ && outer->HasTrivialContext();
725}
726
727
728bool Scope::AllowsLazyParsing() const {
729 // If we are inside a block scope, we must parse eagerly to find out how
730 // to allocate variables on the block scope. At this point, declarations may
731 // not have yet been parsed.
732 for (const Scope* scope = this; scope != NULL; scope = scope->outer_scope_) {
733 if (scope->is_block_scope()) return false;
734 }
735 return AllowsLazyCompilation();
736}
737
738
739bool Scope::AllowsLazyCompilation() const { return !force_eager_compilation_; }
740
741
742bool Scope::AllowsLazyCompilationWithoutContext() const {
743 return !force_eager_compilation_ && HasTrivialOuterContext();
744}
745
746
747int Scope::ContextChainLength(Scope* scope) {
748 int n = 0;
749 for (Scope* s = this; s != scope; s = s->outer_scope_) {
750 DCHECK(s != NULL); // scope must be in the scope chain
751 if (s->NeedsContext()) n++;
752 }
753 return n;
754}
755
756
757int Scope::MaxNestedContextChainLength() {
758 int max_context_chain_length = 0;
759 for (int i = 0; i < inner_scopes_.length(); i++) {
760 Scope* scope = inner_scopes_[i];
761 max_context_chain_length = std::max(scope->MaxNestedContextChainLength(),
762 max_context_chain_length);
763 }
764 if (NeedsContext()) {
765 max_context_chain_length += 1;
766 }
767 return max_context_chain_length;
768}
769
770
771Scope* Scope::DeclarationScope() {
772 Scope* scope = this;
773 while (!scope->is_declaration_scope()) {
774 scope = scope->outer_scope();
775 }
776 return scope;
777}
778
779
780Scope* Scope::ClosureScope() {
781 Scope* scope = this;
782 while (!scope->is_declaration_scope() || scope->is_block_scope()) {
783 scope = scope->outer_scope();
784 }
785 return scope;
786}
787
788
789Scope* Scope::ReceiverScope() {
790 Scope* scope = this;
791 while (!scope->is_script_scope() &&
792 (!scope->is_function_scope() || scope->is_arrow_scope())) {
793 scope = scope->outer_scope();
794 }
795 return scope;
796}
797
798
799
800Handle<ScopeInfo> Scope::GetScopeInfo(Isolate* isolate) {
801 if (scope_info_.is_null()) {
802 scope_info_ = ScopeInfo::Create(isolate, zone(), this);
803 }
804 return scope_info_;
805}
806
Ben Murdochda12d292016-06-02 14:46:10 +0100807Handle<StringSet> Scope::CollectNonLocals(Handle<StringSet> non_locals) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000808 // Collect non-local variables referenced in the scope.
809 // TODO(yangguo): store non-local variables explicitly if we can no longer
810 // rely on unresolved_ to find them.
811 for (int i = 0; i < unresolved_.length(); i++) {
812 VariableProxy* proxy = unresolved_[i];
813 if (proxy->is_resolved() && proxy->var()->IsStackAllocated()) continue;
814 Handle<String> name = proxy->name();
Ben Murdochda12d292016-06-02 14:46:10 +0100815 non_locals = StringSet::Add(non_locals, name);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000816 }
817 for (int i = 0; i < inner_scopes_.length(); i++) {
Ben Murdochda12d292016-06-02 14:46:10 +0100818 non_locals = inner_scopes_[i]->CollectNonLocals(non_locals);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000819 }
Ben Murdochda12d292016-06-02 14:46:10 +0100820 return non_locals;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000821}
822
823
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000824#ifdef DEBUG
825static const char* Header(ScopeType scope_type, FunctionKind function_kind,
826 bool is_declaration_scope) {
827 switch (scope_type) {
828 case EVAL_SCOPE: return "eval";
829 // TODO(adamk): Should we print concise method scopes specially?
830 case FUNCTION_SCOPE:
Ben Murdoch61f157c2016-09-16 13:49:30 +0100831 if (IsGeneratorFunction(function_kind)) return "function*";
832 if (IsAsyncFunction(function_kind)) return "async function";
833 if (IsArrowFunction(function_kind)) return "arrow";
834 return "function";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000835 case MODULE_SCOPE: return "module";
836 case SCRIPT_SCOPE: return "global";
837 case CATCH_SCOPE: return "catch";
838 case BLOCK_SCOPE: return is_declaration_scope ? "varblock" : "block";
839 case WITH_SCOPE: return "with";
840 }
841 UNREACHABLE();
842 return NULL;
843}
844
845
846static void Indent(int n, const char* str) {
847 PrintF("%*s%s", n, "", str);
848}
849
850
851static void PrintName(const AstRawString* name) {
852 PrintF("%.*s", name->length(), name->raw_data());
853}
854
855
856static void PrintLocation(Variable* var) {
857 switch (var->location()) {
858 case VariableLocation::UNALLOCATED:
859 break;
860 case VariableLocation::PARAMETER:
861 PrintF("parameter[%d]", var->index());
862 break;
863 case VariableLocation::LOCAL:
864 PrintF("local[%d]", var->index());
865 break;
866 case VariableLocation::CONTEXT:
867 PrintF("context[%d]", var->index());
868 break;
869 case VariableLocation::GLOBAL:
870 PrintF("global[%d]", var->index());
871 break;
872 case VariableLocation::LOOKUP:
873 PrintF("lookup");
874 break;
875 }
876}
877
878
879static void PrintVar(int indent, Variable* var) {
880 if (var->is_used() || !var->IsUnallocated()) {
881 Indent(indent, Variable::Mode2String(var->mode()));
882 PrintF(" ");
883 if (var->raw_name()->IsEmpty())
884 PrintF(".%p", reinterpret_cast<void*>(var));
885 else
886 PrintName(var->raw_name());
887 PrintF("; // ");
888 PrintLocation(var);
889 bool comma = !var->IsUnallocated();
890 if (var->has_forced_context_allocation()) {
891 if (comma) PrintF(", ");
892 PrintF("forced context allocation");
893 comma = true;
894 }
895 if (var->maybe_assigned() == kMaybeAssigned) {
896 if (comma) PrintF(", ");
897 PrintF("maybe assigned");
898 }
899 PrintF("\n");
900 }
901}
902
903
904static void PrintMap(int indent, VariableMap* map) {
905 for (VariableMap::Entry* p = map->Start(); p != NULL; p = map->Next(p)) {
906 Variable* var = reinterpret_cast<Variable*>(p->value);
907 if (var == NULL) {
908 Indent(indent, "<?>\n");
909 } else {
910 PrintVar(indent, var);
911 }
912 }
913}
914
915
916void Scope::Print(int n) {
917 int n0 = (n > 0 ? n : 0);
918 int n1 = n0 + 2; // indentation
919
920 // Print header.
921 Indent(n0, Header(scope_type_, function_kind_, is_declaration_scope()));
922 if (scope_name_ != nullptr && !scope_name_->IsEmpty()) {
923 PrintF(" ");
924 PrintName(scope_name_);
925 }
926
927 // Print parameters, if any.
928 if (is_function_scope()) {
929 PrintF(" (");
930 for (int i = 0; i < params_.length(); i++) {
931 if (i > 0) PrintF(", ");
932 const AstRawString* name = params_[i]->raw_name();
933 if (name->IsEmpty())
934 PrintF(".%p", reinterpret_cast<void*>(params_[i]));
935 else
936 PrintName(name);
937 }
938 PrintF(")");
939 }
940
941 PrintF(" { // (%d, %d)\n", start_position(), end_position());
942
943 // Function name, if any (named function literals, only).
944 if (function_ != NULL) {
945 Indent(n1, "// (local) function name: ");
946 PrintName(function_->proxy()->raw_name());
947 PrintF("\n");
948 }
949
950 // Scope info.
951 if (HasTrivialOuterContext()) {
952 Indent(n1, "// scope has trivial outer context\n");
953 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100954 if (is_strict(language_mode())) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000955 Indent(n1, "// strict mode scope\n");
956 }
Ben Murdochc5610432016-08-08 18:44:38 +0100957 if (asm_module_) Indent(n1, "// scope is an asm module\n");
958 if (asm_function_) Indent(n1, "// scope is an asm function\n");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000959 if (scope_inside_with_) Indent(n1, "// scope inside 'with'\n");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000960 if (scope_calls_eval_) Indent(n1, "// scope calls 'eval'\n");
961 if (scope_uses_arguments_) Indent(n1, "// scope uses 'arguments'\n");
962 if (scope_uses_super_property_)
963 Indent(n1, "// scope uses 'super' property\n");
964 if (outer_scope_calls_sloppy_eval_) {
965 Indent(n1, "// outer scope calls 'eval' in sloppy context\n");
966 }
967 if (inner_scope_calls_eval_) Indent(n1, "// inner scope calls 'eval'\n");
968 if (num_stack_slots_ > 0) {
969 Indent(n1, "// ");
970 PrintF("%d stack slots\n", num_stack_slots_);
971 }
972 if (num_heap_slots_ > 0) {
973 Indent(n1, "// ");
974 PrintF("%d heap slots (including %d global slots)\n", num_heap_slots_,
975 num_global_slots_);
976 }
977
978 // Print locals.
979 if (function_ != NULL) {
980 Indent(n1, "// function var:\n");
981 PrintVar(n1, function_->proxy()->var());
982 }
983
984 if (temps_.length() > 0) {
Ben Murdochc5610432016-08-08 18:44:38 +0100985 bool printed_header = false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000986 for (int i = 0; i < temps_.length(); i++) {
Ben Murdochc5610432016-08-08 18:44:38 +0100987 if (temps_[i] != nullptr) {
988 if (!printed_header) {
989 printed_header = true;
990 Indent(n1, "// temporary vars:\n");
991 }
992 PrintVar(n1, temps_[i]);
993 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000994 }
995 }
996
997 if (variables_.Start() != NULL) {
998 Indent(n1, "// local vars:\n");
999 PrintMap(n1, &variables_);
1000 }
1001
1002 if (dynamics_ != NULL) {
1003 Indent(n1, "// dynamic vars:\n");
1004 PrintMap(n1, dynamics_->GetMap(DYNAMIC));
1005 PrintMap(n1, dynamics_->GetMap(DYNAMIC_LOCAL));
1006 PrintMap(n1, dynamics_->GetMap(DYNAMIC_GLOBAL));
1007 }
1008
1009 // Print inner scopes (disable by providing negative n).
1010 if (n >= 0) {
1011 for (int i = 0; i < inner_scopes_.length(); i++) {
1012 PrintF("\n");
1013 inner_scopes_[i]->Print(n1);
1014 }
1015 }
1016
1017 Indent(n0, "}\n");
1018}
Ben Murdochc5610432016-08-08 18:44:38 +01001019
1020void Scope::CheckScopePositions() {
1021 // A scope is allowed to have invalid positions if it is hidden and has no
1022 // inner scopes
1023 if (!is_hidden() && inner_scopes_.length() == 0) {
1024 CHECK_NE(RelocInfo::kNoPosition, start_position());
1025 CHECK_NE(RelocInfo::kNoPosition, end_position());
1026 }
1027 for (Scope* scope : inner_scopes_) scope->CheckScopePositions();
1028}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001029#endif // DEBUG
1030
1031
1032Variable* Scope::NonLocal(const AstRawString* name, VariableMode mode) {
1033 if (dynamics_ == NULL) dynamics_ = new (zone()) DynamicScopePart(zone());
1034 VariableMap* map = dynamics_->GetMap(mode);
1035 Variable* var = map->Lookup(name);
1036 if (var == NULL) {
1037 // Declare a new non-local.
1038 InitializationFlag init_flag = (mode == VAR)
1039 ? kCreatedInitialized : kNeedsInitialization;
1040 var = map->Declare(NULL,
1041 name,
1042 mode,
1043 Variable::NORMAL,
1044 init_flag);
1045 // Allocate it by giving it a dynamic lookup.
1046 var->AllocateTo(VariableLocation::LOOKUP, -1);
1047 }
1048 return var;
1049}
1050
1051
1052Variable* Scope::LookupRecursive(VariableProxy* proxy,
1053 BindingKind* binding_kind,
1054 AstNodeFactory* factory) {
1055 DCHECK(binding_kind != NULL);
1056 if (already_resolved() && is_with_scope()) {
1057 // Short-cut: if the scope is deserialized from a scope info, variable
1058 // allocation is already fixed. We can simply return with dynamic lookup.
1059 *binding_kind = DYNAMIC_LOOKUP;
1060 return NULL;
1061 }
1062
1063 // Try to find the variable in this scope.
1064 Variable* var = LookupLocal(proxy->raw_name());
1065
1066 // We found a variable and we are done. (Even if there is an 'eval' in
1067 // this scope which introduces the same variable again, the resulting
1068 // variable remains the same.)
1069 if (var != NULL) {
1070 *binding_kind = BOUND;
1071 return var;
1072 }
1073
1074 // We did not find a variable locally. Check against the function variable,
1075 // if any. We can do this for all scopes, since the function variable is
1076 // only present - if at all - for function scopes.
1077 *binding_kind = UNBOUND;
1078 var = LookupFunctionVar(proxy->raw_name(), factory);
1079 if (var != NULL) {
1080 *binding_kind = BOUND;
1081 } else if (outer_scope_ != NULL) {
1082 var = outer_scope_->LookupRecursive(proxy, binding_kind, factory);
1083 if (*binding_kind == BOUND && (is_function_scope() || is_with_scope())) {
1084 var->ForceContextAllocation();
1085 }
1086 } else {
1087 DCHECK(is_script_scope());
1088 }
1089
1090 // "this" can't be shadowed by "eval"-introduced bindings or by "with" scopes.
1091 // TODO(wingo): There are other variables in this category; add them.
1092 bool name_can_be_shadowed = var == nullptr || !var->is_this();
1093
1094 if (is_with_scope() && name_can_be_shadowed) {
1095 DCHECK(!already_resolved());
1096 // The current scope is a with scope, so the variable binding can not be
1097 // statically resolved. However, note that it was necessary to do a lookup
1098 // in the outer scope anyway, because if a binding exists in an outer scope,
1099 // the associated variable has to be marked as potentially being accessed
1100 // from inside of an inner with scope (the property may not be in the 'with'
1101 // object).
1102 if (var != NULL && proxy->is_assigned()) var->set_maybe_assigned();
1103 *binding_kind = DYNAMIC_LOOKUP;
1104 return NULL;
Ben Murdochc5610432016-08-08 18:44:38 +01001105 } else if (calls_sloppy_eval() && is_declaration_scope() &&
1106 !is_script_scope() && name_can_be_shadowed) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001107 // A variable binding may have been found in an outer scope, but the current
1108 // scope makes a sloppy 'eval' call, so the found variable may not be
1109 // the correct one (the 'eval' may introduce a binding with the same name).
1110 // In that case, change the lookup result to reflect this situation.
Ben Murdochc5610432016-08-08 18:44:38 +01001111 // Only scopes that can host var bindings (declaration scopes) need be
1112 // considered here (this excludes block and catch scopes), and variable
1113 // lookups at script scope are always dynamic.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001114 if (*binding_kind == BOUND) {
1115 *binding_kind = BOUND_EVAL_SHADOWED;
1116 } else if (*binding_kind == UNBOUND) {
1117 *binding_kind = UNBOUND_EVAL_SHADOWED;
1118 }
1119 }
1120 return var;
1121}
1122
1123
1124bool Scope::ResolveVariable(ParseInfo* info, VariableProxy* proxy,
1125 AstNodeFactory* factory) {
1126 DCHECK(info->script_scope()->is_script_scope());
1127
1128 // If the proxy is already resolved there's nothing to do
1129 // (functions and consts may be resolved by the parser).
1130 if (proxy->is_resolved()) return true;
1131
1132 // Otherwise, try to resolve the variable.
1133 BindingKind binding_kind;
1134 Variable* var = LookupRecursive(proxy, &binding_kind, factory);
1135
1136#ifdef DEBUG
1137 if (info->script_is_native()) {
1138 // To avoid polluting the global object in native scripts
1139 // - Variables must not be allocated to the global scope.
1140 CHECK_NOT_NULL(outer_scope());
1141 // - Variables must be bound locally or unallocated.
1142 if (BOUND != binding_kind) {
1143 // The following variable name may be minified. If so, disable
1144 // minification in js2c.py for better output.
1145 Handle<String> name = proxy->raw_name()->string();
1146 V8_Fatal(__FILE__, __LINE__, "Unbound variable: '%s' in native script.",
1147 name->ToCString().get());
1148 }
1149 VariableLocation location = var->location();
1150 CHECK(location == VariableLocation::LOCAL ||
1151 location == VariableLocation::CONTEXT ||
1152 location == VariableLocation::PARAMETER ||
1153 location == VariableLocation::UNALLOCATED);
1154 }
1155#endif
1156
1157 switch (binding_kind) {
1158 case BOUND:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001159 break;
1160
1161 case BOUND_EVAL_SHADOWED:
1162 // We either found a variable binding that might be shadowed by eval or
1163 // gave up on it (e.g. by encountering a local with the same in the outer
1164 // scope which was not promoted to a context, this can happen if we use
1165 // debugger to evaluate arbitrary expressions at a break point).
1166 if (var->IsGlobalObjectProperty()) {
1167 var = NonLocal(proxy->raw_name(), DYNAMIC_GLOBAL);
1168 } else if (var->is_dynamic()) {
1169 var = NonLocal(proxy->raw_name(), DYNAMIC);
1170 } else {
1171 Variable* invalidated = var;
1172 var = NonLocal(proxy->raw_name(), DYNAMIC_LOCAL);
1173 var->set_local_if_not_shadowed(invalidated);
1174 }
1175 break;
1176
1177 case UNBOUND:
1178 // No binding has been found. Declare a variable on the global object.
1179 var = info->script_scope()->DeclareDynamicGlobal(proxy->raw_name());
1180 break;
1181
1182 case UNBOUND_EVAL_SHADOWED:
1183 // No binding has been found. But some scope makes a sloppy 'eval' call.
1184 var = NonLocal(proxy->raw_name(), DYNAMIC_GLOBAL);
1185 break;
1186
1187 case DYNAMIC_LOOKUP:
1188 // The variable could not be resolved statically.
1189 var = NonLocal(proxy->raw_name(), DYNAMIC);
1190 break;
1191 }
1192
1193 DCHECK(var != NULL);
1194 if (proxy->is_assigned()) var->set_maybe_assigned();
1195
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001196 proxy->BindTo(var);
1197
1198 return true;
1199}
1200
1201
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001202bool Scope::ResolveVariablesRecursively(ParseInfo* info,
1203 AstNodeFactory* factory) {
1204 DCHECK(info->script_scope()->is_script_scope());
1205
1206 // Resolve unresolved variables for this scope.
1207 for (int i = 0; i < unresolved_.length(); i++) {
1208 if (!ResolveVariable(info, unresolved_[i], factory)) return false;
1209 }
1210
1211 // Resolve unresolved variables for inner scopes.
1212 for (int i = 0; i < inner_scopes_.length(); i++) {
1213 if (!inner_scopes_[i]->ResolveVariablesRecursively(info, factory))
1214 return false;
1215 }
1216
1217 return true;
1218}
1219
1220
1221void Scope::PropagateScopeInfo(bool outer_scope_calls_sloppy_eval ) {
1222 if (outer_scope_calls_sloppy_eval) {
1223 outer_scope_calls_sloppy_eval_ = true;
1224 }
1225
1226 bool calls_sloppy_eval =
1227 this->calls_sloppy_eval() || outer_scope_calls_sloppy_eval_;
1228 for (int i = 0; i < inner_scopes_.length(); i++) {
1229 Scope* inner = inner_scopes_[i];
1230 inner->PropagateScopeInfo(calls_sloppy_eval);
1231 if (inner->scope_calls_eval_ || inner->inner_scope_calls_eval_) {
1232 inner_scope_calls_eval_ = true;
1233 }
1234 if (inner->force_eager_compilation_) {
1235 force_eager_compilation_ = true;
1236 }
1237 if (asm_module_ && inner->scope_type() == FUNCTION_SCOPE) {
1238 inner->asm_function_ = true;
1239 }
1240 }
1241}
1242
1243
1244bool Scope::MustAllocate(Variable* var) {
1245 // Give var a read/write use if there is a chance it might be accessed
1246 // via an eval() call. This is only possible if the variable has a
1247 // visible name.
1248 if ((var->is_this() || !var->raw_name()->IsEmpty()) &&
1249 (var->has_forced_context_allocation() || scope_calls_eval_ ||
Ben Murdochda12d292016-06-02 14:46:10 +01001250 inner_scope_calls_eval_ || is_catch_scope() || is_block_scope() ||
1251 is_module_scope() || is_script_scope())) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001252 var->set_is_used();
1253 if (scope_calls_eval_ || inner_scope_calls_eval_) var->set_maybe_assigned();
1254 }
1255 // Global variables do not need to be allocated.
1256 return !var->IsGlobalObjectProperty() && var->is_used();
1257}
1258
1259
1260bool Scope::MustAllocateInContext(Variable* var) {
1261 // If var is accessed from an inner scope, or if there is a possibility
1262 // that it might be accessed from the current or an inner scope (through
1263 // an eval() call or a runtime with lookup), it must be allocated in the
1264 // context.
1265 //
1266 // Exceptions: If the scope as a whole has forced context allocation, all
1267 // variables will have context allocation, even temporaries. Otherwise
1268 // temporary variables are always stack-allocated. Catch-bound variables are
1269 // always context-allocated.
1270 if (has_forced_context_allocation()) return true;
1271 if (var->mode() == TEMPORARY) return false;
1272 if (is_catch_scope() || is_module_scope()) return true;
1273 if (is_script_scope() && IsLexicalVariableMode(var->mode())) return true;
Ben Murdochda12d292016-06-02 14:46:10 +01001274 return var->has_forced_context_allocation() || scope_calls_eval_ ||
1275 inner_scope_calls_eval_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001276}
1277
1278
1279bool Scope::HasArgumentsParameter(Isolate* isolate) {
1280 for (int i = 0; i < params_.length(); i++) {
1281 if (params_[i]->name().is_identical_to(
1282 isolate->factory()->arguments_string())) {
1283 return true;
1284 }
1285 }
1286 return false;
1287}
1288
1289
1290void Scope::AllocateStackSlot(Variable* var) {
1291 if (is_block_scope()) {
1292 outer_scope()->DeclarationScope()->AllocateStackSlot(var);
1293 } else {
1294 var->AllocateTo(VariableLocation::LOCAL, num_stack_slots_++);
1295 }
1296}
1297
1298
1299void Scope::AllocateHeapSlot(Variable* var) {
1300 var->AllocateTo(VariableLocation::CONTEXT, num_heap_slots_++);
1301}
1302
1303
1304void Scope::AllocateParameterLocals(Isolate* isolate) {
1305 DCHECK(is_function_scope());
1306 Variable* arguments = LookupLocal(ast_value_factory_->arguments_string());
1307 // Functions have 'arguments' declared implicitly in all non arrow functions.
1308 DCHECK(arguments != nullptr || is_arrow_scope());
1309
1310 bool uses_sloppy_arguments = false;
1311
1312 if (arguments != nullptr && MustAllocate(arguments) &&
1313 !HasArgumentsParameter(isolate)) {
1314 // 'arguments' is used. Unless there is also a parameter called
1315 // 'arguments', we must be conservative and allocate all parameters to
1316 // the context assuming they will be captured by the arguments object.
1317 // If we have a parameter named 'arguments', a (new) value is always
1318 // assigned to it via the function invocation. Then 'arguments' denotes
1319 // that specific parameter value and cannot be used to access the
1320 // parameters, which is why we don't need to allocate an arguments
1321 // object in that case.
1322
1323 // We are using 'arguments'. Tell the code generator that is needs to
1324 // allocate the arguments object by setting 'arguments_'.
1325 arguments_ = arguments;
1326
1327 // In strict mode 'arguments' does not alias formal parameters.
1328 // Therefore in strict mode we allocate parameters as if 'arguments'
1329 // were not used.
1330 // If the parameter list is not simple, arguments isn't sloppy either.
1331 uses_sloppy_arguments =
1332 is_sloppy(language_mode()) && has_simple_parameters();
1333 }
1334
1335 if (rest_parameter_ && !MustAllocate(rest_parameter_)) {
1336 rest_parameter_ = NULL;
1337 }
1338
1339 // The same parameter may occur multiple times in the parameters_ list.
1340 // If it does, and if it is not copied into the context object, it must
1341 // receive the highest parameter index for that parameter; thus iteration
1342 // order is relevant!
1343 for (int i = params_.length() - 1; i >= 0; --i) {
1344 Variable* var = params_[i];
1345 if (var == rest_parameter_) continue;
1346
1347 DCHECK(var->scope() == this);
1348 if (uses_sloppy_arguments || has_forced_context_allocation()) {
1349 // Force context allocation of the parameter.
1350 var->ForceContextAllocation();
1351 }
1352 AllocateParameter(var, i);
1353 }
1354}
1355
1356
1357void Scope::AllocateParameter(Variable* var, int index) {
1358 if (MustAllocate(var)) {
1359 if (MustAllocateInContext(var)) {
1360 DCHECK(var->IsUnallocated() || var->IsContextSlot());
1361 if (var->IsUnallocated()) {
1362 AllocateHeapSlot(var);
1363 }
1364 } else {
1365 DCHECK(var->IsUnallocated() || var->IsParameter());
1366 if (var->IsUnallocated()) {
1367 var->AllocateTo(VariableLocation::PARAMETER, index);
1368 }
1369 }
1370 } else {
1371 DCHECK(!var->IsGlobalSlot());
1372 }
1373}
1374
1375
1376void Scope::AllocateReceiver() {
1377 DCHECK_NOT_NULL(receiver());
1378 DCHECK_EQ(receiver()->scope(), this);
1379
1380 if (has_forced_context_allocation()) {
1381 // Force context allocation of the receiver.
1382 receiver()->ForceContextAllocation();
1383 }
1384 AllocateParameter(receiver(), -1);
1385}
1386
1387
1388void Scope::AllocateNonParameterLocal(Isolate* isolate, Variable* var) {
1389 DCHECK(var->scope() == this);
1390 DCHECK(!var->IsVariable(isolate->factory()->dot_result_string()) ||
1391 !var->IsStackLocal());
1392 if (var->IsUnallocated() && MustAllocate(var)) {
1393 if (MustAllocateInContext(var)) {
1394 AllocateHeapSlot(var);
1395 } else {
1396 AllocateStackSlot(var);
1397 }
1398 }
1399}
1400
1401
1402void Scope::AllocateDeclaredGlobal(Isolate* isolate, Variable* var) {
1403 DCHECK(var->scope() == this);
1404 DCHECK(!var->IsVariable(isolate->factory()->dot_result_string()) ||
1405 !var->IsStackLocal());
1406 if (var->IsUnallocated()) {
1407 if (var->IsStaticGlobalObjectProperty()) {
1408 DCHECK_EQ(-1, var->index());
1409 DCHECK(var->name()->IsString());
1410 var->AllocateTo(VariableLocation::GLOBAL, num_heap_slots_++);
1411 num_global_slots_++;
1412 } else {
1413 // There must be only DYNAMIC_GLOBAL in the script scope.
1414 DCHECK(!is_script_scope() || DYNAMIC_GLOBAL == var->mode());
1415 }
1416 }
1417}
1418
1419
1420void Scope::AllocateNonParameterLocalsAndDeclaredGlobals(Isolate* isolate) {
1421 // All variables that have no rewrite yet are non-parameter locals.
1422 for (int i = 0; i < temps_.length(); i++) {
Ben Murdochc5610432016-08-08 18:44:38 +01001423 if (temps_[i] == nullptr) continue;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001424 AllocateNonParameterLocal(isolate, temps_[i]);
1425 }
1426
1427 ZoneList<VarAndOrder> vars(variables_.occupancy(), zone());
1428 for (VariableMap::Entry* p = variables_.Start();
1429 p != NULL;
1430 p = variables_.Next(p)) {
1431 Variable* var = reinterpret_cast<Variable*>(p->value);
1432 vars.Add(VarAndOrder(var, p->order), zone());
1433 }
1434 vars.Sort(VarAndOrder::Compare);
1435 int var_count = vars.length();
1436 for (int i = 0; i < var_count; i++) {
1437 AllocateNonParameterLocal(isolate, vars[i].var());
1438 }
1439
1440 if (FLAG_global_var_shortcuts) {
1441 for (int i = 0; i < var_count; i++) {
1442 AllocateDeclaredGlobal(isolate, vars[i].var());
1443 }
1444 }
1445
1446 // For now, function_ must be allocated at the very end. If it gets
1447 // allocated in the context, it must be the last slot in the context,
1448 // because of the current ScopeInfo implementation (see
1449 // ScopeInfo::ScopeInfo(FunctionScope* scope) constructor).
1450 if (function_ != nullptr) {
1451 AllocateNonParameterLocal(isolate, function_->proxy()->var());
1452 }
1453
1454 if (rest_parameter_ != nullptr) {
1455 AllocateNonParameterLocal(isolate, rest_parameter_);
1456 }
1457
1458 Variable* new_target_var =
1459 LookupLocal(ast_value_factory_->new_target_string());
1460 if (new_target_var != nullptr && MustAllocate(new_target_var)) {
1461 new_target_ = new_target_var;
1462 }
1463
1464 Variable* this_function_var =
1465 LookupLocal(ast_value_factory_->this_function_string());
1466 if (this_function_var != nullptr && MustAllocate(this_function_var)) {
1467 this_function_ = this_function_var;
1468 }
1469}
1470
1471
1472void Scope::AllocateVariablesRecursively(Isolate* isolate) {
1473 if (!already_resolved()) {
1474 num_stack_slots_ = 0;
1475 }
1476 // Allocate variables for inner scopes.
1477 for (int i = 0; i < inner_scopes_.length(); i++) {
1478 inner_scopes_[i]->AllocateVariablesRecursively(isolate);
1479 }
1480
1481 // If scope is already resolved, we still need to allocate
Ben Murdoch097c5b22016-05-18 11:27:45 +01001482 // variables in inner scopes which might not have been resolved yet.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001483 if (already_resolved()) return;
1484 // The number of slots required for variables.
1485 num_heap_slots_ = Context::MIN_CONTEXT_SLOTS;
1486
1487 // Allocate variables for this scope.
1488 // Parameters must be allocated first, if any.
1489 if (is_function_scope()) AllocateParameterLocals(isolate);
1490 if (has_this_declaration()) AllocateReceiver();
1491 AllocateNonParameterLocalsAndDeclaredGlobals(isolate);
1492
1493 // Force allocation of a context for this scope if necessary. For a 'with'
1494 // scope and for a function scope that makes an 'eval' call we need a context,
1495 // even if no local variables were statically allocated in the scope.
1496 // Likewise for modules.
1497 bool must_have_context =
1498 is_with_scope() || is_module_scope() ||
1499 (is_function_scope() && calls_sloppy_eval()) ||
1500 (is_block_scope() && is_declaration_scope() && calls_sloppy_eval());
1501
1502 // If we didn't allocate any locals in the local context, then we only
1503 // need the minimal number of slots if we must have a context.
1504 if (num_heap_slots_ == Context::MIN_CONTEXT_SLOTS && !must_have_context) {
1505 num_heap_slots_ = 0;
1506 }
1507
1508 // Allocation done.
1509 DCHECK(num_heap_slots_ == 0 || num_heap_slots_ >= Context::MIN_CONTEXT_SLOTS);
1510}
1511
1512
1513int Scope::StackLocalCount() const {
1514 return num_stack_slots() -
1515 (function_ != NULL && function_->proxy()->var()->IsStackLocal() ? 1 : 0);
1516}
1517
1518
1519int Scope::ContextLocalCount() const {
1520 if (num_heap_slots() == 0) return 0;
1521 bool is_function_var_in_context =
1522 function_ != NULL && function_->proxy()->var()->IsContextSlot();
1523 return num_heap_slots() - Context::MIN_CONTEXT_SLOTS - num_global_slots() -
1524 (is_function_var_in_context ? 1 : 0);
1525}
1526
1527
1528int Scope::ContextGlobalCount() const { return num_global_slots(); }
1529
1530} // namespace internal
1531} // namespace v8