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 <set>
8
9#include "src/accessors.h"
10#include "src/ast/ast.h"
11#include "src/base/optional.h"
12#include "src/bootstrapper.h"
13#include "src/counters.h"
14#include "src/message-template.h"
15#include "src/objects-inl.h"
16#include "src/objects/module-inl.h"
17#include "src/objects/scope-info.h"
18#include "src/parsing/parse-info.h"
19#include "src/parsing/parser.h"
20#include "src/parsing/preparse-data.h"
21#include "src/zone/zone-list-inl.h"
22
23namespace v8 {
24namespace internal {
25
26// ----------------------------------------------------------------------------
27// Implementation of LocalsMap
28//
29// Note: We are storing the handle locations as key values in the hash map.
30// When inserting a new variable via Declare(), we rely on the fact that
31// the handle location remains alive for the duration of that variable
32// use. Because a Variable holding a handle with the same location exists
33// this is ensured.
34
35VariableMap::VariableMap(Zone* zone)
36 : ZoneHashMap(8, ZoneAllocationPolicy(zone)) {}
37
38Variable* VariableMap::Declare(Zone* zone, Scope* scope,
39 const AstRawString* name, VariableMode mode,
40 VariableKind kind,
41 InitializationFlag initialization_flag,
42 MaybeAssignedFlag maybe_assigned_flag,
43 bool* was_added) {
44 // AstRawStrings are unambiguous, i.e., the same string is always represented
45 // by the same AstRawString*.
46 // FIXME(marja): fix the type of Lookup.
47 Entry* p =
48 ZoneHashMap::LookupOrInsert(const_cast<AstRawString*>(name), name->Hash(),
49 ZoneAllocationPolicy(zone));
50 *was_added = p->value == nullptr;
51 if (*was_added) {
52 // The variable has not been declared yet -> insert it.
53 DCHECK_EQ(name, p->key);
54 Variable* variable = new (zone) Variable(
55 scope, name, mode, kind, initialization_flag, maybe_assigned_flag);
56 p->value = variable;
57 }
58 return reinterpret_cast<Variable*>(p->value);
59}
60
61void VariableMap::Remove(Variable* var) {
62 const AstRawString* name = var->raw_name();
63 ZoneHashMap::Remove(const_cast<AstRawString*>(name), name->Hash());
64}
65
66void VariableMap::Add(Zone* zone, Variable* var) {
67 const AstRawString* name = var->raw_name();
68 Entry* p =
69 ZoneHashMap::LookupOrInsert(const_cast<AstRawString*>(name), name->Hash(),
70 ZoneAllocationPolicy(zone));
71 DCHECK_NULL(p->value);
72 DCHECK_EQ(name, p->key);
73 p->value = var;
74}
75
76Variable* VariableMap::Lookup(const AstRawString* name) {
77 Entry* p = ZoneHashMap::Lookup(const_cast<AstRawString*>(name), name->Hash());
78 if (p != nullptr) {
79 DCHECK(reinterpret_cast<const AstRawString*>(p->key) == name);
80 DCHECK_NOT_NULL(p->value);
81 return reinterpret_cast<Variable*>(p->value);
82 }
83 return nullptr;
84}
85
86// ----------------------------------------------------------------------------
87// Implementation of Scope
88
89Scope::Scope(Zone* zone)
90 : zone_(zone),
91 outer_scope_(nullptr),
92 variables_(zone),
93 scope_type_(SCRIPT_SCOPE) {
94 SetDefaults();
95}
96
97Scope::Scope(Zone* zone, Scope* outer_scope, ScopeType scope_type)
98 : zone_(zone),
99 outer_scope_(outer_scope),
100 variables_(zone),
101 scope_type_(scope_type) {
102 DCHECK_NE(SCRIPT_SCOPE, scope_type);
103 SetDefaults();
104 set_language_mode(outer_scope->language_mode());
105 outer_scope_->AddInnerScope(this);
106}
107
108DeclarationScope::DeclarationScope(Zone* zone,
109 AstValueFactory* ast_value_factory)
110 : Scope(zone), function_kind_(kNormalFunction), params_(4, zone) {
111 DCHECK_EQ(scope_type_, SCRIPT_SCOPE);
112 SetDefaults();
113 receiver_ = DeclareDynamicGlobal(ast_value_factory->this_string(),
114 THIS_VARIABLE, this);
115}
116
117DeclarationScope::DeclarationScope(Zone* zone, Scope* outer_scope,
118 ScopeType scope_type,
119 FunctionKind function_kind)
120 : Scope(zone, outer_scope, scope_type),
121 function_kind_(function_kind),
122 params_(4, zone) {
123 DCHECK_NE(scope_type, SCRIPT_SCOPE);
124 SetDefaults();
125}
126
127ModuleScope::ModuleScope(DeclarationScope* script_scope,
128 AstValueFactory* avfactory)
129 : DeclarationScope(avfactory->zone(), script_scope, MODULE_SCOPE, kModule),
130 module_descriptor_(new (avfactory->zone())
131 ModuleDescriptor(avfactory->zone())) {
132 set_language_mode(LanguageMode::kStrict);
133 DeclareThis(avfactory);
134}
135
136ModuleScope::ModuleScope(Isolate* isolate, Handle<ScopeInfo> scope_info,
137 AstValueFactory* avfactory)
138 : DeclarationScope(avfactory->zone(), MODULE_SCOPE, scope_info),
139 module_descriptor_(nullptr) {
140 set_language_mode(LanguageMode::kStrict);
141}
142
143ClassScope::ClassScope(Zone* zone, Scope* outer_scope)
144 : Scope(zone, outer_scope, CLASS_SCOPE) {
145 set_language_mode(LanguageMode::kStrict);
146}
147
148ClassScope::ClassScope(Zone* zone, Handle<ScopeInfo> scope_info)
149 : Scope(zone, CLASS_SCOPE, scope_info) {
150 set_language_mode(LanguageMode::kStrict);
151}
152
153Scope::Scope(Zone* zone, ScopeType scope_type, Handle<ScopeInfo> scope_info)
154 : zone_(zone),
155 outer_scope_(nullptr),
156 variables_(zone),
157 scope_info_(scope_info),
158 scope_type_(scope_type) {
159 DCHECK(!scope_info.is_null());
160 SetDefaults();
161#ifdef DEBUG
162 already_resolved_ = true;
163#endif
164 if (scope_info->CallsSloppyEval()) scope_calls_eval_ = true;
165 set_language_mode(scope_info->language_mode());
166 num_heap_slots_ = scope_info->ContextLength();
167 DCHECK_LE(Context::MIN_CONTEXT_SLOTS, num_heap_slots_);
168 // We don't really need to use the preparsed scope data; this is just to
169 // shorten the recursion in SetMustUsePreparseData.
170 must_use_preparsed_scope_data_ = true;
171}
172
173DeclarationScope::DeclarationScope(Zone* zone, ScopeType scope_type,
174 Handle<ScopeInfo> scope_info)
175 : Scope(zone, scope_type, scope_info),
176 function_kind_(scope_info->function_kind()),
177 params_(0, zone) {
178 DCHECK_NE(scope_type, SCRIPT_SCOPE);
179 SetDefaults();
180}
181
182Scope::Scope(Zone* zone, const AstRawString* catch_variable_name,
183 MaybeAssignedFlag maybe_assigned, Handle<ScopeInfo> scope_info)
184 : zone_(zone),
185 outer_scope_(nullptr),
186 variables_(zone),
187 scope_info_(scope_info),
188 scope_type_(CATCH_SCOPE) {
189 SetDefaults();
190#ifdef DEBUG
191 already_resolved_ = true;
192#endif
193 // Cache the catch variable, even though it's also available via the
194 // scope_info, as the parser expects that a catch scope always has the catch
195 // variable as first and only variable.
196 bool was_added;
197 Variable* variable =
198 Declare(zone, catch_variable_name, VariableMode::kVar, NORMAL_VARIABLE,
199 kCreatedInitialized, maybe_assigned, &was_added);
200 DCHECK(was_added);
201 AllocateHeapSlot(variable);
202}
203
204void DeclarationScope::SetDefaults() {
205 is_declaration_scope_ = true;
206 has_simple_parameters_ = true;
207 is_asm_module_ = false;
208 force_eager_compilation_ = false;
209 has_arguments_parameter_ = false;
210 scope_uses_super_property_ = false;
211 has_checked_syntax_ = false;
212 has_this_reference_ = false;
213 has_this_declaration_ =
214 (is_function_scope() && !is_arrow_scope()) || is_module_scope();
215 has_rest_ = false;
216 receiver_ = nullptr;
217 new_target_ = nullptr;
218 function_ = nullptr;
219 arguments_ = nullptr;
220 rare_data_ = nullptr;
221 should_eager_compile_ = false;
222 was_lazily_parsed_ = false;
223 is_skipped_function_ = false;
224 preparse_data_builder_ = nullptr;
225#ifdef DEBUG
226 DeclarationScope* outer_declaration_scope =
227 outer_scope_ ? outer_scope_->GetDeclarationScope() : nullptr;
228 is_being_lazily_parsed_ =
229 outer_declaration_scope ? outer_declaration_scope->is_being_lazily_parsed_
230 : false;
231#endif
232}
233
234void Scope::SetDefaults() {
235#ifdef DEBUG
236 scope_name_ = nullptr;
237 already_resolved_ = false;
238 needs_migration_ = false;
239#endif
240 inner_scope_ = nullptr;
241 sibling_ = nullptr;
242 unresolved_list_.Clear();
243
244 start_position_ = kNoSourcePosition;
245 end_position_ = kNoSourcePosition;
246
247 num_stack_slots_ = 0;
248 num_heap_slots_ = Context::MIN_CONTEXT_SLOTS;
249
250 set_language_mode(LanguageMode::kSloppy);
251
252 scope_calls_eval_ = false;
253 scope_nonlinear_ = false;
254 is_hidden_ = false;
255 is_debug_evaluate_scope_ = false;
256
257 inner_scope_calls_eval_ = false;
258 force_context_allocation_ = false;
259 force_context_allocation_for_parameters_ = false;
260
261 is_declaration_scope_ = false;
262
263 must_use_preparsed_scope_data_ = false;
264}
265
266bool Scope::HasSimpleParameters() {
267 DeclarationScope* scope = GetClosureScope();
268 return !scope->is_function_scope() || scope->has_simple_parameters();
269}
270
271void DeclarationScope::set_should_eager_compile() {
272 should_eager_compile_ = !was_lazily_parsed_;
273}
274
275void DeclarationScope::set_is_asm_module() { is_asm_module_ = true; }
276
277bool Scope::IsAsmModule() const {
278 return is_function_scope() && AsDeclarationScope()->is_asm_module();
279}
280
281bool Scope::ContainsAsmModule() const {
282 if (IsAsmModule()) return true;
283
284 // Check inner scopes recursively
285 for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) {
286 // Don't check inner functions which won't be eagerly compiled.
287 if (!scope->is_function_scope() ||
288 scope->AsDeclarationScope()->ShouldEagerCompile()) {
289 if (scope->ContainsAsmModule()) return true;
290 }
291 }
292
293 return false;
294}
295
296Scope* Scope::DeserializeScopeChain(Isolate* isolate, Zone* zone,
297 ScopeInfo scope_info,
298 DeclarationScope* script_scope,
299 AstValueFactory* ast_value_factory,
300 DeserializationMode deserialization_mode) {
301 // Reconstruct the outer scope chain from a closure's context chain.
302 Scope* current_scope = nullptr;
303 Scope* innermost_scope = nullptr;
304 Scope* outer_scope = nullptr;
305 while (!scope_info.is_null()) {
306 if (scope_info->scope_type() == WITH_SCOPE) {
307 if (scope_info->IsDebugEvaluateScope()) {
308 outer_scope = new (zone)
309 DeclarationScope(zone, FUNCTION_SCOPE, handle(scope_info, isolate));
310 outer_scope->set_is_debug_evaluate_scope();
311 } else {
312 // For scope analysis, debug-evaluate is equivalent to a with scope.
313 outer_scope =
314 new (zone) Scope(zone, WITH_SCOPE, handle(scope_info, isolate));
315 }
316
317 } else if (scope_info->scope_type() == SCRIPT_SCOPE) {
318 // If we reach a script scope, it's the outermost scope. Install the
319 // scope info of this script context onto the existing script scope to
320 // avoid nesting script scopes.
321 if (deserialization_mode == DeserializationMode::kIncludingVariables) {
322 script_scope->SetScriptScopeInfo(handle(scope_info, isolate));
323 }
324 DCHECK(!scope_info->HasOuterScopeInfo());
325 break;
326 } else if (scope_info->scope_type() == FUNCTION_SCOPE) {
327 outer_scope = new (zone)
328 DeclarationScope(zone, FUNCTION_SCOPE, handle(scope_info, isolate));
329 if (scope_info->IsAsmModule()) {
330 outer_scope->AsDeclarationScope()->set_is_asm_module();
331 }
332 } else if (scope_info->scope_type() == EVAL_SCOPE) {
333 outer_scope = new (zone)
334 DeclarationScope(zone, EVAL_SCOPE, handle(scope_info, isolate));
335 } else if (scope_info->scope_type() == CLASS_SCOPE) {
336 outer_scope = new (zone) ClassScope(zone, handle(scope_info, isolate));
337 } else if (scope_info->scope_type() == BLOCK_SCOPE) {
338 if (scope_info->is_declaration_scope()) {
339 outer_scope = new (zone)
340 DeclarationScope(zone, BLOCK_SCOPE, handle(scope_info, isolate));
341 } else {
342 outer_scope =
343 new (zone) Scope(zone, BLOCK_SCOPE, handle(scope_info, isolate));
344 }
345 } else if (scope_info->scope_type() == MODULE_SCOPE) {
346 outer_scope = new (zone)
347 ModuleScope(isolate, handle(scope_info, isolate), ast_value_factory);
348 } else {
349 DCHECK_EQ(scope_info->scope_type(), CATCH_SCOPE);
350 DCHECK_EQ(scope_info->ContextLocalCount(), 1);
351 DCHECK_EQ(scope_info->ContextLocalMode(0), VariableMode::kVar);
352 DCHECK_EQ(scope_info->ContextLocalInitFlag(0), kCreatedInitialized);
353 String name = scope_info->ContextLocalName(0);
354 MaybeAssignedFlag maybe_assigned =
355 scope_info->ContextLocalMaybeAssignedFlag(0);
356 outer_scope = new (zone)
357 Scope(zone, ast_value_factory->GetString(handle(name, isolate)),
358 maybe_assigned, handle(scope_info, isolate));
359 }
360 if (deserialization_mode == DeserializationMode::kScopesOnly) {
361 outer_scope->scope_info_ = Handle<ScopeInfo>::null();
362 }
363 if (current_scope != nullptr) {
364 outer_scope->AddInnerScope(current_scope);
365 }
366 current_scope = outer_scope;
367 if (innermost_scope == nullptr) innermost_scope = current_scope;
368 scope_info = scope_info->HasOuterScopeInfo() ? scope_info->OuterScopeInfo()
369 : ScopeInfo();
370 }
371
372 if (deserialization_mode == DeserializationMode::kIncludingVariables &&
373 script_scope->scope_info_.is_null()) {
374 Handle<ScriptContextTable> table(
375 isolate->native_context()->script_context_table(), isolate);
376 Handle<Context> first = ScriptContextTable::GetContext(isolate, table, 0);
377 Handle<ScopeInfo> scope_info(first->scope_info(), isolate);
378 script_scope->SetScriptScopeInfo(scope_info);
379 }
380
381 if (innermost_scope == nullptr) return script_scope;
382 script_scope->AddInnerScope(current_scope);
383 return innermost_scope;
384}
385
386DeclarationScope* Scope::AsDeclarationScope() {
387 DCHECK(is_declaration_scope());
388 return static_cast<DeclarationScope*>(this);
389}
390
391const DeclarationScope* Scope::AsDeclarationScope() const {
392 DCHECK(is_declaration_scope());
393 return static_cast<const DeclarationScope*>(this);
394}
395
396ModuleScope* Scope::AsModuleScope() {
397 DCHECK(is_module_scope());
398 return static_cast<ModuleScope*>(this);
399}
400
401const ModuleScope* Scope::AsModuleScope() const {
402 DCHECK(is_module_scope());
403 return static_cast<const ModuleScope*>(this);
404}
405
406ClassScope* Scope::AsClassScope() {
407 DCHECK(is_class_scope());
408 return static_cast<ClassScope*>(this);
409}
410
411const ClassScope* Scope::AsClassScope() const {
412 DCHECK(is_class_scope());
413 return static_cast<const ClassScope*>(this);
414}
415
416void DeclarationScope::DeclareSloppyBlockFunction(
417 SloppyBlockFunctionStatement* sloppy_block_function) {
418 sloppy_block_functions_.Add(sloppy_block_function);
419}
420
421void DeclarationScope::HoistSloppyBlockFunctions(AstNodeFactory* factory) {
422 DCHECK(is_sloppy(language_mode()));
423 DCHECK(is_function_scope() || is_eval_scope() || is_script_scope() ||
424 (is_block_scope() && outer_scope()->is_function_scope()));
425 DCHECK(HasSimpleParameters() || is_block_scope() || is_being_lazily_parsed_);
426 DCHECK_EQ(factory == nullptr, is_being_lazily_parsed_);
427
428 if (sloppy_block_functions_.is_empty()) return;
429
430 // In case of complex parameters the current scope is the body scope and the
431 // parameters are stored in the outer scope.
432 Scope* parameter_scope = HasSimpleParameters() ? this : outer_scope_;
433 DCHECK(parameter_scope->is_function_scope() || is_eval_scope() ||
434 is_script_scope());
435
436 DeclarationScope* decl_scope = this;
437 while (decl_scope->is_eval_scope()) {
438 decl_scope = decl_scope->outer_scope()->GetDeclarationScope();
439 }
440 Scope* outer_scope = decl_scope->outer_scope();
441
442 // For each variable which is used as a function declaration in a sloppy
443 // block,
444 for (SloppyBlockFunctionStatement* sloppy_block_function :
445 sloppy_block_functions_) {
446 const AstRawString* name = sloppy_block_function->name();
447
448 // If the variable wouldn't conflict with a lexical declaration
449 // or parameter,
450
451 // Check if there's a conflict with a parameter.
452 Variable* maybe_parameter = parameter_scope->LookupLocal(name);
453 if (maybe_parameter != nullptr && maybe_parameter->is_parameter()) {
454 continue;
455 }
456
457 // Check if there's a conflict with a lexical declaration
458 Scope* query_scope = sloppy_block_function->scope()->outer_scope();
459 Variable* var = nullptr;
460 bool should_hoist = true;
461
462 // It is not sufficient to just do a Lookup on query_scope: for
463 // example, that does not prevent hoisting of the function in
464 // `{ let e; try {} catch (e) { function e(){} } }`
465 do {
466 var = query_scope->LookupInScopeOrScopeInfo(name);
467 if (var != nullptr && IsLexicalVariableMode(var->mode())) {
468 should_hoist = false;
469 break;
470 }
471 query_scope = query_scope->outer_scope();
472 } while (query_scope != outer_scope);
473
474 if (!should_hoist) continue;
475
476 if (factory) {
477 DCHECK(!is_being_lazily_parsed_);
478 int pos = sloppy_block_function->position();
479 bool ok = true;
480 bool was_added;
481 auto declaration = factory->NewVariableDeclaration(pos);
482 // Based on the preceding checks, it doesn't matter what we pass as
483 // sloppy_mode_block_scope_function_redefinition.
484 Variable* var = DeclareVariable(
485 declaration, name, pos, VariableMode::kVar, NORMAL_VARIABLE,
486 Variable::DefaultInitializationFlag(VariableMode::kVar), &was_added,
487 nullptr, &ok);
488 DCHECK(ok);
489 VariableProxy* source =
490 factory->NewVariableProxy(sloppy_block_function->var());
491 VariableProxy* target = factory->NewVariableProxy(var);
492 Assignment* assignment = factory->NewAssignment(
493 sloppy_block_function->init(), target, source, pos);
494 assignment->set_lookup_hoisting_mode(LookupHoistingMode::kLegacySloppy);
495 Statement* statement = factory->NewExpressionStatement(assignment, pos);
496 sloppy_block_function->set_statement(statement);
497 } else {
498 DCHECK(is_being_lazily_parsed_);
499 bool was_added;
500 Variable* var = DeclareVariableName(name, VariableMode::kVar, &was_added);
501 if (sloppy_block_function->init() == Token::ASSIGN)
502 var->set_maybe_assigned();
503 }
504 }
505}
506
507bool DeclarationScope::Analyze(ParseInfo* info) {
508 RuntimeCallTimerScope runtimeTimer(
509 info->runtime_call_stats(),
510 info->on_background_thread()
511 ? RuntimeCallCounterId::kCompileBackgroundScopeAnalysis
512 : RuntimeCallCounterId::kCompileScopeAnalysis);
513 DCHECK_NOT_NULL(info->literal());
514 DeclarationScope* scope = info->literal()->scope();
515
516 base::Optional<AllowHandleDereference> allow_deref;
517 if (!info->maybe_outer_scope_info().is_null()) {
518 // Allow dereferences to the scope info if there is one.
519 allow_deref.emplace();
520 }
521
522 if (scope->is_eval_scope() && is_sloppy(scope->language_mode())) {
523 AstNodeFactory factory(info->ast_value_factory(), info->zone());
524 scope->HoistSloppyBlockFunctions(&factory);
525 }
526
527 // We are compiling one of four cases:
528 // 1) top-level code,
529 // 2) a function/eval/module on the top-level
530 // 3) a function/eval in a scope that was already resolved.
531 DCHECK(scope->is_script_scope() || scope->outer_scope()->is_script_scope() ||
532 scope->outer_scope()->already_resolved_);
533
534 // The outer scope is never lazy.
535 scope->set_should_eager_compile();
536
537 if (scope->must_use_preparsed_scope_data_) {
538 DCHECK_EQ(scope->scope_type_, ScopeType::FUNCTION_SCOPE);
539 allow_deref.emplace();
540 info->consumed_preparse_data()->RestoreScopeAllocationData(scope);
541 }
542
543 if (!scope->AllocateVariables(info)) return false;
544
545#ifdef DEBUG
546 if (FLAG_print_scopes) {
547 PrintF("Global scope:\n");
548 scope->Print();
549 }
550 scope->CheckScopePositions();
551 scope->CheckZones();
552#endif
553
554 return true;
555}
556
557void DeclarationScope::DeclareThis(AstValueFactory* ast_value_factory) {
558 DCHECK(has_this_declaration());
559
560 bool derived_constructor = IsDerivedConstructor(function_kind_);
561
562 receiver_ = new (zone())
563 Variable(this, ast_value_factory->this_string(),
564 derived_constructor ? VariableMode::kConst : VariableMode::kVar,
565 THIS_VARIABLE,
566 derived_constructor ? kNeedsInitialization : kCreatedInitialized,
567 kNotAssigned);
568}
569
570void DeclarationScope::DeclareArguments(AstValueFactory* ast_value_factory) {
571 DCHECK(is_function_scope());
572 DCHECK(!is_arrow_scope());
573
574 // Declare 'arguments' variable which exists in all non arrow functions. Note
575 // that it might never be accessed, in which case it won't be allocated during
576 // variable allocation.
577 bool was_added;
578 arguments_ =
579 Declare(zone(), ast_value_factory->arguments_string(), VariableMode::kVar,
580 NORMAL_VARIABLE, kCreatedInitialized, kNotAssigned, &was_added);
581 if (!was_added && IsLexicalVariableMode(arguments_->mode())) {
582 // Check if there's lexically declared variable named arguments to avoid
583 // redeclaration. See ES#sec-functiondeclarationinstantiation, step 20.
584 arguments_ = nullptr;
585 }
586}
587
588void DeclarationScope::DeclareDefaultFunctionVariables(
589 AstValueFactory* ast_value_factory) {
590 DCHECK(is_function_scope());
591 DCHECK(!is_arrow_scope());
592
593 DeclareThis(ast_value_factory);
594 bool was_added;
595 new_target_ = Declare(zone(), ast_value_factory->new_target_string(),
596 VariableMode::kConst, NORMAL_VARIABLE,
597 kCreatedInitialized, kNotAssigned, &was_added);
598 DCHECK(was_added);
599
600 if (IsConciseMethod(function_kind_) || IsClassConstructor(function_kind_) ||
601 IsAccessorFunction(function_kind_)) {
602 EnsureRareData()->this_function = Declare(
603 zone(), ast_value_factory->this_function_string(), VariableMode::kConst,
604 NORMAL_VARIABLE, kCreatedInitialized, kNotAssigned, &was_added);
605 DCHECK(was_added);
606 }
607}
608
609Variable* DeclarationScope::DeclareFunctionVar(const AstRawString* name,
610 Scope* cache) {
611 DCHECK(is_function_scope());
612 DCHECK_NULL(function_);
613 if (cache == nullptr) cache = this;
614 DCHECK_NULL(cache->variables_.Lookup(name));
615 VariableKind kind = is_sloppy(language_mode()) ? SLOPPY_FUNCTION_NAME_VARIABLE
616 : NORMAL_VARIABLE;
617 function_ = new (zone())
618 Variable(this, name, VariableMode::kConst, kind, kCreatedInitialized);
619 if (calls_sloppy_eval()) {
620 cache->NonLocal(name, VariableMode::kDynamic);
621 } else {
622 cache->variables_.Add(zone(), function_);
623 }
624 return function_;
625}
626
627Variable* DeclarationScope::DeclareGeneratorObjectVar(
628 const AstRawString* name) {
629 DCHECK(is_function_scope() || is_module_scope());
630 DCHECK_NULL(generator_object_var());
631
632 Variable* result = EnsureRareData()->generator_object =
633 NewTemporary(name, kNotAssigned);
634 result->set_is_used();
635 return result;
636}
637
638Scope* Scope::FinalizeBlockScope() {
639 DCHECK(is_block_scope());
640#ifdef DEBUG
641 DCHECK_NE(sibling_, this);
642#endif
643
644 if (variables_.occupancy() > 0 ||
645 (is_declaration_scope() && AsDeclarationScope()->calls_sloppy_eval())) {
646 return this;
647 }
648
649 DCHECK(!is_class_scope());
650
651 // Remove this scope from outer scope.
652 outer_scope()->RemoveInnerScope(this);
653
654 // Reparent inner scopes.
655 if (inner_scope_ != nullptr) {
656 Scope* scope = inner_scope_;
657 scope->outer_scope_ = outer_scope();
658 while (scope->sibling_ != nullptr) {
659 scope = scope->sibling_;
660 scope->outer_scope_ = outer_scope();
661 }
662 scope->sibling_ = outer_scope()->inner_scope_;
663 outer_scope()->inner_scope_ = inner_scope_;
664 inner_scope_ = nullptr;
665 }
666
667 // Move unresolved variables
668 if (!unresolved_list_.is_empty()) {
669 outer_scope()->unresolved_list_.Prepend(std::move(unresolved_list_));
670 unresolved_list_.Clear();
671 }
672
673 if (inner_scope_calls_eval_) outer_scope()->inner_scope_calls_eval_ = true;
674
675 // No need to propagate scope_calls_eval_, since if it was relevant to
676 // this scope we would have had to bail out at the top.
677 DCHECK(!scope_calls_eval_ || !is_declaration_scope() ||
678 !is_sloppy(language_mode()));
679
680 // This block does not need a context.
681 num_heap_slots_ = 0;
682
683 // Mark scope as removed by making it its own sibling.
684#ifdef DEBUG
685 sibling_ = this;
686#endif
687
688 return nullptr;
689}
690
691void DeclarationScope::AddLocal(Variable* var) {
692 DCHECK(!already_resolved_);
693 // Temporaries are only placed in ClosureScopes.
694 DCHECK_EQ(GetClosureScope(), this);
695 locals_.Add(var);
696}
697
698void Scope::Snapshot::Reparent(DeclarationScope* new_parent) {
699 DCHECK(!IsCleared());
700 DCHECK_EQ(new_parent, outer_scope_and_calls_eval_.GetPointer()->inner_scope_);
701 DCHECK_EQ(new_parent->outer_scope_, outer_scope_and_calls_eval_.GetPointer());
702 DCHECK_EQ(new_parent, new_parent->GetClosureScope());
703 DCHECK_NULL(new_parent->inner_scope_);
704 DCHECK(new_parent->unresolved_list_.is_empty());
705 Scope* inner_scope = new_parent->sibling_;
706 if (inner_scope != top_inner_scope_) {
707 for (; inner_scope->sibling() != top_inner_scope_;
708 inner_scope = inner_scope->sibling()) {
709 inner_scope->outer_scope_ = new_parent;
710 if (inner_scope->inner_scope_calls_eval_) {
711 new_parent->inner_scope_calls_eval_ = true;
712 }
713 DCHECK_NE(inner_scope, new_parent);
714 }
715 inner_scope->outer_scope_ = new_parent;
716 if (inner_scope->inner_scope_calls_eval_) {
717 new_parent->inner_scope_calls_eval_ = true;
718 }
719 new_parent->inner_scope_ = new_parent->sibling_;
720 inner_scope->sibling_ = nullptr;
721 // Reset the sibling rather than the inner_scope_ since we
722 // want to keep new_parent there.
723 new_parent->sibling_ = top_inner_scope_;
724 }
725
726 Scope* outer_scope_ = outer_scope_and_calls_eval_.GetPointer();
727 new_parent->unresolved_list_.MoveTail(&outer_scope_->unresolved_list_,
728 top_unresolved_);
729
730 // Move temporaries allocated for complex parameter initializers.
731 DeclarationScope* outer_closure = outer_scope_->GetClosureScope();
732 for (auto it = top_local_; it != outer_closure->locals()->end(); ++it) {
733 Variable* local = *it;
734 DCHECK_EQ(VariableMode::kTemporary, local->mode());
735 DCHECK_EQ(local->scope(), local->scope()->GetClosureScope());
736 DCHECK_NE(local->scope(), new_parent);
737 local->set_scope(new_parent);
738 }
739 new_parent->locals_.MoveTail(outer_closure->locals(), top_local_);
740 outer_closure->locals_.Rewind(top_local_);
741
742 // Move eval calls since Snapshot's creation into new_parent.
743 if (outer_scope_and_calls_eval_->scope_calls_eval_) {
744 new_parent->scope_calls_eval_ = true;
745 new_parent->inner_scope_calls_eval_ = true;
746 }
747
748 // We are in the arrow function case. The calls eval we may have recorded
749 // is intended for the inner scope and we should simply restore the
750 // original "calls eval" flag of the outer scope.
751 RestoreEvalFlag();
752 Clear();
753}
754
755void Scope::ReplaceOuterScope(Scope* outer) {
756 DCHECK_NOT_NULL(outer);
757 DCHECK_NOT_NULL(outer_scope_);
758 DCHECK(!already_resolved_);
759 outer_scope_->RemoveInnerScope(this);
760 outer->AddInnerScope(this);
761 outer_scope_ = outer;
762}
763
764Variable* Scope::LookupInScopeInfo(const AstRawString* name, Scope* cache) {
765 DCHECK(!scope_info_.is_null());
766 DCHECK_NULL(cache->variables_.Lookup(name));
767 DisallowHeapAllocation no_gc;
768
769 String name_handle = *name->string();
770 // The Scope is backed up by ScopeInfo. This means it cannot operate in a
771 // heap-independent mode, and all strings must be internalized immediately. So
772 // it's ok to get the Handle<String> here.
773 bool found = false;
774
775 VariableLocation location;
776 int index;
777 VariableMode mode;
778 InitializationFlag init_flag;
779 MaybeAssignedFlag maybe_assigned_flag;
780
781 {
782 location = VariableLocation::CONTEXT;
783 index = ScopeInfo::ContextSlotIndex(*scope_info_, name_handle, &mode,
784 &init_flag, &maybe_assigned_flag);
785 found = index >= 0;
786 }
787
788 if (!found && is_module_scope()) {
789 location = VariableLocation::MODULE;
790 index = scope_info_->ModuleIndex(name_handle, &mode, &init_flag,
791 &maybe_assigned_flag);
792 found = index != 0;
793 }
794
795 if (!found) {
796 index = scope_info_->FunctionContextSlotIndex(name_handle);
797 if (index < 0) return nullptr; // Nowhere found.
798 Variable* var = AsDeclarationScope()->DeclareFunctionVar(name, cache);
799 DCHECK_EQ(VariableMode::kConst, var->mode());
800 var->AllocateTo(VariableLocation::CONTEXT, index);
801 return cache->variables_.Lookup(name);
802 }
803
804 if (!is_module_scope()) {
805 DCHECK_NE(index, scope_info_->ReceiverContextSlotIndex());
806 }
807
808 bool was_added;
809 Variable* var =
810 cache->variables_.Declare(zone(), this, name, mode, NORMAL_VARIABLE,
811 init_flag, maybe_assigned_flag, &was_added);
812 DCHECK(was_added);
813 var->AllocateTo(location, index);
814 return var;
815}
816
817Variable* DeclarationScope::DeclareParameter(const AstRawString* name,
818 VariableMode mode,
819 bool is_optional, bool is_rest,
820 AstValueFactory* ast_value_factory,
821 int position) {
822 DCHECK(!already_resolved_);
823 DCHECK(is_function_scope() || is_module_scope());
824 DCHECK(!has_rest_);
825 DCHECK(!is_optional || !is_rest);
826 DCHECK(!is_being_lazily_parsed_);
827 DCHECK(!was_lazily_parsed_);
828 Variable* var;
829 if (mode == VariableMode::kTemporary) {
830 var = NewTemporary(name);
831 } else {
832 var = LookupLocal(name);
833 DCHECK_EQ(mode, VariableMode::kVar);
834 DCHECK(var->is_parameter());
835 }
836 has_rest_ = is_rest;
837 var->set_initializer_position(position);
838 params_.Add(var, zone());
839 if (!is_rest) ++num_parameters_;
840 if (name == ast_value_factory->arguments_string()) {
841 has_arguments_parameter_ = true;
842 }
843 // Params are automatically marked as used to make sure that the debugger and
844 // function.arguments sees them.
845 // TODO(verwaest): Reevaluate whether we always need to do this, since
846 // strict-mode function.arguments does not make the arguments available.
847 var->set_is_used();
848 return var;
849}
850
851void DeclarationScope::RecordParameter(bool is_rest) {
852 DCHECK(!already_resolved_);
853 DCHECK(is_function_scope() || is_module_scope());
854 DCHECK(is_being_lazily_parsed_);
855 DCHECK(!has_rest_);
856 has_rest_ = is_rest;
857 if (!is_rest) ++num_parameters_;
858}
859
860Variable* Scope::DeclareLocal(const AstRawString* name, VariableMode mode,
861 VariableKind kind, bool* was_added,
862 InitializationFlag init_flag) {
863 DCHECK(!already_resolved_);
864 // This function handles VariableMode::kVar, VariableMode::kLet, and
865 // VariableMode::kConst modes. VariableMode::kDynamic variables are
866 // introduced during variable allocation, and VariableMode::kTemporary
867 // variables are allocated via NewTemporary().
868 DCHECK(IsDeclaredVariableMode(mode));
869 DCHECK_IMPLIES(GetDeclarationScope()->is_being_lazily_parsed(),
870 mode == VariableMode::kVar || mode == VariableMode::kLet ||
871 mode == VariableMode::kConst);
872 DCHECK(!GetDeclarationScope()->was_lazily_parsed());
873 Variable* var =
874 Declare(zone(), name, mode, kind, init_flag, kNotAssigned, was_added);
875
876 // Pessimistically assume that top-level variables will be assigned and used.
877 //
878 // Top-level variables in a script can be accessed by other scripts or even
879 // become global properties. While this does not apply to top-level variables
880 // in a module (assuming they are not exported), we must still mark these as
881 // assigned because they might be accessed by a lazily parsed top-level
882 // function, which, for efficiency, we preparse without variable tracking.
883 if (is_script_scope() || is_module_scope()) {
884 if (mode != VariableMode::kConst) var->set_maybe_assigned();
885 var->set_is_used();
886 }
887
888 return var;
889}
890
891Variable* Scope::DeclareVariable(
892 Declaration* declaration, const AstRawString* name, int pos,
893 VariableMode mode, VariableKind kind, InitializationFlag init,
894 bool* was_added, bool* sloppy_mode_block_scope_function_redefinition,
895 bool* ok) {
896 DCHECK(IsDeclaredVariableMode(mode));
897 DCHECK(!already_resolved_);
898 DCHECK(!GetDeclarationScope()->is_being_lazily_parsed());
899 DCHECK(!GetDeclarationScope()->was_lazily_parsed());
900
901 if (mode == VariableMode::kVar && !is_declaration_scope()) {
902 return GetDeclarationScope()->DeclareVariable(
903 declaration, name, pos, mode, kind, init, was_added,
904 sloppy_mode_block_scope_function_redefinition, ok);
905 }
906 DCHECK(!is_catch_scope());
907 DCHECK(!is_with_scope());
908 DCHECK(is_declaration_scope() ||
909 (IsLexicalVariableMode(mode) && is_block_scope()));
910
911 DCHECK_NOT_NULL(name);
912
913 Variable* var = LookupLocal(name);
914 // Declare the variable in the declaration scope.
915 *was_added = var == nullptr;
916 if (V8_LIKELY(*was_added)) {
917 if (V8_UNLIKELY(is_eval_scope() && is_sloppy(language_mode()) &&
918 mode == VariableMode::kVar)) {
919 // In a var binding in a sloppy direct eval, pollute the enclosing scope
920 // with this new binding by doing the following:
921 // The proxy is bound to a lookup variable to force a dynamic declaration
922 // using the DeclareEvalVar or DeclareEvalFunction runtime functions.
923 DCHECK_EQ(NORMAL_VARIABLE, kind);
924 var = NonLocal(name, VariableMode::kDynamic);
925 // Mark the var as used in case anyone outside the eval wants to use it.
926 var->set_is_used();
927 } else {
928 // Declare the name.
929 var = DeclareLocal(name, mode, kind, was_added, init);
930 DCHECK(*was_added);
931 }
932 } else {
933 var->set_maybe_assigned();
934 if (V8_UNLIKELY(IsLexicalVariableMode(mode) ||
935 IsLexicalVariableMode(var->mode()))) {
936 // The name was declared in this scope before; check for conflicting
937 // re-declarations. We have a conflict if either of the declarations is
938 // not a var (in script scope, we also have to ignore legacy const for
939 // compatibility). There is similar code in runtime.cc in the Declare
940 // functions. The function CheckConflictingVarDeclarations checks for
941 // var and let bindings from different scopes whereas this is a check
942 // for conflicting declarations within the same scope. This check also
943 // covers the special case
944 //
945 // function () { let x; { var x; } }
946 //
947 // because the var declaration is hoisted to the function scope where
948 // 'x' is already bound.
949 //
950 // In harmony we treat re-declarations as early errors. See ES5 16 for a
951 // definition of early errors.
952 //
953 // Allow duplicate function decls for web compat, see bug 4693.
954 *ok = var->is_sloppy_block_function() &&
955 kind == SLOPPY_BLOCK_FUNCTION_VARIABLE;
956 *sloppy_mode_block_scope_function_redefinition = *ok;
957 }
958 }
959 DCHECK_NOT_NULL(var);
960
961 // We add a declaration node for every declaration. The compiler
962 // will only generate code if necessary. In particular, declarations
963 // for inner local variables that do not represent functions won't
964 // result in any generated code.
965 //
966 // This will lead to multiple declaration nodes for the
967 // same variable if it is declared several times. This is not a
968 // semantic issue, but it may be a performance issue since it may
969 // lead to repeated DeclareEvalVar or DeclareEvalFunction calls.
970 decls_.Add(declaration);
971 declaration->set_var(var);
972 return var;
973}
974
975Variable* Scope::DeclareVariableName(const AstRawString* name,
976 VariableMode mode, bool* was_added,
977 VariableKind kind) {
978 DCHECK(IsDeclaredVariableMode(mode));
979 DCHECK(!already_resolved_);
980 DCHECK(GetDeclarationScope()->is_being_lazily_parsed());
981
982 if (mode == VariableMode::kVar && !is_declaration_scope()) {
983 return GetDeclarationScope()->DeclareVariableName(name, mode, was_added,
984 kind);
985 }
986 DCHECK(!is_with_scope());
987 DCHECK(!is_eval_scope());
988 DCHECK(is_declaration_scope() || IsLexicalVariableMode(mode));
989 DCHECK(scope_info_.is_null());
990
991 // Declare the variable in the declaration scope.
992 Variable* var = DeclareLocal(name, mode, kind, was_added);
993 if (!*was_added) {
994 if (IsLexicalVariableMode(mode) || IsLexicalVariableMode(var->mode())) {
995 if (!var->is_sloppy_block_function() ||
996 kind != SLOPPY_BLOCK_FUNCTION_VARIABLE) {
997 // Duplicate functions are allowed in the sloppy mode, but if this is
998 // not a function declaration, it's an error. This is an error PreParser
999 // hasn't previously detected.
1000 return nullptr;
1001 }
1002 // Sloppy block function redefinition.
1003 }
1004 var->set_maybe_assigned();
1005 }
1006 var->set_is_used();
1007 return var;
1008}
1009
1010Variable* Scope::DeclareCatchVariableName(const AstRawString* name) {
1011 DCHECK(!already_resolved_);
1012 DCHECK(is_catch_scope());
1013 DCHECK(scope_info_.is_null());
1014
1015 bool was_added;
1016 Variable* result = Declare(zone(), name, VariableMode::kVar, NORMAL_VARIABLE,
1017 kCreatedInitialized, kNotAssigned, &was_added);
1018 DCHECK(was_added);
1019 return result;
1020}
1021
1022void Scope::AddUnresolved(VariableProxy* proxy) {
1023 DCHECK(!already_resolved_);
1024 DCHECK(!proxy->is_resolved());
1025 unresolved_list_.Add(proxy);
1026}
1027
1028Variable* DeclarationScope::DeclareDynamicGlobal(const AstRawString* name,
1029 VariableKind kind,
1030 Scope* cache) {
1031 DCHECK(is_script_scope());
1032 bool was_added;
1033 return cache->variables_.Declare(
1034 zone(), this, name, VariableMode::kDynamicGlobal, kind,
1035 kCreatedInitialized, kNotAssigned, &was_added);
1036 // TODO(neis): Mark variable as maybe-assigned?
1037}
1038
1039bool Scope::RemoveUnresolved(VariableProxy* var) {
1040 return unresolved_list_.Remove(var);
1041}
1042
1043void Scope::DeleteUnresolved(VariableProxy* var) {
1044 DCHECK(unresolved_list_.Contains(var));
1045 var->mark_removed_from_unresolved();
1046}
1047
1048Variable* Scope::NewTemporary(const AstRawString* name) {
1049 return NewTemporary(name, kMaybeAssigned);
1050}
1051
1052Variable* Scope::NewTemporary(const AstRawString* name,
1053 MaybeAssignedFlag maybe_assigned) {
1054 DeclarationScope* scope = GetClosureScope();
1055 Variable* var = new (zone()) Variable(scope, name, VariableMode::kTemporary,
1056 NORMAL_VARIABLE, kCreatedInitialized);
1057 scope->AddLocal(var);
1058 if (maybe_assigned == kMaybeAssigned) var->set_maybe_assigned();
1059 return var;
1060}
1061
1062Declaration* DeclarationScope::CheckConflictingVarDeclarations() {
1063 if (has_checked_syntax_) return nullptr;
1064 for (Declaration* decl : decls_) {
1065 // Lexical vs lexical conflicts within the same scope have already been
1066 // captured in Parser::Declare. The only conflicts we still need to check
1067 // are lexical vs nested var.
1068 if (decl->IsVariableDeclaration() &&
1069 decl->AsVariableDeclaration()->AsNested() != nullptr) {
1070 Scope* current = decl->AsVariableDeclaration()->AsNested()->scope();
1071 DCHECK(decl->var()->mode() == VariableMode::kVar ||
1072 decl->var()->mode() == VariableMode::kDynamic);
1073 // Iterate through all scopes until the declaration scope.
1074 do {
1075 // There is a conflict if there exists a non-VAR binding.
1076 if (current->is_catch_scope()) {
1077 current = current->outer_scope();
1078 continue;
1079 }
1080 Variable* other_var = current->LookupLocal(decl->var()->raw_name());
1081 if (other_var != nullptr) {
1082 DCHECK(IsLexicalVariableMode(other_var->mode()));
1083 return decl;
1084 }
1085 current = current->outer_scope();
1086 } while (current != this);
1087 }
1088 }
1089
1090 if (V8_LIKELY(!is_eval_scope())) return nullptr;
1091 if (!is_sloppy(language_mode())) return nullptr;
1092
1093 // Var declarations in sloppy eval are hoisted to the first non-eval
1094 // declaration scope. Check for conflicts between the eval scope that
1095 // declaration scope.
1096 Scope* end = this;
1097 do {
1098 end = end->outer_scope_->GetDeclarationScope();
1099 } while (end->is_eval_scope());
1100 end = end->outer_scope_;
1101
1102 for (Declaration* decl : decls_) {
1103 if (IsLexicalVariableMode(decl->var()->mode())) continue;
1104 Scope* current = outer_scope_;
1105 // Iterate through all scopes until and including the declaration scope.
1106 do {
1107 // There is a conflict if there exists a non-VAR binding up to the
1108 // declaration scope in which this sloppy-eval runs.
1109 Variable* other_var =
1110 current->LookupInScopeOrScopeInfo(decl->var()->raw_name());
1111 if (other_var != nullptr && IsLexicalVariableMode(other_var->mode())) {
1112 DCHECK(!current->is_catch_scope());
1113 return decl;
1114 }
1115 current = current->outer_scope();
1116 } while (current != end);
1117 }
1118 return nullptr;
1119}
1120
1121const AstRawString* Scope::FindVariableDeclaredIn(Scope* scope,
1122 VariableMode mode_limit) {
1123 const VariableMap& variables = scope->variables_;
1124 for (ZoneHashMap::Entry* p = variables.Start(); p != nullptr;
1125 p = variables.Next(p)) {
1126 const AstRawString* name = static_cast<const AstRawString*>(p->key);
1127 Variable* var = LookupLocal(name);
1128 if (var != nullptr && var->mode() <= mode_limit) return name;
1129 }
1130 return nullptr;
1131}
1132
1133void DeclarationScope::DeserializeReceiver(AstValueFactory* ast_value_factory) {
1134 if (is_script_scope()) {
1135 DCHECK_NOT_NULL(receiver_);
1136 return;
1137 }
1138 DCHECK(has_this_declaration());
1139 DeclareThis(ast_value_factory);
1140 if (is_debug_evaluate_scope()) {
1141 receiver_->AllocateTo(VariableLocation::LOOKUP, -1);
1142 } else {
1143 receiver_->AllocateTo(VariableLocation::CONTEXT,
1144 scope_info_->ReceiverContextSlotIndex());
1145 }
1146}
1147
1148bool DeclarationScope::AllocateVariables(ParseInfo* info) {
1149 // Module variables must be allocated before variable resolution
1150 // to ensure that UpdateNeedsHoleCheck() can detect import variables.
1151 if (is_module_scope()) AsModuleScope()->AllocateModuleVariables();
1152
1153 ClassScope* closest_class_scope = GetClassScope();
1154 if (closest_class_scope != nullptr &&
1155 !closest_class_scope->ResolvePrivateNames(info)) {
1156 DCHECK(info->pending_error_handler()->has_pending_error());
1157 return false;
1158 }
1159
1160 if (!ResolveVariablesRecursively(info)) {
1161 DCHECK(info->pending_error_handler()->has_pending_error());
1162 return false;
1163 }
1164
1165 // // Don't allocate variables of preparsed scopes.
1166 if (!was_lazily_parsed()) AllocateVariablesRecursively();
1167
1168 return true;
1169}
1170
1171bool Scope::HasThisReference() const {
1172 if (is_declaration_scope() && AsDeclarationScope()->has_this_reference()) {
1173 return true;
1174 }
1175
1176 for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) {
1177 if (!scope->is_declaration_scope() ||
1178 !scope->AsDeclarationScope()->has_this_declaration()) {
1179 if (scope->HasThisReference()) return true;
1180 }
1181 }
1182
1183 return false;
1184}
1185
1186bool Scope::AllowsLazyParsingWithoutUnresolvedVariables(
1187 const Scope* outer) const {
1188 // If none of the outer scopes need to decide whether to context allocate
1189 // specific variables, we can preparse inner functions without unresolved
1190 // variables. Otherwise we need to find unresolved variables to force context
1191 // allocation of the matching declarations. We can stop at the outer scope for
1192 // the parse, since context allocation of those variables is already
1193 // guaranteed to be correct.
1194 for (const Scope* s = this; s != outer; s = s->outer_scope_) {
1195 // Eval forces context allocation on all outer scopes, so we don't need to
1196 // look at those scopes. Sloppy eval makes top-level non-lexical variables
1197 // dynamic, whereas strict-mode requires context allocation.
1198 if (s->is_eval_scope()) return is_sloppy(s->language_mode());
1199 // Catch scopes force context allocation of all variables.
1200 if (s->is_catch_scope()) continue;
1201 // With scopes do not introduce variables that need allocation.
1202 if (s->is_with_scope()) continue;
1203 DCHECK(s->is_module_scope() || s->is_block_scope() ||
1204 s->is_function_scope());
1205 return false;
1206 }
1207 return true;
1208}
1209
1210bool DeclarationScope::AllowsLazyCompilation() const {
1211 // Functions which force eager compilation and class member initializer
1212 // functions are not lazily compilable.
1213 return !force_eager_compilation_ &&
1214 !IsClassMembersInitializerFunction(function_kind());
1215}
1216
1217int Scope::ContextChainLength(Scope* scope) const {
1218 int n = 0;
1219 for (const Scope* s = this; s != scope; s = s->outer_scope_) {
1220 DCHECK_NOT_NULL(s); // scope must be in the scope chain
1221 if (s->NeedsContext()) n++;
1222 }
1223 return n;
1224}
1225
1226int Scope::ContextChainLengthUntilOutermostSloppyEval() const {
1227 int result = 0;
1228 int length = 0;
1229
1230 for (const Scope* s = this; s != nullptr; s = s->outer_scope()) {
1231 if (!s->NeedsContext()) continue;
1232 length++;
1233 if (s->is_declaration_scope() &&
1234 s->AsDeclarationScope()->calls_sloppy_eval()) {
1235 result = length;
1236 }
1237 }
1238
1239 return result;
1240}
1241
1242ClassScope* Scope::GetClassScope() {
1243 Scope* scope = this;
1244 while (scope != nullptr && !scope->is_class_scope()) {
1245 scope = scope->outer_scope();
1246 }
1247 if (scope != nullptr && scope->is_class_scope()) {
1248 return scope->AsClassScope();
1249 }
1250 return nullptr;
1251}
1252
1253DeclarationScope* Scope::GetDeclarationScope() {
1254 Scope* scope = this;
1255 while (!scope->is_declaration_scope()) {
1256 scope = scope->outer_scope();
1257 }
1258 return scope->AsDeclarationScope();
1259}
1260
1261const DeclarationScope* Scope::GetClosureScope() const {
1262 const Scope* scope = this;
1263 while (!scope->is_declaration_scope() || scope->is_block_scope()) {
1264 scope = scope->outer_scope();
1265 }
1266 return scope->AsDeclarationScope();
1267}
1268
1269DeclarationScope* Scope::GetClosureScope() {
1270 Scope* scope = this;
1271 while (!scope->is_declaration_scope() || scope->is_block_scope()) {
1272 scope = scope->outer_scope();
1273 }
1274 return scope->AsDeclarationScope();
1275}
1276
1277bool Scope::NeedsScopeInfo() const {
1278 DCHECK(!already_resolved_);
1279 DCHECK(GetClosureScope()->ShouldEagerCompile());
1280 // The debugger expects all functions to have scope infos.
1281 // TODO(jochen|yangguo): Remove this requirement.
1282 if (is_function_scope()) return true;
1283 return NeedsContext();
1284}
1285
1286bool Scope::ShouldBanArguments() {
1287 return GetReceiverScope()->should_ban_arguments();
1288}
1289
1290DeclarationScope* Scope::GetReceiverScope() {
1291 Scope* scope = this;
1292 while (!scope->is_declaration_scope() ||
1293 (!scope->is_script_scope() &&
1294 !scope->AsDeclarationScope()->has_this_declaration())) {
1295 scope = scope->outer_scope();
1296 }
1297 return scope->AsDeclarationScope();
1298}
1299
1300Scope* Scope::GetOuterScopeWithContext() {
1301 Scope* scope = outer_scope_;
1302 while (scope && !scope->NeedsContext()) {
1303 scope = scope->outer_scope();
1304 }
1305 return scope;
1306}
1307
1308namespace {
1309bool WasLazilyParsed(Scope* scope) {
1310 return scope->is_declaration_scope() &&
1311 scope->AsDeclarationScope()->was_lazily_parsed();
1312}
1313
1314} // namespace
1315
1316template <typename FunctionType>
1317void Scope::ForEach(FunctionType callback) {
1318 Scope* scope = this;
1319 while (true) {
1320 Iteration iteration = callback(scope);
1321 // Try to descend into inner scopes first.
1322 if ((iteration == Iteration::kDescend) && scope->inner_scope_ != nullptr) {
1323 scope = scope->inner_scope_;
1324 } else {
1325 // Find the next outer scope with a sibling.
1326 while (scope->sibling_ == nullptr) {
1327 if (scope == this) return;
1328 scope = scope->outer_scope_;
1329 }
1330 if (scope == this) return;
1331 scope = scope->sibling_;
1332 }
1333 }
1334}
1335
1336void Scope::CollectNonLocals(DeclarationScope* max_outer_scope,
1337 Isolate* isolate, ParseInfo* info,
1338 Handle<StringSet>* non_locals) {
1339 this->ForEach([max_outer_scope, isolate, info, non_locals](Scope* scope) {
1340 // Module variables must be allocated before variable resolution
1341 // to ensure that UpdateNeedsHoleCheck() can detect import variables.
1342 if (scope->is_module_scope()) {
1343 scope->AsModuleScope()->AllocateModuleVariables();
1344 }
1345
1346 // Lazy parsed declaration scopes are already partially analyzed. If there
1347 // are unresolved references remaining, they just need to be resolved in
1348 // outer scopes.
1349 Scope* lookup = WasLazilyParsed(scope) ? scope->outer_scope() : scope;
1350
1351 for (VariableProxy* proxy : scope->unresolved_list_) {
1352 DCHECK(!proxy->is_resolved());
1353 Variable* var =
1354 Lookup<kParsedScope>(proxy, lookup, max_outer_scope->outer_scope());
1355 if (var == nullptr) {
1356 *non_locals = StringSet::Add(isolate, *non_locals, proxy->name());
1357 } else {
1358 // In this case we need to leave scopes in a way that they can be
1359 // allocated. If we resolved variables from lazy parsed scopes, we need
1360 // to context allocate the var.
1361 scope->ResolveTo(info, proxy, var);
1362 if (!var->is_dynamic() && lookup != scope)
1363 var->ForceContextAllocation();
1364 }
1365 }
1366
1367 // Clear unresolved_list_ as it's in an inconsistent state.
1368 scope->unresolved_list_.Clear();
1369 return Iteration::kDescend;
1370 });
1371}
1372
1373void Scope::AnalyzePartially(DeclarationScope* max_outer_scope,
1374 AstNodeFactory* ast_node_factory,
1375 UnresolvedList* new_unresolved_list) {
1376 this->ForEach([max_outer_scope, ast_node_factory,
1377 new_unresolved_list](Scope* scope) {
1378 DCHECK_IMPLIES(scope->is_declaration_scope(),
1379 !scope->AsDeclarationScope()->was_lazily_parsed());
1380
1381 for (VariableProxy* proxy = scope->unresolved_list_.first();
1382 proxy != nullptr; proxy = proxy->next_unresolved()) {
1383 DCHECK(!proxy->is_resolved());
1384 Variable* var =
1385 Lookup<kParsedScope>(proxy, scope, max_outer_scope->outer_scope());
1386 if (var == nullptr) {
1387 // Don't copy unresolved references to the script scope, unless it's a
1388 // reference to a private name or method. In that case keep it so we
1389 // can fail later.
1390 if (!max_outer_scope->outer_scope()->is_script_scope()) {
1391 VariableProxy* copy = ast_node_factory->CopyVariableProxy(proxy);
1392 new_unresolved_list->Add(copy);
1393 }
1394 } else {
1395 var->set_is_used();
1396 if (proxy->is_assigned()) var->set_maybe_assigned();
1397 }
1398 }
1399
1400 // Clear unresolved_list_ as it's in an inconsistent state.
1401 scope->unresolved_list_.Clear();
1402 return Iteration::kDescend;
1403 });
1404}
1405
1406Handle<StringSet> DeclarationScope::CollectNonLocals(
1407 Isolate* isolate, ParseInfo* info, Handle<StringSet> non_locals) {
1408 Scope::CollectNonLocals(this, isolate, info, &non_locals);
1409 return non_locals;
1410}
1411
1412void DeclarationScope::ResetAfterPreparsing(AstValueFactory* ast_value_factory,
1413 bool aborted) {
1414 DCHECK(is_function_scope());
1415
1416 // Reset all non-trivial members.
1417 params_.Clear();
1418 decls_.Clear();
1419 locals_.Clear();
1420 inner_scope_ = nullptr;
1421 unresolved_list_.Clear();
1422 sloppy_block_functions_.Clear();
1423 rare_data_ = nullptr;
1424 has_rest_ = false;
1425
1426 DCHECK_NE(zone_, ast_value_factory->zone());
1427 zone_->ReleaseMemory();
1428
1429 if (aborted) {
1430 // Prepare scope for use in the outer zone.
1431 zone_ = ast_value_factory->zone();
1432 variables_.Reset(ZoneAllocationPolicy(zone_));
1433 if (!IsArrowFunction(function_kind_)) {
1434 has_simple_parameters_ = true;
1435 DeclareDefaultFunctionVariables(ast_value_factory);
1436 }
1437 } else {
1438 // Make sure this scope isn't used for allocation anymore.
1439 zone_ = nullptr;
1440 variables_.Invalidate();
1441 }
1442
1443#ifdef DEBUG
1444 needs_migration_ = false;
1445 is_being_lazily_parsed_ = false;
1446#endif
1447
1448 was_lazily_parsed_ = !aborted;
1449}
1450
1451bool Scope::IsSkippableFunctionScope() {
1452 // Lazy non-arrow function scopes are skippable. Lazy functions are exactly
1453 // those Scopes which have their own PreparseDataBuilder object. This
1454 // logic ensures that the scope allocation data is consistent with the
1455 // skippable function data (both agree on where the lazy function boundaries
1456 // are).
1457 if (!is_function_scope()) return false;
1458 DeclarationScope* declaration_scope = AsDeclarationScope();
1459 return !declaration_scope->is_arrow_scope() &&
1460 declaration_scope->preparse_data_builder() != nullptr;
1461}
1462
1463void Scope::SavePreparseData(Parser* parser) {
1464 this->ForEach([parser](Scope* scope) {
1465 if (scope->IsSkippableFunctionScope()) {
1466 scope->AsDeclarationScope()->SavePreparseDataForDeclarationScope(parser);
1467 }
1468 return Iteration::kDescend;
1469 });
1470}
1471
1472void DeclarationScope::SavePreparseDataForDeclarationScope(Parser* parser) {
1473 if (preparse_data_builder_ == nullptr) return;
1474 preparse_data_builder_->SaveScopeAllocationData(this, parser);
1475}
1476
1477void DeclarationScope::AnalyzePartially(Parser* parser,
1478 AstNodeFactory* ast_node_factory) {
1479 DCHECK(!force_eager_compilation_);
1480 UnresolvedList new_unresolved_list;
1481 if (!IsArrowFunction(function_kind_) &&
1482 (!outer_scope_->is_script_scope() ||
1483 (preparse_data_builder_ != nullptr &&
1484 preparse_data_builder_->HasInnerFunctions()))) {
1485 // Try to resolve unresolved variables for this Scope and migrate those
1486 // which cannot be resolved inside. It doesn't make sense to try to resolve
1487 // them in the outer Scopes here, because they are incomplete.
1488 Scope::AnalyzePartially(this, ast_node_factory, &new_unresolved_list);
1489
1490 // Migrate function_ to the right Zone.
1491 if (function_ != nullptr) {
1492 function_ = ast_node_factory->CopyVariable(function_);
1493 }
1494
1495 SavePreparseData(parser);
1496 }
1497
1498#ifdef DEBUG
1499 if (FLAG_print_scopes) {
1500 PrintF("Inner function scope:\n");
1501 Print();
1502 }
1503#endif
1504
1505 ResetAfterPreparsing(ast_node_factory->ast_value_factory(), false);
1506
1507 unresolved_list_ = std::move(new_unresolved_list);
1508}
1509
1510#ifdef DEBUG
1511namespace {
1512
1513const char* Header(ScopeType scope_type, FunctionKind function_kind,
1514 bool is_declaration_scope) {
1515 switch (scope_type) {
1516 case EVAL_SCOPE: return "eval";
1517 // TODO(adamk): Should we print concise method scopes specially?
1518 case FUNCTION_SCOPE:
1519 if (IsGeneratorFunction(function_kind)) return "function*";
1520 if (IsAsyncFunction(function_kind)) return "async function";
1521 if (IsArrowFunction(function_kind)) return "arrow";
1522 return "function";
1523 case MODULE_SCOPE: return "module";
1524 case SCRIPT_SCOPE: return "global";
1525 case CATCH_SCOPE: return "catch";
1526 case BLOCK_SCOPE: return is_declaration_scope ? "varblock" : "block";
1527 case CLASS_SCOPE:
1528 return "class";
1529 case WITH_SCOPE: return "with";
1530 }
1531 UNREACHABLE();
1532}
1533
1534void Indent(int n, const char* str) { PrintF("%*s%s", n, "", str); }
1535
1536void PrintName(const AstRawString* name) {
1537 PrintF("%.*s", name->length(), name->raw_data());
1538}
1539
1540void PrintLocation(Variable* var) {
1541 switch (var->location()) {
1542 case VariableLocation::UNALLOCATED:
1543 break;
1544 case VariableLocation::PARAMETER:
1545 PrintF("parameter[%d]", var->index());
1546 break;
1547 case VariableLocation::LOCAL:
1548 PrintF("local[%d]", var->index());
1549 break;
1550 case VariableLocation::CONTEXT:
1551 PrintF("context[%d]", var->index());
1552 break;
1553 case VariableLocation::LOOKUP:
1554 PrintF("lookup");
1555 break;
1556 case VariableLocation::MODULE:
1557 PrintF("module");
1558 break;
1559 }
1560}
1561
1562void PrintVar(int indent, Variable* var) {
1563 Indent(indent, VariableMode2String(var->mode()));
1564 PrintF(" ");
1565 if (var->raw_name()->IsEmpty())
1566 PrintF(".%p", reinterpret_cast<void*>(var));
1567 else
1568 PrintName(var->raw_name());
1569 PrintF("; // (%p) ", reinterpret_cast<void*>(var));
1570 PrintLocation(var);
1571 bool comma = !var->IsUnallocated();
1572 if (var->has_forced_context_allocation()) {
1573 if (comma) PrintF(", ");
1574 PrintF("forced context allocation");
1575 comma = true;
1576 }
1577 if (var->maybe_assigned() == kNotAssigned) {
1578 if (comma) PrintF(", ");
1579 PrintF("never assigned");
1580 comma = true;
1581 }
1582 if (var->initialization_flag() == kNeedsInitialization &&
1583 !var->binding_needs_init()) {
1584 if (comma) PrintF(", ");
1585 PrintF("hole initialization elided");
1586 }
1587 PrintF("\n");
1588}
1589
1590void PrintMap(int indent, const char* label, VariableMap* map, bool locals,
1591 Variable* function_var) {
1592 bool printed_label = false;
1593 for (VariableMap::Entry* p = map->Start(); p != nullptr; p = map->Next(p)) {
1594 Variable* var = reinterpret_cast<Variable*>(p->value);
1595 if (var == function_var) continue;
1596 bool local = !IsDynamicVariableMode(var->mode());
1597 if ((locals ? local : !local) &&
1598 (var->is_used() || !var->IsUnallocated())) {
1599 if (!printed_label) {
1600 Indent(indent, label);
1601 printed_label = true;
1602 }
1603 PrintVar(indent, var);
1604 }
1605 }
1606}
1607
1608} // anonymous namespace
1609
1610void DeclarationScope::PrintParameters() {
1611 PrintF(" (");
1612 for (int i = 0; i < params_.length(); i++) {
1613 if (i > 0) PrintF(", ");
1614 const AstRawString* name = params_[i]->raw_name();
1615 if (name->IsEmpty()) {
1616 PrintF(".%p", reinterpret_cast<void*>(params_[i]));
1617 } else {
1618 PrintName(name);
1619 }
1620 }
1621 PrintF(")");
1622}
1623
1624void Scope::Print(int n) {
1625 int n0 = (n > 0 ? n : 0);
1626 int n1 = n0 + 2; // indentation
1627
1628 // Print header.
1629 FunctionKind function_kind = is_function_scope()
1630 ? AsDeclarationScope()->function_kind()
1631 : kNormalFunction;
1632 Indent(n0, Header(scope_type_, function_kind, is_declaration_scope()));
1633 if (scope_name_ != nullptr && !scope_name_->IsEmpty()) {
1634 PrintF(" ");
1635 PrintName(scope_name_);
1636 }
1637
1638 // Print parameters, if any.
1639 Variable* function = nullptr;
1640 if (is_function_scope()) {
1641 AsDeclarationScope()->PrintParameters();
1642 function = AsDeclarationScope()->function_var();
1643 }
1644
1645 PrintF(" { // (%p) (%d, %d)\n", reinterpret_cast<void*>(this),
1646 start_position(), end_position());
1647 if (is_hidden()) {
1648 Indent(n1, "// is hidden\n");
1649 }
1650
1651 // Function name, if any (named function literals, only).
1652 if (function != nullptr) {
1653 Indent(n1, "// (local) function name: ");
1654 PrintName(function->raw_name());
1655 PrintF("\n");
1656 }
1657
1658 // Scope info.
1659 if (is_strict(language_mode())) {
1660 Indent(n1, "// strict mode scope\n");
1661 }
1662 if (IsAsmModule()) Indent(n1, "// scope is an asm module\n");
1663 if (is_declaration_scope() && AsDeclarationScope()->calls_sloppy_eval()) {
1664 Indent(n1, "// scope calls sloppy 'eval'\n");
1665 }
1666 if (is_declaration_scope() && AsDeclarationScope()->NeedsHomeObject()) {
1667 Indent(n1, "// scope needs home object\n");
1668 }
1669 if (inner_scope_calls_eval_) Indent(n1, "// inner scope calls 'eval'\n");
1670 if (is_declaration_scope()) {
1671 DeclarationScope* scope = AsDeclarationScope();
1672 if (scope->was_lazily_parsed()) Indent(n1, "// lazily parsed\n");
1673 if (scope->ShouldEagerCompile()) Indent(n1, "// will be compiled\n");
1674 }
1675 if (num_stack_slots_ > 0) {
1676 Indent(n1, "// ");
1677 PrintF("%d stack slots\n", num_stack_slots_);
1678 }
1679 if (num_heap_slots_ > 0) {
1680 Indent(n1, "// ");
1681 PrintF("%d heap slots\n", num_heap_slots_);
1682 }
1683
1684 // Print locals.
1685 if (function != nullptr) {
1686 Indent(n1, "// function var:\n");
1687 PrintVar(n1, function);
1688 }
1689
1690 // Print temporaries.
1691 {
1692 bool printed_header = false;
1693 for (Variable* local : locals_) {
1694 if (local->mode() != VariableMode::kTemporary) continue;
1695 if (!printed_header) {
1696 printed_header = true;
1697 Indent(n1, "// temporary vars:\n");
1698 }
1699 PrintVar(n1, local);
1700 }
1701 }
1702
1703 if (variables_.occupancy() > 0) {
1704 PrintMap(n1, "// local vars:\n", &variables_, true, function);
1705 PrintMap(n1, "// dynamic vars:\n", &variables_, false, function);
1706 }
1707
1708 if (is_class_scope()) {
1709 ClassScope* class_scope = AsClassScope();
1710 if (class_scope->rare_data_ != nullptr) {
1711 PrintMap(n1, "// private name vars:\n",
1712 &(class_scope->rare_data_->private_name_map), true, function);
1713 }
1714 }
1715
1716 // Print inner scopes (disable by providing negative n).
1717 if (n >= 0) {
1718 for (Scope* scope = inner_scope_; scope != nullptr;
1719 scope = scope->sibling_) {
1720 PrintF("\n");
1721 scope->Print(n1);
1722 }
1723 }
1724
1725 Indent(n0, "}\n");
1726}
1727
1728void Scope::CheckScopePositions() {
1729 this->ForEach([](Scope* scope) {
1730 // Visible leaf scopes must have real positions.
1731 if (!scope->is_hidden() && scope->inner_scope_ == nullptr) {
1732 DCHECK_NE(kNoSourcePosition, scope->start_position());
1733 DCHECK_NE(kNoSourcePosition, scope->end_position());
1734 }
1735 return Iteration::kDescend;
1736 });
1737}
1738
1739void Scope::CheckZones() {
1740 DCHECK(!needs_migration_);
1741 this->ForEach([](Scope* scope) {
1742 if (WasLazilyParsed(scope)) {
1743 DCHECK_NULL(scope->zone());
1744 DCHECK_NULL(scope->inner_scope_);
1745 return Iteration::kContinue;
1746 }
1747 return Iteration::kDescend;
1748 });
1749}
1750#endif // DEBUG
1751
1752Variable* Scope::NonLocal(const AstRawString* name, VariableMode mode) {
1753 // Declare a new non-local.
1754 DCHECK(IsDynamicVariableMode(mode));
1755 bool was_added;
1756 Variable* var =
1757 variables_.Declare(zone(), this, name, mode, NORMAL_VARIABLE,
1758 kCreatedInitialized, kNotAssigned, &was_added);
1759 // Allocate it by giving it a dynamic lookup.
1760 var->AllocateTo(VariableLocation::LOOKUP, -1);
1761 return var;
1762}
1763
1764// static
1765template <Scope::ScopeLookupMode mode>
1766Variable* Scope::Lookup(VariableProxy* proxy, Scope* scope,
1767 Scope* outer_scope_end, Scope* entry_point,
1768 bool force_context_allocation) {
1769 if (mode == kDeserializedScope) {
1770 Variable* var = entry_point->variables_.Lookup(proxy->raw_name());
1771 if (var != nullptr) return var;
1772 }
1773
1774 while (true) {
1775 DCHECK_IMPLIES(mode == kParsedScope, !scope->is_debug_evaluate_scope_);
1776 // Short-cut: whenever we find a debug-evaluate scope, just look everything
1777 // up dynamically. Debug-evaluate doesn't properly create scope info for the
1778 // lookups it does. It may not have a valid 'this' declaration, and anything
1779 // accessed through debug-evaluate might invalidly resolve to
1780 // stack-allocated variables.
1781 // TODO(yangguo): Remove once debug-evaluate creates proper ScopeInfo for
1782 // the scopes in which it's evaluating.
1783 if (mode == kDeserializedScope &&
1784 V8_UNLIKELY(scope->is_debug_evaluate_scope_)) {
1785 return entry_point->NonLocal(proxy->raw_name(), VariableMode::kDynamic);
1786 }
1787
1788 // Try to find the variable in this scope.
1789 Variable* var = mode == kParsedScope ? scope->LookupLocal(proxy->raw_name())
1790 : scope->LookupInScopeInfo(
1791 proxy->raw_name(), entry_point);
1792
1793 // We found a variable and we are done. (Even if there is an 'eval' in this
1794 // scope which introduces the same variable again, the resulting variable
1795 // remains the same.)
1796 if (var != nullptr) {
1797 if (mode == kParsedScope && force_context_allocation &&
1798 !var->is_dynamic()) {
1799 var->ForceContextAllocation();
1800 }
1801 return var;
1802 }
1803
1804 if (scope->outer_scope_ == outer_scope_end) break;
1805
1806 DCHECK(!scope->is_script_scope());
1807 if (V8_UNLIKELY(scope->is_with_scope())) {
1808 return LookupWith(proxy, scope, outer_scope_end, entry_point,
1809 force_context_allocation);
1810 }
1811 if (V8_UNLIKELY(scope->is_declaration_scope() &&
1812 scope->AsDeclarationScope()->calls_sloppy_eval())) {
1813 return LookupSloppyEval(proxy, scope, outer_scope_end, entry_point,
1814 force_context_allocation);
1815 }
1816
1817 force_context_allocation |= scope->is_function_scope();
1818 scope = scope->outer_scope_;
1819 // TODO(verwaest): Separate through AnalyzePartially.
1820 if (mode == kParsedScope && !scope->scope_info_.is_null()) {
1821 return Lookup<kDeserializedScope>(proxy, scope, outer_scope_end, scope);
1822 }
1823 }
1824
1825 // We may just be trying to find all free variables. In that case, don't
1826 // declare them in the outer scope.
1827 // TODO(marja): Separate Lookup for preparsed scopes better.
1828 if (mode == kParsedScope && !scope->is_script_scope()) {
1829 return nullptr;
1830 }
1831
1832 // No binding has been found. Declare a variable on the global object.
1833 return scope->AsDeclarationScope()->DeclareDynamicGlobal(
1834 proxy->raw_name(), NORMAL_VARIABLE,
1835 mode == kDeserializedScope ? entry_point : scope);
1836}
1837
1838template Variable* Scope::Lookup<Scope::kParsedScope>(
1839 VariableProxy* proxy, Scope* scope, Scope* outer_scope_end,
1840 Scope* entry_point, bool force_context_allocation);
1841template Variable* Scope::Lookup<Scope::kDeserializedScope>(
1842 VariableProxy* proxy, Scope* scope, Scope* outer_scope_end,
1843 Scope* entry_point, bool force_context_allocation);
1844
1845Variable* Scope::LookupWith(VariableProxy* proxy, Scope* scope,
1846 Scope* outer_scope_end, Scope* entry_point,
1847 bool force_context_allocation) {
1848 DCHECK(scope->is_with_scope());
1849
1850 Variable* var =
1851 scope->outer_scope_->scope_info_.is_null()
1852 ? Lookup<kParsedScope>(proxy, scope->outer_scope_, outer_scope_end,
1853 nullptr, force_context_allocation)
1854 : Lookup<kDeserializedScope>(proxy, scope->outer_scope_,
1855 outer_scope_end, entry_point);
1856
1857 if (var == nullptr) return var;
1858
1859 // The current scope is a with scope, so the variable binding can not be
1860 // statically resolved. However, note that it was necessary to do a lookup
1861 // in the outer scope anyway, because if a binding exists in an outer
1862 // scope, the associated variable has to be marked as potentially being
1863 // accessed from inside of an inner with scope (the property may not be in
1864 // the 'with' object).
1865 if (!var->is_dynamic() && var->IsUnallocated()) {
1866 DCHECK(!scope->already_resolved_);
1867 var->set_is_used();
1868 var->ForceContextAllocation();
1869 if (proxy->is_assigned()) var->set_maybe_assigned();
1870 }
1871 if (entry_point != nullptr) entry_point->variables_.Remove(var);
1872 Scope* target = entry_point == nullptr ? scope : entry_point;
1873 return target->NonLocal(proxy->raw_name(), VariableMode::kDynamic);
1874}
1875
1876Variable* Scope::LookupSloppyEval(VariableProxy* proxy, Scope* scope,
1877 Scope* outer_scope_end, Scope* entry_point,
1878 bool force_context_allocation) {
1879 DCHECK(scope->is_declaration_scope() &&
1880 scope->AsDeclarationScope()->calls_sloppy_eval());
1881
1882 // If we're compiling eval, it's possible that the outer scope is the first
1883 // ScopeInfo-backed scope.
1884 Scope* entry = entry_point == nullptr ? scope->outer_scope_ : entry_point;
1885 Variable* var =
1886 scope->outer_scope_->scope_info_.is_null()
1887 ? Lookup<kParsedScope>(proxy, scope->outer_scope_, outer_scope_end,
1888 nullptr, force_context_allocation)
1889 : Lookup<kDeserializedScope>(proxy, scope->outer_scope_,
1890 outer_scope_end, entry);
1891 if (var == nullptr) return var;
1892
1893 // A variable binding may have been found in an outer scope, but the current
1894 // scope makes a sloppy 'eval' call, so the found variable may not be the
1895 // correct one (the 'eval' may introduce a binding with the same name). In
1896 // that case, change the lookup result to reflect this situation. Only
1897 // scopes that can host var bindings (declaration scopes) need be considered
1898 // here (this excludes block and catch scopes), and variable lookups at
1899 // script scope are always dynamic.
1900 if (var->IsGlobalObjectProperty()) {
1901 Scope* target = entry_point == nullptr ? scope : entry_point;
1902 return target->NonLocal(proxy->raw_name(), VariableMode::kDynamicGlobal);
1903 }
1904
1905 if (var->is_dynamic()) return var;
1906
1907 Variable* invalidated = var;
1908 if (entry_point != nullptr) entry_point->variables_.Remove(invalidated);
1909
1910 Scope* target = entry_point == nullptr ? scope : entry_point;
1911 var = target->NonLocal(proxy->raw_name(), VariableMode::kDynamicLocal);
1912 var->set_local_if_not_shadowed(invalidated);
1913
1914 return var;
1915}
1916
1917void Scope::ResolveVariable(ParseInfo* info, VariableProxy* proxy) {
1918 DCHECK(info->script_scope()->is_script_scope());
1919 DCHECK(!proxy->is_resolved());
1920 Variable* var = Lookup<kParsedScope>(proxy, this, nullptr);
1921 DCHECK_NOT_NULL(var);
1922 ResolveTo(info, proxy, var);
1923}
1924
1925namespace {
1926
1927void SetNeedsHoleCheck(Variable* var, VariableProxy* proxy) {
1928 proxy->set_needs_hole_check();
1929 var->ForceHoleInitialization();
1930}
1931
1932void UpdateNeedsHoleCheck(Variable* var, VariableProxy* proxy, Scope* scope) {
1933 if (var->mode() == VariableMode::kDynamicLocal) {
1934 // Dynamically introduced variables never need a hole check (since they're
1935 // VariableMode::kVar bindings, either from var or function declarations),
1936 // but the variable they shadow might need a hole check, which we want to do
1937 // if we decide that no shadowing variable was dynamically introoduced.
1938 DCHECK_EQ(kCreatedInitialized, var->initialization_flag());
1939 return UpdateNeedsHoleCheck(var->local_if_not_shadowed(), proxy, scope);
1940 }
1941
1942 if (var->initialization_flag() == kCreatedInitialized) return;
1943
1944 // It's impossible to eliminate module import hole checks here, because it's
1945 // unknown at compilation time whether the binding referred to in the
1946 // exporting module itself requires hole checks.
1947 if (var->location() == VariableLocation::MODULE && !var->IsExport()) {
1948 return SetNeedsHoleCheck(var, proxy);
1949 }
1950
1951 // Check if the binding really needs an initialization check. The check
1952 // can be skipped in the following situation: we have a VariableMode::kLet or
1953 // VariableMode::kConst binding, both the Variable and the VariableProxy have
1954 // the same declaration scope (i.e. they are both in global code, in the same
1955 // function or in the same eval code), the VariableProxy is in the source
1956 // physically located after the initializer of the variable, and that the
1957 // initializer cannot be skipped due to a nonlinear scope.
1958 //
1959 // The condition on the closure scopes is a conservative check for
1960 // nested functions that access a binding and are called before the
1961 // binding is initialized:
1962 // function() { f(); let x = 1; function f() { x = 2; } }
1963 //
1964 // The check cannot be skipped on non-linear scopes, namely switch
1965 // scopes, to ensure tests are done in cases like the following:
1966 // switch (1) { case 0: let x = 2; case 1: f(x); }
1967 // The scope of the variable needs to be checked, in case the use is
1968 // in a sub-block which may be linear.
1969 if (var->scope()->GetClosureScope() != scope->GetClosureScope()) {
1970 return SetNeedsHoleCheck(var, proxy);
1971 }
1972
1973 // We should always have valid source positions.
1974 DCHECK_NE(var->initializer_position(), kNoSourcePosition);
1975 DCHECK_NE(proxy->position(), kNoSourcePosition);
1976
1977 if (var->scope()->is_nonlinear() ||
1978 var->initializer_position() >= proxy->position()) {
1979 return SetNeedsHoleCheck(var, proxy);
1980 }
1981}
1982
1983} // anonymous namespace
1984
1985void Scope::ResolveTo(ParseInfo* info, VariableProxy* proxy, Variable* var) {
1986 DCHECK_NOT_NULL(var);
1987 UpdateNeedsHoleCheck(var, proxy, this);
1988 proxy->BindTo(var);
1989}
1990
1991void Scope::ResolvePreparsedVariable(VariableProxy* proxy, Scope* scope,
1992 Scope* end) {
1993 // Resolve the variable in all parsed scopes to force context allocation.
1994 for (; scope != end; scope = scope->outer_scope_) {
1995 Variable* var = scope->LookupLocal(proxy->raw_name());
1996 if (var != nullptr) {
1997 var->set_is_used();
1998 if (!var->is_dynamic()) {
1999 var->ForceContextAllocation();
2000 if (proxy->is_assigned()) var->set_maybe_assigned();
2001 return;
2002 }
2003 }
2004 }
2005}
2006
2007bool Scope::ResolveVariablesRecursively(ParseInfo* info) {
2008 DCHECK(info->script_scope()->is_script_scope());
2009 // Lazy parsed declaration scopes are already partially analyzed. If there are
2010 // unresolved references remaining, they just need to be resolved in outer
2011 // scopes.
2012 if (WasLazilyParsed(this)) {
2013 DCHECK_EQ(variables_.occupancy(), 0);
2014 Scope* end = info->scope();
2015 // Resolve in all parsed scopes except for the script scope.
2016 if (!end->is_script_scope()) end = end->outer_scope();
2017
2018 for (VariableProxy* proxy : unresolved_list_) {
2019 ResolvePreparsedVariable(proxy, outer_scope(), end);
2020 }
2021 } else {
2022 // Resolve unresolved variables for this scope.
2023 for (VariableProxy* proxy : unresolved_list_) {
2024 ResolveVariable(info, proxy);
2025 }
2026
2027 // Resolve unresolved variables for inner scopes.
2028 for (Scope* scope = inner_scope_; scope != nullptr;
2029 scope = scope->sibling_) {
2030 if (!scope->ResolveVariablesRecursively(info)) return false;
2031 }
2032 }
2033 return true;
2034}
2035
2036bool Scope::MustAllocate(Variable* var) {
2037 DCHECK(var->location() != VariableLocation::MODULE);
2038 // Give var a read/write use if there is a chance it might be accessed
2039 // via an eval() call. This is only possible if the variable has a
2040 // visible name.
2041 if (!var->raw_name()->IsEmpty() &&
2042 (inner_scope_calls_eval_ || is_catch_scope() || is_script_scope())) {
2043 var->set_is_used();
2044 if (inner_scope_calls_eval_) var->set_maybe_assigned();
2045 }
2046 DCHECK(!var->has_forced_context_allocation() || var->is_used());
2047 // Global variables do not need to be allocated.
2048 return !var->IsGlobalObjectProperty() && var->is_used();
2049}
2050
2051
2052bool Scope::MustAllocateInContext(Variable* var) {
2053 // If var is accessed from an inner scope, or if there is a possibility
2054 // that it might be accessed from the current or an inner scope (through
2055 // an eval() call or a runtime with lookup), it must be allocated in the
2056 // context.
2057 //
2058 // Temporary variables are always stack-allocated. Catch-bound variables are
2059 // always context-allocated.
2060 if (var->mode() == VariableMode::kTemporary) return false;
2061 if (is_catch_scope()) return true;
2062 if ((is_script_scope() || is_eval_scope()) &&
2063 IsLexicalVariableMode(var->mode())) {
2064 return true;
2065 }
2066 return var->has_forced_context_allocation() || inner_scope_calls_eval_;
2067}
2068
2069
2070void Scope::AllocateStackSlot(Variable* var) {
2071 if (is_block_scope()) {
2072 outer_scope()->GetDeclarationScope()->AllocateStackSlot(var);
2073 } else {
2074 var->AllocateTo(VariableLocation::LOCAL, num_stack_slots_++);
2075 }
2076}
2077
2078
2079void Scope::AllocateHeapSlot(Variable* var) {
2080 var->AllocateTo(VariableLocation::CONTEXT, num_heap_slots_++);
2081}
2082
2083void DeclarationScope::AllocateParameterLocals() {
2084 DCHECK(is_function_scope());
2085
2086 bool has_mapped_arguments = false;
2087 if (arguments_ != nullptr) {
2088 DCHECK(!is_arrow_scope());
2089 if (MustAllocate(arguments_) && !has_arguments_parameter_) {
2090 // 'arguments' is used and does not refer to a function
2091 // parameter of the same name. If the arguments object
2092 // aliases formal parameters, we conservatively allocate
2093 // them specially in the loop below.
2094 has_mapped_arguments =
2095 GetArgumentsType() == CreateArgumentsType::kMappedArguments;
2096 } else {
2097 // 'arguments' is unused. Tell the code generator that it does not need to
2098 // allocate the arguments object by nulling out arguments_.
2099 arguments_ = nullptr;
2100 }
2101 }
2102
2103 // The same parameter may occur multiple times in the parameters_ list.
2104 // If it does, and if it is not copied into the context object, it must
2105 // receive the highest parameter index for that parameter; thus iteration
2106 // order is relevant!
2107 for (int i = num_parameters() - 1; i >= 0; --i) {
2108 Variable* var = params_[i];
2109 DCHECK_NOT_NULL(var);
2110 DCHECK(!has_rest_ || var != rest_parameter());
2111 DCHECK_EQ(this, var->scope());
2112 if (has_mapped_arguments) {
2113 var->set_is_used();
2114 var->set_maybe_assigned();
2115 var->ForceContextAllocation();
2116 }
2117 AllocateParameter(var, i);
2118 }
2119}
2120
2121void DeclarationScope::AllocateParameter(Variable* var, int index) {
2122 if (!MustAllocate(var)) return;
2123 if (has_forced_context_allocation_for_parameters() ||
2124 MustAllocateInContext(var)) {
2125 DCHECK(var->IsUnallocated() || var->IsContextSlot());
2126 if (var->IsUnallocated()) AllocateHeapSlot(var);
2127 } else {
2128 DCHECK(var->IsUnallocated() || var->IsParameter());
2129 if (var->IsUnallocated()) {
2130 var->AllocateTo(VariableLocation::PARAMETER, index);
2131 }
2132 }
2133}
2134
2135void DeclarationScope::AllocateReceiver() {
2136 if (!has_this_declaration()) return;
2137 DCHECK_NOT_NULL(receiver());
2138 DCHECK_EQ(receiver()->scope(), this);
2139 AllocateParameter(receiver(), -1);
2140}
2141
2142void Scope::AllocateNonParameterLocal(Variable* var) {
2143 DCHECK_EQ(var->scope(), this);
2144 if (var->IsUnallocated() && MustAllocate(var)) {
2145 if (MustAllocateInContext(var)) {
2146 AllocateHeapSlot(var);
2147 DCHECK_IMPLIES(is_catch_scope(),
2148 var->index() == Context::THROWN_OBJECT_INDEX);
2149 } else {
2150 AllocateStackSlot(var);
2151 }
2152 }
2153}
2154
2155void Scope::AllocateNonParameterLocalsAndDeclaredGlobals() {
2156 for (Variable* local : locals_) {
2157 AllocateNonParameterLocal(local);
2158 }
2159
2160 if (is_declaration_scope()) {
2161 AsDeclarationScope()->AllocateLocals();
2162 }
2163}
2164
2165void DeclarationScope::AllocateLocals() {
2166 // For now, function_ must be allocated at the very end. If it gets
2167 // allocated in the context, it must be the last slot in the context,
2168 // because of the current ScopeInfo implementation (see
2169 // ScopeInfo::ScopeInfo(FunctionScope* scope) constructor).
2170 if (function_ != nullptr && MustAllocate(function_)) {
2171 AllocateNonParameterLocal(function_);
2172 } else {
2173 function_ = nullptr;
2174 }
2175
2176 DCHECK(!has_rest_ || !MustAllocate(rest_parameter()) ||
2177 !rest_parameter()->IsUnallocated());
2178
2179 if (new_target_ != nullptr && !MustAllocate(new_target_)) {
2180 new_target_ = nullptr;
2181 }
2182
2183 NullifyRareVariableIf(RareVariable::kThisFunction,
2184 [=](Variable* var) { return !MustAllocate(var); });
2185}
2186
2187void ModuleScope::AllocateModuleVariables() {
2188 for (const auto& it : module()->regular_imports()) {
2189 Variable* var = LookupLocal(it.first);
2190 var->AllocateTo(VariableLocation::MODULE, it.second->cell_index);
2191 DCHECK(!var->IsExport());
2192 }
2193
2194 for (const auto& it : module()->regular_exports()) {
2195 Variable* var = LookupLocal(it.first);
2196 var->AllocateTo(VariableLocation::MODULE, it.second->cell_index);
2197 DCHECK(var->IsExport());
2198 }
2199}
2200
2201void Scope::AllocateVariablesRecursively() {
2202 this->ForEach([](Scope* scope) -> Iteration {
2203 DCHECK(!scope->already_resolved_);
2204 if (WasLazilyParsed(scope)) return Iteration::kContinue;
2205 DCHECK_EQ(Context::MIN_CONTEXT_SLOTS, scope->num_heap_slots_);
2206
2207 // Allocate variables for this scope.
2208 // Parameters must be allocated first, if any.
2209 if (scope->is_declaration_scope()) {
2210 if (scope->is_function_scope()) {
2211 scope->AsDeclarationScope()->AllocateParameterLocals();
2212 }
2213 scope->AsDeclarationScope()->AllocateReceiver();
2214 }
2215 scope->AllocateNonParameterLocalsAndDeclaredGlobals();
2216
2217 // Force allocation of a context for this scope if necessary. For a 'with'
2218 // scope and for a function scope that makes an 'eval' call we need a
2219 // context, even if no local variables were statically allocated in the
2220 // scope. Likewise for modules and function scopes representing asm.js
2221 // modules. Also force a context, if the scope is stricter than the outer
2222 // scope.
2223 bool must_have_context =
2224 scope->is_with_scope() || scope->is_module_scope() ||
2225 scope->IsAsmModule() || scope->ForceContextForLanguageMode() ||
2226 (scope->is_function_scope() &&
2227 scope->AsDeclarationScope()->calls_sloppy_eval()) ||
2228 (scope->is_block_scope() && scope->is_declaration_scope() &&
2229 scope->AsDeclarationScope()->calls_sloppy_eval());
2230
2231 // If we didn't allocate any locals in the local context, then we only
2232 // need the minimal number of slots if we must have a context.
2233 if (scope->num_heap_slots_ == Context::MIN_CONTEXT_SLOTS &&
2234 !must_have_context) {
2235 scope->num_heap_slots_ = 0;
2236 }
2237
2238 // Allocation done.
2239 DCHECK(scope->num_heap_slots_ == 0 ||
2240 scope->num_heap_slots_ >= Context::MIN_CONTEXT_SLOTS);
2241 return Iteration::kDescend;
2242 });
2243}
2244
2245void Scope::AllocateScopeInfosRecursively(Isolate* isolate,
2246 MaybeHandle<ScopeInfo> outer_scope) {
2247 DCHECK(scope_info_.is_null());
2248 MaybeHandle<ScopeInfo> next_outer_scope = outer_scope;
2249
2250 if (NeedsScopeInfo()) {
2251 scope_info_ = ScopeInfo::Create(isolate, zone(), this, outer_scope);
2252 // The ScopeInfo chain should mirror the context chain, so we only link to
2253 // the next outer scope that needs a context.
2254 if (NeedsContext()) next_outer_scope = scope_info_;
2255 }
2256
2257 // Allocate ScopeInfos for inner scopes.
2258 for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) {
2259 if (!scope->is_function_scope() ||
2260 scope->AsDeclarationScope()->ShouldEagerCompile()) {
2261 scope->AllocateScopeInfosRecursively(isolate, next_outer_scope);
2262 }
2263 }
2264}
2265
2266// static
2267void DeclarationScope::AllocateScopeInfos(ParseInfo* info, Isolate* isolate) {
2268 DeclarationScope* scope = info->literal()->scope();
2269 if (!scope->scope_info_.is_null()) return; // Allocated by outer function.
2270
2271 MaybeHandle<ScopeInfo> outer_scope;
2272 if (scope->outer_scope_ != nullptr) {
2273 outer_scope = scope->outer_scope_->scope_info_;
2274 }
2275
2276 scope->AllocateScopeInfosRecursively(isolate, outer_scope);
2277
2278 // The debugger expects all shared function infos to contain a scope info.
2279 // Since the top-most scope will end up in a shared function info, make sure
2280 // it has one, even if it doesn't need a scope info.
2281 // TODO(jochen|yangguo): Remove this requirement.
2282 if (scope->scope_info_.is_null()) {
2283 scope->scope_info_ =
2284 ScopeInfo::Create(isolate, scope->zone(), scope, outer_scope);
2285 }
2286
2287 // Ensuring that the outer script scope has a scope info avoids having
2288 // special case for native contexts vs other contexts.
2289 if (info->script_scope() && info->script_scope()->scope_info_.is_null()) {
2290 info->script_scope()->scope_info_ =
2291 handle(ScopeInfo::Empty(isolate), isolate);
2292 }
2293}
2294
2295int Scope::ContextLocalCount() const {
2296 if (num_heap_slots() == 0) return 0;
2297 Variable* function =
2298 is_function_scope() ? AsDeclarationScope()->function_var() : nullptr;
2299 bool is_function_var_in_context =
2300 function != nullptr && function->IsContextSlot();
2301 return num_heap_slots() - Context::MIN_CONTEXT_SLOTS -
2302 (is_function_var_in_context ? 1 : 0);
2303}
2304
2305Variable* ClassScope::DeclarePrivateName(const AstRawString* name,
2306 bool* was_added) {
2307 Variable* result = EnsureRareData()->private_name_map.Declare(
2308 zone(), this, name, VariableMode::kConst, NORMAL_VARIABLE,
2309 InitializationFlag::kNeedsInitialization,
2310 MaybeAssignedFlag::kMaybeAssigned, was_added);
2311 if (*was_added) {
2312 locals_.Add(result);
2313 }
2314 result->ForceContextAllocation();
2315 return result;
2316}
2317
2318Variable* ClassScope::LookupLocalPrivateName(const AstRawString* name) {
2319 if (rare_data_ == nullptr) {
2320 return nullptr;
2321 }
2322 return rare_data_->private_name_map.Lookup(name);
2323}
2324
2325UnresolvedList::Iterator ClassScope::GetUnresolvedPrivateNameTail() {
2326 if (rare_data_ == nullptr) {
2327 return UnresolvedList::Iterator();
2328 }
2329 return rare_data_->unresolved_private_names.end();
2330}
2331
2332void ClassScope::ResetUnresolvedPrivateNameTail(UnresolvedList::Iterator tail) {
2333 if (rare_data_ == nullptr ||
2334 rare_data_->unresolved_private_names.end() == tail) {
2335 return;
2336 }
2337
2338 bool tail_is_empty = tail == UnresolvedList::Iterator();
2339 if (tail_is_empty) {
2340 // If the saved tail is empty, the list used to be empty, so clear it.
2341 rare_data_->unresolved_private_names.Clear();
2342 } else {
2343 rare_data_->unresolved_private_names.Rewind(tail);
2344 }
2345}
2346
2347void ClassScope::MigrateUnresolvedPrivateNameTail(
2348 AstNodeFactory* ast_node_factory, UnresolvedList::Iterator tail) {
2349 if (rare_data_ == nullptr ||
2350 rare_data_->unresolved_private_names.end() == tail) {
2351 return;
2352 }
2353 UnresolvedList migrated_names;
2354
2355 // If the saved tail is empty, the list used to be empty, so we should
2356 // migrate everything after the head.
2357 bool tail_is_empty = tail == UnresolvedList::Iterator();
2358 UnresolvedList::Iterator it =
2359 tail_is_empty ? rare_data_->unresolved_private_names.begin() : tail;
2360
2361 for (; it != rare_data_->unresolved_private_names.end(); ++it) {
2362 VariableProxy* proxy = *it;
2363 VariableProxy* copy = ast_node_factory->CopyVariableProxy(proxy);
2364 migrated_names.Add(copy);
2365 }
2366
2367 // Replace with the migrated copies.
2368 if (tail_is_empty) {
2369 rare_data_->unresolved_private_names.Clear();
2370 } else {
2371 rare_data_->unresolved_private_names.Rewind(tail);
2372 }
2373 rare_data_->unresolved_private_names.Append(std::move(migrated_names));
2374}
2375
2376void ClassScope::AddUnresolvedPrivateName(VariableProxy* proxy) {
2377 // During a reparse, already_resolved_ may be true here, because
2378 // the class scope is deserialized while the function scope inside may
2379 // be new.
2380 DCHECK(!proxy->is_resolved());
2381 DCHECK(proxy->IsPrivateName());
2382 EnsureRareData()->unresolved_private_names.Add(proxy);
2383}
2384
2385Variable* ClassScope::LookupPrivateNameInScopeInfo(const AstRawString* name) {
2386 DCHECK(!scope_info_.is_null());
2387 DCHECK_NULL(LookupLocalPrivateName(name));
2388 DisallowHeapAllocation no_gc;
2389
2390 String name_handle = *name->string();
2391 VariableMode mode;
2392 InitializationFlag init_flag;
2393 MaybeAssignedFlag maybe_assigned_flag;
2394 int index = ScopeInfo::ContextSlotIndex(*scope_info_, name_handle, &mode,
2395 &init_flag, &maybe_assigned_flag);
2396 if (index < 0) {
2397 return nullptr;
2398 }
2399
2400 DCHECK_EQ(mode, VariableMode::kConst);
2401 DCHECK_EQ(init_flag, InitializationFlag::kNeedsInitialization);
2402 DCHECK_EQ(maybe_assigned_flag, MaybeAssignedFlag::kMaybeAssigned);
2403
2404 // Add the found private name to the map to speed up subsequent
2405 // lookups for the same name.
2406 bool was_added;
2407 Variable* var = DeclarePrivateName(name, &was_added);
2408 DCHECK(was_added);
2409 var->AllocateTo(VariableLocation::CONTEXT, index);
2410 return var;
2411}
2412
2413Variable* ClassScope::LookupPrivateName(VariableProxy* proxy) {
2414 DCHECK(!proxy->is_resolved());
2415
2416 for (Scope* scope = this; !scope->is_script_scope();
2417 scope = scope->outer_scope_) {
2418 if (!scope->is_class_scope()) continue; // Only search in class scopes
2419 ClassScope* class_scope = scope->AsClassScope();
2420 // Try finding it in the private name map first, if it can't be found,
2421 // try the deseralized scope info.
2422 Variable* var = class_scope->LookupLocalPrivateName(proxy->raw_name());
2423 if (var == nullptr && !class_scope->scope_info_.is_null()) {
2424 var = class_scope->LookupPrivateNameInScopeInfo(proxy->raw_name());
2425 }
2426 return var;
2427 }
2428 return nullptr;
2429}
2430
2431bool ClassScope::ResolvePrivateNames(ParseInfo* info) {
2432 if (rare_data_ == nullptr ||
2433 rare_data_->unresolved_private_names.is_empty()) {
2434 return true;
2435 }
2436
2437 UnresolvedList& list = rare_data_->unresolved_private_names;
2438 for (VariableProxy* proxy : list) {
2439 Variable* var = LookupPrivateName(proxy);
2440 if (var == nullptr) {
2441 Scanner::Location loc = proxy->location();
2442 info->pending_error_handler()->ReportMessageAt(
2443 loc.beg_pos, loc.end_pos,
2444 MessageTemplate::kInvalidPrivateFieldResolution, proxy->raw_name(),
2445 kSyntaxError);
2446 return false;
2447 } else {
2448 var->set_is_used();
2449 proxy->BindTo(var);
2450 }
2451 }
2452
2453 // By now all unresolved private names should be resolved so
2454 // clear the list.
2455 list.Clear();
2456 return true;
2457}
2458
2459VariableProxy* ClassScope::ResolvePrivateNamesPartially() {
2460 if (rare_data_ == nullptr ||
2461 rare_data_->unresolved_private_names.is_empty()) {
2462 return nullptr;
2463 }
2464
2465 ClassScope* outer_class_scope =
2466 outer_scope_ == nullptr ? nullptr : outer_scope_->GetClassScope();
2467 UnresolvedList& unresolved = rare_data_->unresolved_private_names;
2468 bool has_private_names = rare_data_->private_name_map.capacity() > 0;
2469
2470 // If the class itself does not have private names, nor does it have
2471 // an outer class scope, then we are certain any private name access
2472 // inside cannot be resolved.
2473 if (!has_private_names && outer_class_scope == nullptr &&
2474 !unresolved.is_empty()) {
2475 return unresolved.first();
2476 }
2477
2478 for (VariableProxy* proxy = unresolved.first(); proxy != nullptr;) {
2479 DCHECK(proxy->IsPrivateName());
2480 VariableProxy* next = proxy->next_unresolved();
2481 unresolved.Remove(proxy);
2482 Variable* var = nullptr;
2483
2484 // If we can find private name in the current class scope, we can bind
2485 // them immediately because it's going to shadow any outer private names.
2486 if (has_private_names) {
2487 var = LookupLocalPrivateName(proxy->raw_name());
2488 if (var != nullptr) {
2489 var->set_is_used();
2490 proxy->BindTo(var);
2491 }
2492 }
2493
2494 // If the current scope does not have declared private names,
2495 // start looking from the outer class scope.
2496 if (var == nullptr && outer_class_scope != nullptr) {
2497 var = outer_class_scope->LookupPrivateName(proxy);
2498 }
2499
2500 // The outer class scopes are incomplete at this point, so even if
2501 // we have found it in any of the outer class scopes, we still delay
2502 // the resolution until this method is called for outer scopes
2503 // when they are complete.
2504 if (var != nullptr) {
2505 proxy = next;
2506 continue;
2507 }
2508
2509 // There's no outer class scope so we are certain that the variable
2510 // cannot be resolved later.
2511 if (outer_class_scope == nullptr) {
2512 return proxy;
2513 }
2514
2515 // The private name may still be found later in the outer class scope,
2516 // so push it to the outer sopce.
2517 outer_class_scope->AddUnresolvedPrivateName(proxy);
2518 proxy = next;
2519 }
2520
2521 DCHECK(unresolved.is_empty());
2522 return nullptr;
2523}
2524
2525} // namespace internal
2526} // namespace v8
2527