v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
scopes.cc
Go to the documentation of this file.
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 <optional>
8#include <set>
9
10#include "src/ast/ast.h"
11#include "src/base/logging.h"
20#include "src/parsing/parser.h"
22#include "src/zone/zone.h"
23
24namespace v8 {
25namespace internal {
26
27// ----------------------------------------------------------------------------
28// Implementation of LocalsMap
29//
30// Note: We are storing the handle locations as key values in the hash map.
31// When inserting a new variable via Declare(), we rely on the fact that
32// the handle location remains alive for the duration of that variable
33// use. Because a Variable holding a handle with the same location exists
34// this is ensured.
35
36static_assert(sizeof(VariableMap) == (sizeof(void*) + 2 * sizeof(uint32_t) +
37 sizeof(ZoneAllocationPolicy)),
38 "Empty base optimization didn't kick in for VariableMap");
39
42
45
47 const AstRawString* name, VariableMode mode,
49 InitializationFlag initialization_flag,
50 MaybeAssignedFlag maybe_assigned_flag,
51 IsStaticFlag is_static_flag, bool* was_added) {
53 // AstRawStrings are unambiguous, i.e., the same string is always represented
54 // by the same AstRawString*.
55 // FIXME(marja): fix the type of Lookup.
56 Entry* p = ZoneHashMap::LookupOrInsert(const_cast<AstRawString*>(name),
57 name->Hash());
58 *was_added = p->value == nullptr;
59 if (*was_added) {
60 // The variable has not been declared yet -> insert it.
61 DCHECK_EQ(name, p->key);
62 Variable* variable =
63 zone->New<Variable>(scope, name, mode, kind, initialization_flag,
64 maybe_assigned_flag, is_static_flag);
65 p->value = variable;
66 }
67 return reinterpret_cast<Variable*>(p->value);
68}
69
71 const AstRawString* name = var->raw_name();
72 ZoneHashMap::Remove(const_cast<AstRawString*>(name), name->Hash());
73}
74
76 const AstRawString* name = var->raw_name();
77 Entry* p = ZoneHashMap::LookupOrInsert(const_cast<AstRawString*>(name),
78 name->Hash());
80 DCHECK_EQ(name, p->key);
81 p->value = var;
82}
83
85 Entry* p = ZoneHashMap::Lookup(const_cast<AstRawString*>(name), name->Hash());
86 if (p != nullptr) {
87 DCHECK(reinterpret_cast<const AstRawString*>(p->key) == name);
89 return reinterpret_cast<Variable*>(p->value);
90 }
91 return nullptr;
92}
93
94// ----------------------------------------------------------------------------
95// Implementation of Scope
96
97Scope::Scope(Zone* zone, ScopeType scope_type)
98 : outer_scope_(nullptr), variables_(zone), scope_type_(scope_type) {
100 SetDefaults();
101}
102
103Scope::Scope(Zone* zone, Scope* outer_scope, ScopeType scope_type)
104 : outer_scope_(outer_scope), variables_(zone), scope_type_(scope_type) {
106 SetDefaults();
112}
113
115 bool was_added;
116 Variable* home_object_variable = Declare(
117 zone(), ast_value_factory->dot_home_object_string(), VariableMode::kConst,
120 DCHECK(was_added);
121 home_object_variable->set_is_used();
122 home_object_variable->ForceContextAllocation();
123 return home_object_variable;
124}
125
127 AstValueFactory* ast_value_factory) {
128 bool was_added;
129 Variable* static_home_object_variable =
130 Declare(zone(), ast_value_factory->dot_static_home_object_string(),
134 DCHECK(was_added);
135 static_home_object_variable->set_is_used();
136 static_home_object_variable->ForceContextAllocation();
137 return static_home_object_variable;
138}
139
141 AstValueFactory* ast_value_factory,
142 REPLMode repl_mode)
143 : Scope(zone, repl_mode == REPLMode::kYes ? REPL_MODE_SCOPE : SCRIPT_SCOPE),
144 function_kind_(repl_mode == REPLMode::kYes
147 params_(4, zone) {
149 SetDefaults();
150 receiver_ = DeclareDynamicGlobal(ast_value_factory->this_string(),
151 THIS_VARIABLE, this);
152}
153
155 ScopeType scope_type,
156 FunctionKind function_kind)
157 : Scope(zone, outer_scope, scope_type),
158 function_kind_(function_kind),
159 params_(4, zone) {
161 SetDefaults();
162}
163
165 AstValueFactory* avfactory)
166 : DeclarationScope(avfactory->single_parse_zone(), script_scope,
168 module_descriptor_(
169 avfactory->single_parse_zone()->New<SourceTextModuleDescriptor>(
170 avfactory->single_parse_zone())) {
172 DeclareThis(avfactory);
173}
174
176 AstValueFactory* avfactory)
177 : DeclarationScope(avfactory->single_parse_zone(), MODULE_SCOPE, avfactory,
178 scope_info),
179 module_descriptor_(nullptr) {
181}
182
183ClassScope::ClassScope(Zone* zone, Scope* outer_scope, bool is_anonymous)
184 : Scope(zone, outer_scope, CLASS_SCOPE),
185 rare_data_and_is_parsing_heritage_(nullptr),
186 is_anonymous_class_(is_anonymous) {
188}
189
190template <typename IsolateT>
191ClassScope::ClassScope(IsolateT* isolate, Zone* zone,
192 AstValueFactory* ast_value_factory,
193 Handle<ScopeInfo> scope_info)
194 : Scope(zone, CLASS_SCOPE, ast_value_factory, scope_info),
195 rare_data_and_is_parsing_heritage_(nullptr) {
197 if (scope_info->ClassScopeHasPrivateBrand()) {
198 Variable* brand =
199 LookupInScopeInfo(ast_value_factory->dot_brand_string(), this);
202 }
203
204 // If the class variable is context-allocated and its index is
205 // saved for deserialization, deserialize it.
206 if (scope_info->HasSavedClassVariable()) {
208 int index;
209 std::tie(name, index) = scope_info->SavedClassVariable();
210 DCHECK_EQ(scope_info->ContextLocalMode(index), VariableMode::kConst);
211 DCHECK_EQ(scope_info->ContextLocalInitFlag(index),
213 DCHECK_EQ(scope_info->ContextLocalMaybeAssignedFlag(index),
216 ast_value_factory,
217 ast_value_factory->GetString(name,
222 }
223
224 DCHECK(scope_info->HasPositionInfo());
225 set_start_position(scope_info->StartPosition());
226 set_end_position(scope_info->EndPosition());
227}
228template ClassScope::ClassScope(Isolate* isolate, Zone* zone,
229 AstValueFactory* ast_value_factory,
230 Handle<ScopeInfo> scope_info);
231template ClassScope::ClassScope(LocalIsolate* isolate, Zone* zone,
232 AstValueFactory* ast_value_factory,
233 Handle<ScopeInfo> scope_info);
234
235Scope::Scope(Zone* zone, ScopeType scope_type,
236 AstValueFactory* ast_value_factory, Handle<ScopeInfo> scope_info)
237 : outer_scope_(nullptr),
238 variables_(zone),
239 scope_info_(scope_info),
240 scope_type_(scope_type) {
241 DCHECK(!scope_info.is_null());
242 SetDefaults();
243#ifdef DEBUG
244 already_resolved_ = true;
245#endif
246 set_language_mode(scope_info->language_mode());
249 scope_info->PrivateNameLookupSkipsOuterClass();
250 // We don't really need to use the preparsed scope data; this is just to
251 // shorten the recursion in SetMustUsePreparseData.
253
254 if (scope_type == BLOCK_SCOPE) {
255 // Set is_block_scope_for_object_literal_ based on the existence of the home
256 // object variable (we don't store it explicitly).
257 DCHECK_NOT_NULL(ast_value_factory);
258 int home_object_index = scope_info->ContextSlotIndex(
259 ast_value_factory->dot_home_object_string()->string());
260 DCHECK_IMPLIES(home_object_index >= 0,
262 if (home_object_index >= 0) {
264 }
265 }
266}
267
269 AstValueFactory* ast_value_factory,
270 Handle<ScopeInfo> scope_info)
271 : Scope(zone, scope_type, ast_value_factory, scope_info),
272 function_kind_(scope_info->function_kind()),
273 params_(0, zone) {
275 SetDefaults();
276 if (scope_info->SloppyEvalCanExtendVars()) {
279 }
280 if (scope_info->ClassScopeHasPrivateBrand()) {
283 }
284}
285
286Scope::Scope(Zone* zone, const AstRawString* catch_variable_name,
287 MaybeAssignedFlag maybe_assigned, Handle<ScopeInfo> scope_info)
288 : outer_scope_(nullptr),
289 variables_(zone),
290 scope_info_(scope_info),
291 scope_type_(CATCH_SCOPE) {
292 SetDefaults();
293#ifdef DEBUG
294 already_resolved_ = true;
295#endif
296 // Cache the catch variable, even though it's also available via the
297 // scope_info, as the parser expects that a catch scope always has the catch
298 // variable as first and only variable.
299 bool was_added;
300 Variable* variable =
301 Declare(zone, catch_variable_name, VariableMode::kVar, NORMAL_VARIABLE,
302 kCreatedInitialized, maybe_assigned, &was_added);
303 DCHECK(was_added);
304 AllocateHeapSlot(variable);
305}
306
310#if V8_ENABLE_WEBASSEMBLY
311 is_asm_module_ = false;
312#endif // V8_ENABLE_WEBASSEMBLY
315 uses_super_property_ = false;
316 has_checked_syntax_ = false;
317 has_this_reference_ = false;
321 has_rest_ = false;
322 receiver_ = nullptr;
323 new_target_ = nullptr;
324 function_ = nullptr;
325 arguments_ = nullptr;
326 rare_data_ = nullptr;
327 should_eager_compile_ = false;
328 was_lazily_parsed_ = false;
329 is_skipped_function_ = false;
330 preparse_data_builder_ = nullptr;
332#ifdef DEBUG
333 DeclarationScope* outer_declaration_scope =
335 is_being_lazily_parsed_ =
336 outer_declaration_scope ? outer_declaration_scope->is_being_lazily_parsed_
337 : false;
338#endif
339}
340
342#ifdef DEBUG
343 scope_name_ = nullptr;
344 already_resolved_ = false;
345 needs_migration_ = false;
346#endif
347 inner_scope_ = nullptr;
348 sibling_ = nullptr;
350
353
354 calls_eval_ = false;
356 scope_nonlinear_ = false;
357 is_hidden_ = false;
359
362
363 is_declaration_scope_ = false;
364
366
368
369 needs_home_object_ = false;
371
374
375 is_wrapped_function_ = false;
376
379
381}
382
385 return !scope->is_function_scope() || scope->has_simple_parameters();
386}
387
391
392#if V8_ENABLE_WEBASSEMBLY
393void DeclarationScope::set_is_asm_module() { is_asm_module_ = true; }
394
395bool Scope::IsAsmModule() const {
396 return is_function_scope() && AsDeclarationScope()->is_asm_module();
397}
398
399bool Scope::ContainsAsmModule() const {
400 if (IsAsmModule()) return true;
401
402 // Check inner scopes recursively
403 for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) {
404 // Don't check inner functions which won't be eagerly compiled.
405 if (!scope->is_function_scope() ||
406 scope->AsDeclarationScope()->ShouldEagerCompile()) {
407 if (scope->ContainsAsmModule()) return true;
408 }
409 }
410
411 return false;
412}
413#endif // V8_ENABLE_WEBASSEMBLY
414
415template <typename IsolateT>
416Scope* Scope::DeserializeScopeChain(IsolateT* isolate, Zone* zone,
417 Tagged<ScopeInfo> scope_info,
418 DeclarationScope* script_scope,
419 AstValueFactory* ast_value_factory,
420 DeserializationMode deserialization_mode,
421 ParseInfo* parse_info) {
422 // Reconstruct the outer scope chain from a closure's context chain.
423 Scope* current_scope = nullptr;
424 Scope* innermost_scope = nullptr;
425 Scope* outer_scope = nullptr;
426 while (!scope_info.is_null()) {
427 if (scope_info->scope_type() == WITH_SCOPE) {
428 if (scope_info->IsDebugEvaluateScope()) {
430 zone->New<DeclarationScope>(zone, FUNCTION_SCOPE, ast_value_factory,
431 handle(scope_info, isolate));
433 } else {
434 // For scope analysis, debug-evaluate is equivalent to a with scope.
435 outer_scope = zone->New<Scope>(zone, WITH_SCOPE, ast_value_factory,
436 handle(scope_info, isolate));
437 }
438
439 } else if (scope_info->is_script_scope()) {
440 // If we reach a script scope, it's the outermost scope. Install the
441 // scope info of this script context onto the existing script scope to
442 // avoid nesting script scopes.
443 if (deserialization_mode == DeserializationMode::kIncludingVariables) {
444 script_scope->SetScriptScopeInfo(handle(scope_info, isolate));
445 }
446 DCHECK(!scope_info->HasOuterScopeInfo());
447 break;
448 } else if (scope_info->scope_type() == FUNCTION_SCOPE) {
450 zone, FUNCTION_SCOPE, ast_value_factory, handle(scope_info, isolate));
451#if V8_ENABLE_WEBASSEMBLY
452 if (scope_info->IsAsmModule()) {
453 outer_scope->AsDeclarationScope()->set_is_asm_module();
454 }
455#endif // V8_ENABLE_WEBASSEMBLY
456 } else if (scope_info->scope_type() == EVAL_SCOPE) {
458 zone, EVAL_SCOPE, ast_value_factory, handle(scope_info, isolate));
459 } else if (scope_info->scope_type() == CLASS_SCOPE) {
460 outer_scope = zone->New<ClassScope>(isolate, zone, ast_value_factory,
461 handle(scope_info, isolate));
462 } else if (scope_info->scope_type() == BLOCK_SCOPE) {
463 if (scope_info->is_declaration_scope()) {
465 zone, BLOCK_SCOPE, ast_value_factory, handle(scope_info, isolate));
466 } else {
467 outer_scope = zone->New<Scope>(zone, BLOCK_SCOPE, ast_value_factory,
468 handle(scope_info, isolate));
469 }
470 } else if (scope_info->scope_type() == MODULE_SCOPE) {
472 ast_value_factory);
473 if (parse_info) {
474 parse_info->set_has_module_in_scope_chain();
475 }
476 } else {
477 DCHECK_EQ(scope_info->scope_type(), CATCH_SCOPE);
478 DCHECK_EQ(scope_info->ContextLocalCount(), 1);
479 DCHECK_EQ(scope_info->ContextLocalMode(0), VariableMode::kVar);
480 DCHECK_EQ(scope_info->ContextLocalInitFlag(0), kCreatedInitialized);
481 DCHECK(scope_info->HasInlinedLocalNames());
482 Tagged<String> name = scope_info->ContextInlinedLocalName(0);
483 MaybeAssignedFlag maybe_assigned =
484 scope_info->ContextLocalMaybeAssignedFlag(0);
486 zone->New<Scope>(zone,
487 ast_value_factory->GetString(
488 name, SharedStringAccessGuardIfNeeded(isolate)),
489 maybe_assigned, handle(scope_info, isolate));
490 }
491
492 if (deserialization_mode == DeserializationMode::kScopesOnly) {
494 }
495
496 if (current_scope != nullptr) {
497 outer_scope->AddInnerScope(current_scope);
498 }
499 current_scope = outer_scope;
500 if (innermost_scope == nullptr) innermost_scope = current_scope;
501 scope_info = scope_info->HasOuterScopeInfo() ? scope_info->OuterScopeInfo()
503 }
504
505 if (deserialization_mode == DeserializationMode::kIncludingVariables) {
506 SetScriptScopeInfo(isolate, script_scope);
507 }
508
509 if (innermost_scope == nullptr) return script_scope;
510 script_scope->AddInnerScope(current_scope);
511 return innermost_scope;
512}
513
514template <typename IsolateT>
515void Scope::SetScriptScopeInfo(IsolateT* isolate,
516 DeclarationScope* script_scope) {
517 if (script_scope->scope_info_.is_null()) {
518 script_scope->SetScriptScopeInfo(
519 isolate->factory()->global_this_binding_scope_info());
520 }
521}
522
526 script_scope);
530 script_scope);
531
534 Isolate* isolate, Zone* zone, Tagged<ScopeInfo> scope_info,
535 DeclarationScope* script_scope, AstValueFactory* ast_value_factory,
536 DeserializationMode deserialization_mode, ParseInfo* parse_info);
539 LocalIsolate* isolate, Zone* zone, Tagged<ScopeInfo> scope_info,
540 DeclarationScope* script_scope, AstValueFactory* ast_value_factory,
541 DeserializationMode deserialization_mode, ParseInfo* parse_info);
542
544 // Here and below: if an attacker corrupts the in-sandox SFI::unique_id or
545 // fields of a Script object, we can get confused about which type of scope
546 // we're operating on. These CHECKs defend against that.
548 return static_cast<DeclarationScope*>(this);
549}
550
553 return static_cast<const DeclarationScope*>(this);
554}
555
558 return static_cast<ModuleScope*>(this);
559}
560
563 return static_cast<const ModuleScope*>(this);
564}
565
568 return static_cast<ClassScope*>(this);
569}
570
573 return static_cast<const ClassScope*>(this);
574}
575
577 SloppyBlockFunctionStatement* sloppy_block_function) {
578 sloppy_block_functions_.Add(sloppy_block_function);
579}
580
585 DCHECK(HasSimpleParameters() || is_block_scope() || is_being_lazily_parsed_);
586 DCHECK_EQ(factory == nullptr, is_being_lazily_parsed_);
587
588 if (sloppy_block_functions_.is_empty()) return;
589
590 // In case of complex parameters the current scope is the body scope and the
591 // parameters are stored in the outer scope.
592 Scope* parameter_scope = HasSimpleParameters() ? this : outer_scope_;
593 DCHECK(parameter_scope->is_function_scope() || is_eval_scope() ||
595
597 Scope* outer_scope = decl_scope->outer_scope();
598
599 // For each variable which is used as a function declaration in a sloppy
600 // block,
601 for (SloppyBlockFunctionStatement* sloppy_block_function :
603 const AstRawString* name = sloppy_block_function->name();
604
605 // If the variable wouldn't conflict with a lexical declaration
606 // or parameter,
607
608 // Check if there's a conflict with a parameter.
609 Variable* maybe_parameter = parameter_scope->LookupLocal(name);
610 if (maybe_parameter != nullptr && maybe_parameter->is_parameter()) {
611 continue;
612 }
613
614 // Check if there's a conflict with a lexical declaration
615 Scope* query_scope = sloppy_block_function->scope()->outer_scope();
616 bool should_hoist = true;
617
618 // It is not sufficient to just do a Lookup on query_scope: for
619 // example, that does not prevent hoisting of the function in
620 // `{ let e; try {} catch (e) { function e(){} } }`
621 //
622 // Don't use a generic cache scope, as the cache scope would be the outer
623 // scope and we terminate the iteration there anyway.
624 do {
625 Variable* var = query_scope->LookupInScopeOrScopeInfo(name, query_scope);
626 if (var != nullptr && IsLexicalVariableMode(var->mode()) &&
627 !var->is_sloppy_block_function()) {
628 should_hoist = false;
629 break;
630 }
631 query_scope = query_scope->outer_scope();
632 } while (query_scope != outer_scope);
633
634 if (!should_hoist) continue;
635
636 if (factory) {
637 DCHECK(!is_being_lazily_parsed_);
638 int pos = sloppy_block_function->position();
639 bool ok = true;
640 bool was_added;
641 auto declaration = factory->NewVariableDeclaration(pos);
642 // Based on the preceding checks, it doesn't matter what we pass as
643 // sloppy_mode_block_scope_function_redefinition.
644 //
645 // This synthesized var for Annex B functions-in-block (FiB) may be
646 // declared multiple times for the same var scope, such as in the case of
647 // shadowed functions-in-block like the following:
648 //
649 // {
650 // function f() {}
651 // { function f() {} }
652 // }
653 //
654 // Redeclarations for vars do not create new bindings, but the
655 // redeclarations' initializers are still run. That is, shadowed FiB will
656 // result in multiple assignments to the same synthesized var.
659 Variable::DefaultInitializationFlag(VariableMode::kVar), &was_added,
660 nullptr, &ok);
661 DCHECK(ok);
662 VariableProxy* source =
663 factory->NewVariableProxy(sloppy_block_function->var());
664 VariableProxy* target = factory->NewVariableProxy(var);
665 Assignment* assignment = factory->NewAssignment(
666 sloppy_block_function->init(), target, source, pos);
668 Statement* statement = factory->NewExpressionStatement(assignment, pos);
669 sloppy_block_function->set_statement(statement);
670 } else {
671 DCHECK(is_being_lazily_parsed_);
672 bool was_added;
673 Variable* var = DeclareVariableName(name, VariableMode::kVar, &was_added);
674 if (sloppy_block_function->init() == Token::kAssign) {
675 var->SetMaybeAssigned();
676 }
677 }
678 }
679}
680
686
688 RCS_SCOPE(info->runtime_call_stats(),
689 RuntimeCallCounterId::kCompileScopeAnalysis,
690 RuntimeCallStats::kThreadSpecific);
691 DCHECK_NOT_NULL(info->literal());
692 DeclarationScope* scope = info->literal()->scope();
693
694 std::optional<AllowHandleDereference> allow_deref;
695#ifdef DEBUG
696 if (scope->outer_scope() && !scope->outer_scope()->scope_info_.is_null()) {
697 allow_deref.emplace();
698 }
699#endif
700
701 if (scope->is_eval_scope() && is_sloppy(scope->language_mode())) {
702 AstNodeFactory factory(info->ast_value_factory(), info->zone());
703 scope->HoistSloppyBlockFunctions(&factory);
704 }
705
706 // We are compiling one of four cases:
707 // 1) top-level code,
708 // 2) a function/eval/module on the top-level
709 // 4) a class member initializer function scope
710 // 3) 4 function/eval in a scope that was already resolved.
711 DCHECK(scope->is_script_scope() || scope->outer_scope()->is_script_scope() ||
712 scope->outer_scope()->already_resolved_);
713
714 // The outer scope is never lazy.
716
719 allow_deref.emplace();
720 info->consumed_preparse_data()->RestoreScopeAllocationData(
721 scope, info->ast_value_factory(), info->zone());
722 }
723
724 if (!scope->AllocateVariables(info)) return false;
726
727#ifdef DEBUG
728 if (v8_flags.print_scopes) {
729 PrintF("Global scope:\n");
730 scope->Print();
731 }
732 scope->CheckScopePositions();
733 scope->CheckZones();
734#endif
735
736 return true;
737}
738
741
742 bool derived_constructor = IsDerivedConstructor(function_kind_);
743
745 this, ast_value_factory->this_string(),
746 derived_constructor ? VariableMode::kConst : VariableMode::kVar,
748 derived_constructor ? kNeedsInitialization : kCreatedInitialized,
750 // Derived constructors have hole checks when calling super. Mark the 'this'
751 // variable as having hole initialization forced so that TDZ elision analysis
752 // applies and numbers the variable.
753 if (derived_constructor) {
755 Variable::kHasHoleCheckUseInUnknownScope);
756 }
757 locals_.Add(receiver_);
758}
759
763
764 // Because when arguments_ is not nullptr, we already declared
765 // "arguments exotic object" to add it into parameters before
766 // impl()->InsertShadowingVarBindingInitializers, so here
767 // only declare "arguments exotic object" when arguments_
768 // is nullptr
769 if (arguments_ != nullptr) {
770 return;
771 }
772
773 // Declare 'arguments' variable which exists in all non arrow functions. Note
774 // that it might never be accessed, in which case it won't be allocated during
775 // variable allocation.
776 bool was_added = false;
777
778 arguments_ =
779 Declare(zone(), ast_value_factory->arguments_string(), VariableMode::kVar,
781 // According to ES#sec-functiondeclarationinstantiation step 18
782 // we should set argumentsObjectNeeded to false if has lexical
783 // declared arguments only when hasParameterExpressions is false
784 if (!was_added && IsLexicalVariableMode(arguments_->mode()) &&
786 // Check if there's lexically declared variable named arguments to avoid
787 // redeclaration. See ES#sec-functiondeclarationinstantiation, step 20.
788 arguments_ = nullptr;
789 }
790}
791
793 AstValueFactory* ast_value_factory) {
796
797 DeclareThis(ast_value_factory);
798 bool was_added;
799 new_target_ = Declare(zone(), ast_value_factory->new_target_string(),
801 kCreatedInitialized, kNotAssigned, &was_added);
802 DCHECK(was_added);
803
807 zone(), ast_value_factory->this_function_string(), VariableMode::kConst,
809 DCHECK(was_added);
810 }
811}
812
814 Scope* cache) {
816 if (cache == nullptr) {
818 cache = this;
819 } else if (function_ != nullptr) {
820 return function_;
821 }
822 DCHECK(this->IsOuterScopeOf(cache));
823 DCHECK_NULL(cache->variables_.Lookup(name));
829 cache->NonLocal(name, VariableMode::kDynamic);
830 } else {
831 cache->variables_.Add(function_);
832 }
833 return function_;
834}
835
846
849#ifdef DEBUG
850 DCHECK_NE(sibling_, this);
851#endif
852
853 if (variables_.occupancy() > 0 ||
855 AsDeclarationScope()->sloppy_eval_can_extend_vars())) {
856 return this;
857 }
858
860
861 // Remove this scope from outer scope.
863
864 // Reparent inner scopes.
865 if (inner_scope_ != nullptr) {
866 Scope* scope = inner_scope_;
867 scope->outer_scope_ = outer_scope();
868 while (scope->sibling_ != nullptr) {
869 scope = scope->sibling_;
870 scope->outer_scope_ = outer_scope();
871 }
874 inner_scope_ = nullptr;
875 }
876
877 // Move unresolved variables
878 if (!unresolved_list_.is_empty()) {
881 }
882
884
885 // No need to propagate sloppy_eval_can_extend_vars_, since if it was relevant
886 // to this scope we would have had to bail out at the top.
888 !AsDeclarationScope()->sloppy_eval_can_extend_vars());
889
890 // This block does not need a context.
891 num_heap_slots_ = 0;
892
893 // Mark scope as removed by making it its own sibling.
894#ifdef DEBUG
895 sibling_ = this;
896#endif
897
898 return nullptr;
899}
900
902 DCHECK(!already_resolved_);
903 // Temporaries are only placed in ClosureScopes.
904 DCHECK_EQ(GetClosureScope(), this);
905 locals_.Add(var);
906}
907
909 DCHECK_EQ(new_parent, outer_scope_->inner_scope_);
910 DCHECK_EQ(new_parent->outer_scope_, outer_scope_);
911 DCHECK_EQ(new_parent, new_parent->GetClosureScope());
912 DCHECK_NULL(new_parent->inner_scope_);
913 DCHECK(new_parent->unresolved_list_.is_empty());
914 Scope* inner_scope = new_parent->sibling_;
918 inner_scope->outer_scope_ = new_parent;
920 new_parent->inner_scope_calls_eval_ = true;
921 }
922 DCHECK_NE(inner_scope, new_parent);
923 }
924 inner_scope->outer_scope_ = new_parent;
926 new_parent->inner_scope_calls_eval_ = true;
927 }
928 new_parent->inner_scope_ = new_parent->sibling_;
929 inner_scope->sibling_ = nullptr;
930 // Reset the sibling rather than the inner_scope_ since we
931 // want to keep new_parent there.
932 new_parent->sibling_ = top_inner_scope_;
933 }
934
937
938 // Move temporaries allocated for complex parameter initializers.
940 for (auto it = top_local_; it != outer_closure->locals()->end(); ++it) {
941 Variable* local = *it;
943 DCHECK_EQ(local->scope(), local->scope()->GetClosureScope());
944 DCHECK_NE(local->scope(), new_parent);
945 local->set_scope(new_parent);
946 }
947 new_parent->locals_.MoveTail(outer_closure->locals(), top_local_);
948 outer_closure->locals_.Rewind(top_local_);
949
950 // Move eval calls since Snapshot's creation into new_parent.
952 new_parent->RecordEvalCall();
953 outer_scope_->calls_eval_ = false;
955 }
956}
957
959 DCHECK(!scope_info_.is_null());
960 DCHECK(this->IsOuterScopeOf(cache));
961 DCHECK_NULL(cache->variables_.Lookup(name));
963
964 Tagged<String> name_handle = *name->string();
966 // The Scope is backed up by ScopeInfo. This means it cannot operate in a
967 // heap-independent mode, and all strings must be internalized immediately. So
968 // it's ok to get the Handle<String> here.
969 bool found = false;
970
971 VariableLocation location;
972 int index;
973 VariableLookupResult lookup_result;
974
975 {
976 location = VariableLocation::CONTEXT;
977 index = scope_info->ContextSlotIndex(name->string(), &lookup_result);
978 found = index >= 0;
979 }
980
981 if (!found && is_module_scope()) {
982 location = VariableLocation::MODULE;
983 index = scope_info->ModuleIndex(name_handle, &lookup_result.mode,
984 &lookup_result.init_flag,
985 &lookup_result.maybe_assigned_flag);
986 found = index != 0;
987 }
988
989 if (!found) {
990 index = scope_info->FunctionContextSlotIndex(name_handle);
991 if (index < 0) return nullptr; // Nowhere found.
992 Variable* var = AsDeclarationScope()->DeclareFunctionVar(name, cache);
995 return cache->variables_.Lookup(name);
996 }
997
998 if (!is_module_scope()) {
999 DCHECK_NE(index, scope_info->ReceiverContextSlotIndex());
1000 }
1001
1002 bool was_added;
1003 Variable* var = cache->variables_.Declare(
1004 zone(), this, name, lookup_result.mode, NORMAL_VARIABLE,
1005 lookup_result.init_flag, lookup_result.maybe_assigned_flag,
1006 IsStaticFlag::kNotStatic, &was_added);
1007 DCHECK(was_added);
1008 var->AllocateTo(location, index);
1009 return var;
1010}
1011
1013 VariableMode mode,
1014 bool is_optional, bool is_rest,
1015 AstValueFactory* ast_value_factory,
1016 int position) {
1017 DCHECK(!already_resolved_);
1019 DCHECK(!has_rest_);
1020 DCHECK(!is_optional || !is_rest);
1021 DCHECK(!is_being_lazily_parsed_);
1022 DCHECK(!was_lazily_parsed_);
1023 Variable* var;
1024 if (mode == VariableMode::kTemporary) {
1025 var = NewTemporary(name);
1026 } else {
1027 var = LookupLocal(name);
1029 DCHECK(var->is_parameter());
1030 }
1031 has_rest_ = is_rest;
1033 params_.Add(var, zone());
1034 if (!is_rest) ++num_parameters_;
1035 if (name == ast_value_factory->arguments_string()) {
1036 has_arguments_parameter_ = true;
1037 }
1038 // Params are automatically marked as used to make sure that the debugger and
1039 // function.arguments sees them.
1040 // TODO(verwaest): Reevaluate whether we always need to do this, since
1041 // strict-mode function.arguments does not make the arguments available.
1042 var->set_is_used();
1043 return var;
1044}
1045
1047 DCHECK(!already_resolved_);
1049 DCHECK(is_being_lazily_parsed_);
1050 DCHECK(!has_rest_);
1051 has_rest_ = is_rest;
1052 if (!is_rest) ++num_parameters_;
1053}
1054
1056 VariableKind kind, bool* was_added,
1057 InitializationFlag init_flag) {
1058 DCHECK(!already_resolved_);
1059 // Private methods should be declared with ClassScope::DeclarePrivateName()
1061 // This function handles VariableMode::kVar, VariableMode::kLet,
1062 // VariableMode::kConst, VariableMode::kUsing, and VariableMode::kAwaitUsing
1063 // modes. VariableMode::kDynamic variables are introduced during variable
1064 // allocation, and VariableMode::kTemporary variables are allocated via
1065 // NewTemporary().
1067 DCHECK_IMPLIES(GetDeclarationScope()->is_being_lazily_parsed(),
1068 mode == VariableMode::kVar || mode == VariableMode::kLet ||
1069 mode == VariableMode::kConst ||
1070 mode == VariableMode::kUsing ||
1072 DCHECK(!GetDeclarationScope()->was_lazily_parsed());
1073 Variable* var =
1074 Declare(zone(), name, mode, kind, init_flag, kNotAssigned, was_added);
1075
1076 // Pessimistically assume that top-level variables will be assigned and used.
1077 //
1078 // Top-level variables in a script can be accessed by other scripts or even
1079 // become global properties. While this does not apply to top-level variables
1080 // in a module (assuming they are not exported), we must still mark these as
1081 // assigned because they might be accessed by a lazily parsed top-level
1082 // function, which, for efficiency, we preparse without variable tracking.
1083 if (is_script_scope() || is_module_scope()) {
1084 if (mode != VariableMode::kConst) var->SetMaybeAssigned();
1085 var->set_is_used();
1086 }
1087
1088 return var;
1089}
1090
1092 Declaration* declaration, const AstRawString* name, int pos,
1094 bool* was_added, bool* sloppy_mode_block_scope_function_redefinition,
1095 bool* ok) {
1096 // Private methods should be declared with ClassScope::DeclarePrivateName()
1099 DCHECK(!already_resolved_);
1100 DCHECK(!GetDeclarationScope()->is_being_lazily_parsed());
1101 DCHECK(!GetDeclarationScope()->was_lazily_parsed());
1102
1103 if (mode == VariableMode::kVar && !is_declaration_scope()) {
1105 declaration, name, pos, mode, kind, init, was_added,
1106 sloppy_mode_block_scope_function_redefinition, ok);
1107 }
1112
1113 DCHECK_NOT_NULL(name);
1114
1115 Variable* var = LookupLocal(name);
1116 // Declare the variable in the declaration scope.
1117 *was_added = var == nullptr;
1118 if (V8_LIKELY(*was_added)) {
1120 mode == VariableMode::kVar)) {
1121 // In a var binding in a sloppy direct eval, pollute the enclosing scope
1122 // with this new binding by doing the following:
1123 // The proxy is bound to a lookup variable to force a dynamic declaration
1124 // using the DeclareEvalVar or DeclareEvalFunction runtime functions.
1126 var = NonLocal(name, VariableMode::kDynamic);
1127 // Mark the var as used in case anyone outside the eval wants to use it.
1128 var->set_is_used();
1129 } else {
1130 // Declare the name.
1131 var = DeclareLocal(name, mode, kind, was_added, init);
1132 DCHECK(*was_added);
1133 }
1134 } else {
1135 var->SetMaybeAssigned();
1137 IsLexicalVariableMode(var->mode()))) {
1138 // The name was declared in this scope before; check for conflicting
1139 // re-declarations. We have a conflict if either of the declarations is
1140 // not a var (in script scope, we also have to ignore legacy const for
1141 // compatibility). There is similar code in runtime.cc in the Declare
1142 // functions. The function CheckConflictingVarDeclarations checks for
1143 // var and let bindings from different scopes whereas this is a check
1144 // for conflicting declarations within the same scope. This check also
1145 // covers the special case
1146 //
1147 // function () { let x; { var x; } }
1148 //
1149 // because the var declaration is hoisted to the function scope where
1150 // 'x' is already bound.
1151 //
1152 // In harmony we treat re-declarations as early errors. See ES5 16 for a
1153 // definition of early errors.
1154 //
1155 // Allow duplicate function decls for web compat, see bug 4693.
1156 *ok = var->is_sloppy_block_function() &&
1158 *sloppy_mode_block_scope_function_redefinition = *ok;
1159 }
1160 }
1161 DCHECK_NOT_NULL(var);
1162
1163 // We add a declaration node for every declaration. The compiler
1164 // will only generate code if necessary. In particular, declarations
1165 // for inner local variables that do not represent functions won't
1166 // result in any generated code.
1167 //
1168 // This will lead to multiple declaration nodes for the
1169 // same variable if it is declared several times. This is not a
1170 // semantic issue, but it may be a performance issue since it may
1171 // lead to repeated DeclareEvalVar or DeclareEvalFunction calls.
1172 decls_.Add(declaration);
1173 declaration->set_var(var);
1174 return var;
1175}
1176
1178 VariableMode mode, bool* was_added,
1181 DCHECK(!already_resolved_);
1182 DCHECK(GetDeclarationScope()->is_being_lazily_parsed());
1183 // Private methods should be declared with ClassScope::DeclarePrivateName()
1185 if (mode == VariableMode::kVar && !is_declaration_scope()) {
1186 return GetDeclarationScope()->DeclareVariableName(name, mode, was_added,
1187 kind);
1188 }
1192 DCHECK(scope_info_.is_null());
1193
1194 // Declare the variable in the declaration scope.
1195 Variable* var = DeclareLocal(name, mode, kind, was_added);
1196 if (!*was_added) {
1197 if (IsLexicalVariableMode(mode) || IsLexicalVariableMode(var->mode())) {
1198 if (!var->is_sloppy_block_function() ||
1200 // Duplicate functions are allowed in the sloppy mode, but if this is
1201 // not a function declaration, it's an error. This is an error PreParser
1202 // hasn't previously detected.
1203 return nullptr;
1204 }
1205 // Sloppy block function redefinition.
1206 }
1207 var->SetMaybeAssigned();
1208 }
1209 var->set_is_used();
1210 return var;
1211}
1212
1214 DCHECK(!already_resolved_);
1216 DCHECK(scope_info_.is_null());
1217
1218 bool was_added;
1220 kCreatedInitialized, kNotAssigned, &was_added);
1221 DCHECK(was_added);
1222 return result;
1223}
1224
1226 // The scope is only allowed to already be resolved if we're reparsing a class
1227 // initializer. Class initializers will manually resolve these references
1228 // separate from regular variable resolution.
1229 DCHECK_IMPLIES(already_resolved_, reparsing_for_class_initializer_);
1230 DCHECK(!proxy->is_resolved());
1231 unresolved_list_.Add(proxy);
1232}
1233
1236 Scope* cache) {
1238 bool was_added;
1239 return cache->variables_.Declare(
1240 zone(), this, name, VariableMode::kDynamicGlobal, kind,
1242 // TODO(neis): Mark variable as maybe-assigned?
1243}
1244
1249
1251 return NewTemporary(name, kMaybeAssigned);
1252}
1253
1255 MaybeAssignedFlag maybe_assigned) {
1259 scope->AddLocal(var);
1260 if (maybe_assigned == kMaybeAssigned) var->SetMaybeAssigned();
1261 return var;
1262}
1263
1265 bool* allowed_catch_binding_var_redeclaration) {
1266 if (has_checked_syntax_) return nullptr;
1267 for (Declaration* decl : decls_) {
1268 // Lexical vs lexical conflicts within the same scope have already been
1269 // captured in Parser::Declare. The only conflicts we still need to check
1270 // are lexical vs nested var.
1271 if (decl->IsVariableDeclaration() &&
1272 decl->AsVariableDeclaration()->AsNested() != nullptr) {
1273 Scope* current = decl->AsVariableDeclaration()->AsNested()->scope();
1274 if (decl->var()->mode() != VariableMode::kVar &&
1275 decl->var()->mode() != VariableMode::kDynamic)
1276 continue;
1277 // Iterate through all scopes until the declaration scope.
1278 do {
1279 // There is a conflict if there exists a non-VAR binding.
1280 Variable* other_var = current->LookupLocal(decl->var()->raw_name());
1281 if (current->is_catch_scope()) {
1282 *allowed_catch_binding_var_redeclaration |= other_var != nullptr;
1283 current = current->outer_scope();
1284 continue;
1285 }
1286 if (other_var != nullptr) {
1287 DCHECK(IsLexicalVariableMode(other_var->mode()));
1288 return decl;
1289 }
1290 current = current->outer_scope();
1291 } while (current != this);
1292 }
1293 }
1294
1295 if (V8_LIKELY(!is_eval_scope())) return nullptr;
1296 if (!is_sloppy(language_mode())) return nullptr;
1297
1298 // Var declarations in sloppy eval are hoisted to the first non-eval
1299 // declaration scope. Check for conflicts between the eval scope that
1300 // declaration scope.
1302
1303 for (Declaration* decl : decls_) {
1304 if (IsLexicalVariableMode(decl->var()->mode())) continue;
1305 Scope* current = outer_scope_;
1306 // Iterate through all scopes until and including the declaration scope.
1307 do {
1308 // There is a conflict if there exists a non-VAR binding up to the
1309 // declaration scope in which this sloppy-eval runs.
1310 //
1311 // Use the current scope as the cache. We can't use the regular cache
1312 // since catch scope vars don't result in conflicts, but they will mask
1313 // variables for regular scope resolution. We have to make sure to not put
1314 // masked variables in the cache used for regular lookup.
1315 Variable* other_var =
1316 current->LookupInScopeOrScopeInfo(decl->var()->raw_name(), current);
1317 if (other_var != nullptr && !current->is_catch_scope()) {
1318 // If this is a VAR, then we know that it doesn't conflict with
1319 // anything, so we can't conflict with anything either. The one
1320 // exception is the binding variable in catch scopes, which is handled
1321 // by the if above.
1322 if (!IsLexicalVariableMode(other_var->mode())) break;
1323 return decl;
1324 }
1325 current = current->outer_scope();
1326 } while (current != end);
1327 }
1328 return nullptr;
1329}
1330
1332 VariableMode mode_limit) {
1333 const VariableMap& variables = scope->variables_;
1334 for (ZoneHashMap::Entry* p = variables.Start(); p != nullptr;
1335 p = variables.Next(p)) {
1336 const AstRawString* name = static_cast<const AstRawString*>(p->key);
1337 Variable* var = LookupLocal(name);
1338 if (var != nullptr && var->mode() <= mode_limit) return name;
1339 }
1340 return nullptr;
1341}
1342
1344 if (is_script_scope()) {
1346 return;
1347 }
1348 DCHECK(has_this_declaration());
1349 DeclareThis(ast_value_factory);
1351 receiver_->AllocateTo(VariableLocation::LOOKUP, -1);
1352 } else {
1354 scope_info_->ReceiverContextSlotIndex());
1355 }
1356}
1357
1359 // Module variables must be allocated before variable resolution
1360 // to ensure that UpdateNeedsHoleCheck() can detect import variables.
1362
1363 PrivateNameScopeIterator private_name_scope_iter(this);
1364 if (!private_name_scope_iter.Done() &&
1365 !private_name_scope_iter.GetScope()->ResolvePrivateNames(info)) {
1366 DCHECK(info->pending_error_handler()->has_pending_error());
1367 return false;
1368 }
1369
1370 if (!ResolveVariablesRecursively(info->scope())) {
1371 DCHECK(info->pending_error_handler()->has_pending_error());
1372 return false;
1373 }
1374
1375 // Don't allocate variables of preparsed scopes.
1376 if (!was_lazily_parsed()) AllocateVariablesRecursively();
1377
1378 return true;
1379}
1380
1382 return !scope_info_.is_null() && scope_info_->HasAllocatedReceiver();
1383}
1384
1386 if (is_declaration_scope() && AsDeclarationScope()->has_this_reference()) {
1387 return true;
1388 }
1389
1390 for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) {
1391 if (!scope->is_declaration_scope() ||
1392 !scope->AsDeclarationScope()->has_this_declaration()) {
1393 if (scope->HasThisReference()) return true;
1394 }
1395 }
1396
1397 return false;
1398}
1399
1401 const Scope* outer) const {
1402 // If none of the outer scopes need to decide whether to context allocate
1403 // specific variables, we can preparse inner functions without unresolved
1404 // variables. Otherwise we need to find unresolved variables to force context
1405 // allocation of the matching declarations. We can stop at the outer scope for
1406 // the parse, since context allocation of those variables is already
1407 // guaranteed to be correct.
1408 for (const Scope* s = this; s != outer; s = s->outer_scope_) {
1409 // Eval forces context allocation on all outer scopes, so we don't need to
1410 // look at those scopes. Sloppy eval makes top-level non-lexical variables
1411 // dynamic, whereas strict-mode requires context allocation.
1412 if (s->is_eval_scope()) return is_sloppy(s->language_mode());
1413 // Catch scopes force context allocation of all variables.
1414 if (s->is_catch_scope()) continue;
1415 // With scopes do not introduce variables that need allocation.
1416 if (s->is_with_scope()) continue;
1417 DCHECK(s->is_module_scope() || s->is_block_scope() ||
1418 s->is_function_scope());
1419 return false;
1420 }
1421 return true;
1422}
1423
1425 // Functions which force eager compilation and class member initializer
1426 // functions are not lazily compilable.
1427 return !force_eager_compilation_ &&
1428 !IsClassMembersInitializerFunction(function_kind());
1429}
1430
1432 int n = 0;
1433 for (const Scope* s = this; s != scope; s = s->outer_scope_) {
1434 DCHECK_NOT_NULL(s); // scope must be in the scope chain
1435 if (s->NeedsContext()) n++;
1436 }
1437 return n;
1438}
1439
1441 int result = 0;
1442 int length = 0;
1443
1444 for (const Scope* s = this; s != nullptr; s = s->outer_scope()) {
1445 if (!s->NeedsContext()) continue;
1446 length++;
1447 if (s->is_declaration_scope() &&
1448 s->AsDeclarationScope()->sloppy_eval_can_extend_vars()) {
1449 result = length;
1450 }
1451 }
1452
1453 return result;
1454}
1455
1457 Scope* scope = this;
1458 while (!scope->is_declaration_scope()) {
1459 scope = scope->outer_scope();
1460 }
1461 return scope->AsDeclarationScope();
1462}
1463
1465 Scope* scope = this;
1466 while (!scope->is_declaration_scope() || scope->is_eval_scope()) {
1467 scope = scope->outer_scope();
1468 }
1469 return scope->AsDeclarationScope();
1470}
1471
1473 const Scope* scope = this;
1474 while (!scope->is_declaration_scope() || scope->is_block_scope()) {
1475 scope = scope->outer_scope();
1476 }
1477 return scope->AsDeclarationScope();
1478}
1479
1481 Scope* scope = this;
1482 while (!scope->is_declaration_scope() || scope->is_block_scope()) {
1483 scope = scope->outer_scope();
1484 }
1485 return scope->AsDeclarationScope();
1486}
1487
1489 DCHECK(!already_resolved_);
1490 DCHECK(GetClosureScope()->ShouldEagerCompile());
1491 // The debugger expects all functions to have scope infos.
1492 // TODO(yangguo): Remove this requirement.
1493 if (is_function_scope()) return true;
1494 return NeedsContext();
1495}
1496
1500
1502 Scope* scope = this;
1503 while (!scope->is_declaration_scope() ||
1504 (!scope->is_script_scope() &&
1506 scope = scope->outer_scope();
1507 }
1508 return scope->AsDeclarationScope();
1509}
1510
1512 Scope* scope = this;
1513 while (scope != nullptr && !scope->IsConstructorScope()) {
1514 scope = scope->outer_scope();
1515 }
1516 if (scope == nullptr) {
1517 return nullptr;
1518 }
1519 DCHECK(scope->IsConstructorScope());
1520 return scope->AsDeclarationScope();
1521}
1522
1524 Scope* scope = GetReceiverScope();
1525 DCHECK(scope->is_function_scope());
1527 // "super" in arrow functions binds outside the arrow function. Arrow
1528 // functions are also never receiver scopes since they close over the
1529 // receiver.
1531 // If we find a function which doesn't bind "super" (is not a method etc.), we
1532 // know "super" here doesn't bind anywhere and we can return nullptr.
1533 if (!BindsSuper(kind)) return nullptr;
1534 // Functions that bind "super" can only syntactically occur nested inside home
1535 // object scopes (i.e. class scopes and object literal scopes), so directly
1536 // return the outer scope.
1537 Scope* outer_scope = scope->outer_scope();
1539 return outer_scope;
1540}
1541
1543 Scope* scope = this;
1544 while (!scope->is_script_scope()) {
1545 scope = scope->outer_scope();
1546 }
1547 return scope->AsDeclarationScope();
1548}
1549
1551 Scope* scope = outer_scope_;
1552 while (scope && !scope->NeedsContext()) {
1553 scope = scope->outer_scope();
1554 }
1555 return scope;
1556}
1557
1558namespace {
1559bool WasLazilyParsed(Scope* scope) {
1560 return scope->is_declaration_scope() &&
1562}
1563
1564} // namespace
1565
1566template <typename FunctionType>
1568 Scope* scope = this;
1569 while (true) {
1570 Iteration iteration = callback(scope);
1571 // Try to descend into inner scopes first.
1572 if ((iteration == Iteration::kDescend) && scope->inner_scope_ != nullptr) {
1573 scope = scope->inner_scope_;
1574 } else {
1575 // Find the next outer scope with a sibling.
1576 while (scope->sibling_ == nullptr) {
1577 if (scope == this) return;
1578 scope = scope->outer_scope_;
1579 }
1580 if (scope == this) return;
1581 scope = scope->sibling_;
1582 }
1583 }
1584}
1585
1587 return is_declaration_scope() &&
1588 IsClassConstructor(AsDeclarationScope()->function_kind());
1589}
1590
1591bool Scope::IsOuterScopeOf(Scope* other) const {
1592 Scope* scope = other;
1593 while (scope) {
1594 if (scope == this) return true;
1595 scope = scope->outer_scope();
1596 }
1597 return false;
1598}
1599
1601 AstNodeFactory* ast_node_factory,
1602 UnresolvedList* new_unresolved_list,
1603 bool maybe_in_arrowhead) {
1604 this->ForEach([max_outer_scope, ast_node_factory, new_unresolved_list,
1605 maybe_in_arrowhead](Scope* scope) {
1606 // Skip already lazily parsed scopes. This can only happen to functions
1607 // inside arrowheads.
1608 if (WasLazilyParsed(scope)) {
1609 DCHECK(max_outer_scope->is_arrow_scope());
1610 return Iteration::kContinue;
1611 }
1612
1613 for (VariableProxy* proxy = scope->unresolved_list_.first();
1614 proxy != nullptr; proxy = proxy->next_unresolved()) {
1615 if (proxy->is_removed_from_unresolved()) continue;
1616 DCHECK(!proxy->is_resolved());
1617 Variable* var =
1618 Lookup<kParsedScope>(proxy, scope, max_outer_scope->outer_scope());
1619 if (var == nullptr) {
1620 // Don't copy unresolved references to the script scope, unless it's a
1621 // reference to a private name or method. In that case keep it so we
1622 // can fail later.
1623 if (!max_outer_scope->outer_scope()->is_script_scope() ||
1624 maybe_in_arrowhead) {
1625 VariableProxy* copy = ast_node_factory->CopyVariableProxy(proxy);
1626 new_unresolved_list->Add(copy);
1627 }
1628 } else {
1629 var->set_is_used();
1630 if (proxy->is_assigned()) var->SetMaybeAssigned();
1631 }
1632 }
1633
1634 // Clear unresolved_list_ as it's in an inconsistent state.
1635 scope->unresolved_list_.Clear();
1636 return Iteration::kDescend;
1637 });
1638}
1639
1641 bool aborted) {
1643
1644 // Reset all non-trivial members.
1645 params_.DropAndClear();
1646 num_parameters_ = 0;
1647 decls_.Clear();
1648 locals_.Clear();
1649 inner_scope_ = nullptr;
1651 sloppy_block_functions_.Clear();
1652 rare_data_ = nullptr;
1653 has_rest_ = false;
1654 function_ = nullptr;
1655
1656 DCHECK_NE(zone(), ast_value_factory->single_parse_zone());
1657 // Make sure this scope and zone aren't used for allocation anymore.
1658 {
1659 // Get the zone, while variables_ is still valid
1660 Zone* zone = this->zone();
1662 zone->Reset();
1663 }
1664
1665 if (aborted) {
1666 // Prepare scope for use in the outer zone.
1667 variables_ = VariableMap(ast_value_factory->single_parse_zone());
1668 if (!IsArrowFunction(function_kind_)) {
1669 has_simple_parameters_ = true;
1670 DeclareDefaultFunctionVariables(ast_value_factory);
1671 }
1672 }
1673
1674#ifdef DEBUG
1675 needs_migration_ = false;
1676 is_being_lazily_parsed_ = false;
1677#endif
1678
1679 was_lazily_parsed_ = !aborted;
1680}
1681
1683 // Lazy non-arrow function scopes are skippable. Lazy functions are exactly
1684 // those Scopes which have their own PreparseDataBuilder object. This
1685 // logic ensures that the scope allocation data is consistent with the
1686 // skippable function data (both agree on where the lazy function boundaries
1687 // are).
1688 if (!is_function_scope()) return false;
1689 DeclarationScope* declaration_scope = AsDeclarationScope();
1690 return !declaration_scope->is_arrow_scope() &&
1691 declaration_scope->preparse_data_builder() != nullptr;
1692}
1693
1695 this->ForEach([parser](Scope* scope) {
1696 // Save preparse data for every skippable scope, unless it was already
1697 // previously saved (this can happen with functions inside arrowheads).
1698 if (scope->IsSkippableFunctionScope() &&
1701 }
1702 return Iteration::kDescend;
1703 });
1704}
1705
1707 if (preparse_data_builder_ == nullptr) return;
1708 preparse_data_builder_->SaveScopeAllocationData(this, parser);
1709}
1710
1712 AstNodeFactory* ast_node_factory,
1713 bool maybe_in_arrowhead) {
1714 DCHECK(!force_eager_compilation_);
1715 UnresolvedList new_unresolved_list;
1716
1717 // We don't need to do partial analysis for top level functions, since they
1718 // can only access values in the global scope, and we can't track assignments
1719 // for these since they're accessible across scripts.
1720 //
1721 // If the top level function has inner functions though, we do still want to
1722 // analyze those to save their preparse data.
1723 //
1724 // Additionally, functions in potential arrowheads _need_ to be analyzed, in
1725 // case they do end up being in an arrowhead and the arrow function needs to
1726 // know about context acceses. For example, in
1727 //
1728 // (a, b=function foo(){ a = 1 }) => { b(); return a}
1729 //
1730 // `function foo(){ a = 1 }` is "maybe_in_arrowhead" but still top-level when
1731 // parsed, and is re-scoped to the arrow function when that one is parsed. The
1732 // arrow function needs to know that `a` needs to be context allocated, so
1733 // that the call to `b()` correctly updates the `a` parameter.
1734 const bool is_top_level_function = outer_scope_->is_script_scope();
1735 const bool has_inner_functions = preparse_data_builder_ != nullptr &&
1736 preparse_data_builder_->HasInnerFunctions();
1737 if (maybe_in_arrowhead || !is_top_level_function || has_inner_functions) {
1738 // Try to resolve unresolved variables for this Scope and migrate those
1739 // which cannot be resolved inside. It doesn't make sense to try to resolve
1740 // them in the outer Scopes here, because they are incomplete.
1741 Scope::AnalyzePartially(this, ast_node_factory, &new_unresolved_list,
1742 maybe_in_arrowhead);
1743
1744 // Migrate function_ to the right Zone.
1745 if (function_ != nullptr) {
1746 function_ = ast_node_factory->CopyVariable(function_);
1747 }
1748
1749 SavePreparseData(parser);
1750 }
1751
1752#ifdef DEBUG
1753 if (v8_flags.print_scopes) {
1754 PrintF("Inner function scope:\n");
1755 Print();
1756 }
1757#endif
1758
1759 ResetAfterPreparsing(ast_node_factory->ast_value_factory(), false);
1760
1761 unresolved_list_ = std::move(new_unresolved_list);
1762}
1763
1765 if (!GetScriptScope()->is_repl_mode_scope()) return;
1766
1767 for (Scope* scope = this; scope != nullptr; scope = scope->outer_scope_) {
1768 for (VariableMap::Entry* p = scope->variables_.Start(); p != nullptr;
1769 p = scope->variables_.Next(p)) {
1770 Variable* var = reinterpret_cast<Variable*>(p->value);
1771 if (var->scope()->is_repl_mode_scope()) var->RewriteLocationForRepl();
1772 }
1773 }
1774}
1775
1776#ifdef DEBUG
1777namespace {
1778
1779const char* Header(ScopeType scope_type, FunctionKind function_kind,
1780 bool is_declaration_scope) {
1781 switch (scope_type) {
1782 case EVAL_SCOPE: return "eval";
1783 case FUNCTION_SCOPE:
1784 if (IsGeneratorFunction(function_kind)) return "function*";
1785 if (IsAsyncFunction(function_kind)) return "async function";
1786 if (IsArrowFunction(function_kind)) return "arrow";
1787 return "function";
1788 case MODULE_SCOPE: return "module";
1789 case REPL_MODE_SCOPE:
1790 return "repl";
1791 case SCRIPT_SCOPE: return "global";
1792 case CATCH_SCOPE: return "catch";
1793 case BLOCK_SCOPE: return is_declaration_scope ? "varblock" : "block";
1794 case CLASS_SCOPE:
1795 return "class";
1796 case WITH_SCOPE: return "with";
1797 case SHADOW_REALM_SCOPE:
1798 return "shadowrealm";
1799 }
1800 UNREACHABLE();
1801}
1802
1803void Indent(int n, const char* str) { PrintF("%*s%s", n, "", str); }
1804
1805void PrintName(const AstRawString* name) {
1806 PrintF("%.*s", name->length(), name->raw_data());
1807}
1808
1809void PrintLocation(Variable* var) {
1810 switch (var->location()) {
1812 break;
1814 PrintF("parameter[%d]", var->index());
1815 break;
1817 PrintF("local[%d]", var->index());
1818 break;
1820 PrintF("context[%d]", var->index());
1821 break;
1823 PrintF("lookup");
1824 break;
1826 PrintF("module");
1827 break;
1829 PrintF("repl global[%d]", var->index());
1830 break;
1831 }
1832}
1833
1834void PrintVar(int indent, Variable* var) {
1835 Indent(indent, VariableMode2String(var->mode()));
1836 PrintF(" ");
1837 if (var->raw_name()->IsEmpty())
1838 PrintF(".%p", reinterpret_cast<void*>(var));
1839 else
1840 PrintName(var->raw_name());
1841 PrintF("; // (%p) ", reinterpret_cast<void*>(var));
1842 PrintLocation(var);
1843 bool comma = !var->IsUnallocated();
1844 if (var->has_forced_context_allocation()) {
1845 if (comma) PrintF(", ");
1846 PrintF("forced context allocation");
1847 comma = true;
1848 }
1849 if (var->maybe_assigned() == kNotAssigned) {
1850 if (comma) PrintF(", ");
1851 PrintF("never assigned");
1852 comma = true;
1853 }
1854 if (var->initialization_flag() == kNeedsInitialization &&
1855 !var->binding_needs_init()) {
1856 if (comma) PrintF(", ");
1857 PrintF("hole initialization elided");
1858 }
1859 PrintF("\n");
1860}
1861
1862void PrintMap(int indent, const char* label, VariableMap* map, bool locals,
1863 Variable* function_var) {
1864 bool printed_label = false;
1865 for (VariableMap::Entry* p = map->Start(); p != nullptr; p = map->Next(p)) {
1866 Variable* var = reinterpret_cast<Variable*>(p->value);
1867 if (var == function_var) continue;
1868 bool local = !IsDynamicVariableMode(var->mode());
1869 if ((locals ? local : !local) &&
1870 (var->is_used() || !var->IsUnallocated())) {
1871 if (!printed_label) {
1872 Indent(indent, label);
1873 printed_label = true;
1874 }
1875 PrintVar(indent, var);
1876 }
1877 }
1878}
1879
1880} // anonymous namespace
1881
1882void DeclarationScope::PrintParameters() {
1883 PrintF(" (");
1884 for (int i = 0; i < params_.length(); i++) {
1885 if (i > 0) PrintF(", ");
1886 const AstRawString* name = params_[i]->raw_name();
1887 if (name->IsEmpty()) {
1888 PrintF(".%p", reinterpret_cast<void*>(params_[i]));
1889 } else {
1890 PrintName(name);
1891 }
1892 }
1893 PrintF(")");
1894}
1895
1896void Scope::Print(int n) {
1897 int n0 = (n > 0 ? n : 0);
1898 int n1 = n0 + 2; // indentation
1899
1900 // Print header.
1901 FunctionKind function_kind = is_function_scope()
1904 Indent(n0, Header(scope_type_, function_kind, is_declaration_scope()));
1905 if (scope_name_ != nullptr && !scope_name_->IsEmpty()) {
1906 PrintF(" ");
1907 PrintName(scope_name_);
1908 }
1909
1910 // Print parameters, if any.
1911 Variable* function = nullptr;
1912 if (is_function_scope()) {
1913 AsDeclarationScope()->PrintParameters();
1914 function = AsDeclarationScope()->function_var();
1915 }
1916
1917 PrintF(" { // (%p) (%d, %d)\n", reinterpret_cast<void*>(this),
1919 if (is_hidden()) {
1920 Indent(n1, "// is hidden\n");
1921 }
1922
1923 // Function name, if any (named function literals, only).
1924 if (function != nullptr) {
1925 Indent(n1, "// (local) function name: ");
1926 PrintName(function->raw_name());
1927 PrintF("\n");
1928 }
1929
1930 // Scope info.
1931 if (is_strict(language_mode())) {
1932 Indent(n1, "// strict mode scope\n");
1933 }
1934#if V8_ENABLE_WEBASSEMBLY
1935 if (IsAsmModule()) Indent(n1, "// scope is an asm module\n");
1936#endif // V8_ENABLE_WEBASSEMBLY
1937 if (is_declaration_scope() &&
1938 AsDeclarationScope()->sloppy_eval_can_extend_vars()) {
1939 Indent(n1, "// scope calls sloppy 'eval'\n");
1940 }
1942 Indent(n1, "// scope skips outer class for #-names\n");
1943 }
1944 if (inner_scope_calls_eval_) Indent(n1, "// inner scope calls 'eval'\n");
1945 if (is_declaration_scope()) {
1947 if (scope->was_lazily_parsed()) Indent(n1, "// lazily parsed\n");
1948 if (scope->ShouldEagerCompile()) Indent(n1, "// will be compiled\n");
1949 if (scope->needs_private_name_context_chain_recalc()) {
1950 Indent(n1, "// needs #-name context chain recalc\n");
1951 }
1952 Indent(n1, "// ");
1953 PrintF("%s\n", FunctionKind2String(scope->function_kind()));
1954 if (scope->class_scope_has_private_brand()) {
1955 Indent(n1, "// class scope has private brand\n");
1956 }
1957 }
1958 if (num_stack_slots_ > 0) {
1959 Indent(n1, "// ");
1960 PrintF("%d stack slots\n", num_stack_slots_);
1961 }
1962 if (num_heap_slots_ > 0) {
1963 Indent(n1, "// ");
1964 PrintF("%d heap slots\n", num_heap_slots_);
1965 }
1966
1967 // Print locals.
1968 if (function != nullptr) {
1969 Indent(n1, "// function var:\n");
1970 PrintVar(n1, function);
1971 }
1972
1973 // Print temporaries.
1974 {
1975 bool printed_header = false;
1976 for (Variable* local : locals_) {
1977 if (local->mode() != VariableMode::kTemporary) continue;
1978 if (!printed_header) {
1979 printed_header = true;
1980 Indent(n1, "// temporary vars:\n");
1981 }
1982 PrintVar(n1, local);
1983 }
1984 }
1985
1986 if (variables_.occupancy() > 0) {
1987 PrintMap(n1, "// local vars:\n", &variables_, true, function);
1988 PrintMap(n1, "// dynamic vars:\n", &variables_, false, function);
1989 }
1990
1991 if (is_class_scope()) {
1992 ClassScope* class_scope = AsClassScope();
1993 if (class_scope->GetRareData() != nullptr) {
1994 PrintMap(n1, "// private name vars:\n",
1995 &(class_scope->GetRareData()->private_name_map), true, function);
1996 Variable* brand = class_scope->brand();
1997 if (brand != nullptr) {
1998 Indent(n1, "// brand var:\n");
1999 PrintVar(n1, brand);
2000 }
2001 }
2002 if (class_scope->class_variable() != nullptr) {
2003 Indent(n1, "// class var");
2004 PrintF("%s%s:\n",
2005 class_scope->class_variable()->is_used() ? ", used" : ", unused",
2006 class_scope->should_save_class_variable_index()
2007 ? ", index saved"
2008 : ", index not saved");
2009 PrintVar(n1, class_scope->class_variable());
2010 }
2011 }
2012
2013 // Print inner scopes (disable by providing negative n).
2014 if (n >= 0) {
2015 for (Scope* scope = inner_scope_; scope != nullptr;
2016 scope = scope->sibling_) {
2017 PrintF("\n");
2018 scope->Print(n1);
2019 }
2020 }
2021
2022 Indent(n0, "}\n");
2023}
2024
2025void Scope::CheckScopePositions() {
2026 this->ForEach([](Scope* scope) {
2027 // Visible leaf scopes must have real positions.
2028 if (!scope->is_hidden() && scope->inner_scope_ == nullptr) {
2029 DCHECK_NE(kNoSourcePosition, scope->start_position());
2030 DCHECK_NE(kNoSourcePosition, scope->end_position());
2031 }
2032 return Iteration::kDescend;
2033 });
2034}
2035
2036void Scope::CheckZones() {
2037 DCHECK(!needs_migration_);
2038 this->ForEach([](Scope* scope) {
2039 if (WasLazilyParsed(scope)) {
2040 DCHECK_NULL(scope->zone());
2041 DCHECK_NULL(scope->inner_scope_);
2042 return Iteration::kContinue;
2043 }
2044 return Iteration::kDescend;
2045 });
2046}
2047#endif // DEBUG
2048
2050 // Declare a new non-local.
2052 bool was_added;
2053 Variable* var = variables_.Declare(zone(), this, name, mode, NORMAL_VARIABLE,
2055 IsStaticFlag::kNotStatic, &was_added);
2056 // Allocate it by giving it a dynamic lookup.
2058 return var;
2059}
2060
2062 // At the moment this is only used for looking up private names dynamically
2063 // in debug-evaluate from top-level scope.
2064 DCHECK(proxy->IsPrivateName());
2066 Variable* dynamic = NonLocal(proxy->raw_name(), VariableMode::kDynamic);
2067 proxy->BindTo(dynamic);
2068}
2069
2070// static
2071template <Scope::ScopeLookupMode mode>
2073 Scope* outer_scope_end, Scope* cache_scope,
2074 bool force_context_allocation) {
2075 // If we have already passed the cache scope in earlier recursions, we should
2076 // first quickly check if the current scope uses the cache scope before
2077 // continuing.
2078 if (mode == kDeserializedScope) {
2079 Variable* var = cache_scope->variables_.Lookup(proxy->raw_name());
2080 if (var != nullptr) return var;
2081 }
2082
2083 while (true) {
2085 // Short-cut: whenever we find a debug-evaluate scope, just look everything
2086 // up dynamically. Debug-evaluate doesn't properly create scope info for the
2087 // lookups it does. It may not have a valid 'this' declaration, and anything
2088 // accessed through debug-evaluate might invalidly resolve to
2089 // stack-allocated variables.
2090 // TODO(yangguo): Remove once debug-evaluate creates proper ScopeInfo for
2091 // the scopes in which it's evaluating.
2092 if (mode == kDeserializedScope &&
2094 return cache_scope->NonLocal(proxy->raw_name(), VariableMode::kDynamic);
2095 }
2096
2097 // Try to find the variable in this scope.
2098 Variable* var;
2099 if (mode == kParsedScope) {
2100 var = scope->LookupLocal(proxy->raw_name());
2101 } else {
2103 var = scope->LookupInScopeInfo(proxy->raw_name(), cache_scope);
2104 }
2105
2106 // We found a variable and we are done. (Even if there is an 'eval' in this
2107 // scope which introduces the same variable again, the resulting variable
2108 // remains the same.)
2109 //
2110 // For sloppy eval though, we skip dynamic variable to avoid resolving to a
2111 // variable when the variable and proxy are in the same eval execution. The
2112 // variable is not available on subsequent lazy executions of functions in
2113 // the eval, so this avoids inner functions from looking up different
2114 // variables during eager and lazy compilation.
2115 //
2116 // TODO(leszeks): Maybe we want to restrict this to e.g. lookups of a proxy
2117 // living in a different scope to the current one, or some other
2118 // optimisation.
2119 if (var != nullptr &&
2120 !(scope->is_eval_scope() && var->mode() == VariableMode::kDynamic)) {
2121 if (mode == kParsedScope && force_context_allocation &&
2122 !var->is_dynamic()) {
2124 }
2125 return var;
2126 }
2127
2128 if (scope->outer_scope_ == outer_scope_end) break;
2129
2130 DCHECK(!scope->is_script_scope());
2131 if (V8_UNLIKELY(scope->is_with_scope())) {
2132 return LookupWith(proxy, scope, outer_scope_end, cache_scope,
2133 force_context_allocation);
2134 }
2135 if (V8_UNLIKELY(
2136 scope->is_declaration_scope() &&
2138 return LookupSloppyEval(proxy, scope, outer_scope_end, cache_scope,
2139 force_context_allocation);
2140 }
2141
2142 force_context_allocation |= scope->is_function_scope();
2143 scope = scope->outer_scope_;
2144
2145 // TODO(verwaest): Separate through AnalyzePartially.
2146 if (mode == kParsedScope && !scope->scope_info_.is_null()) {
2147 DCHECK_NULL(cache_scope);
2148 return Lookup<kDeserializedScope>(proxy, scope, outer_scope_end, scope);
2149 }
2150 }
2151
2152 // We may just be trying to find all free variables. In that case, don't
2153 // declare them in the outer scope.
2154 // TODO(marja): Separate Lookup for preparsed scopes better.
2155 if (mode == kParsedScope && !scope->is_script_scope()) {
2156 return nullptr;
2157 }
2158
2159 // No binding has been found. Declare a variable on the global object.
2161 proxy->raw_name(), NORMAL_VARIABLE,
2162 mode == kDeserializedScope ? cache_scope : scope);
2163}
2164
2165template Variable* Scope::Lookup<Scope::kParsedScope>(
2166 VariableProxy* proxy, Scope* scope, Scope* outer_scope_end,
2167 Scope* cache_scope, bool force_context_allocation);
2168template Variable* Scope::Lookup<Scope::kDeserializedScope>(
2169 VariableProxy* proxy, Scope* scope, Scope* outer_scope_end,
2170 Scope* cache_scope, bool force_context_allocation);
2171
2173 Scope* outer_scope_end, Scope* cache_scope,
2174 bool force_context_allocation) {
2175 DCHECK(scope->is_with_scope());
2176
2177 Variable* var =
2178 scope->outer_scope_->scope_info_.is_null()
2179 ? Lookup<kParsedScope>(proxy, scope->outer_scope_, outer_scope_end,
2180 nullptr, force_context_allocation)
2182 outer_scope_end, cache_scope);
2183
2184 if (var == nullptr) return var;
2185
2186 // The current scope is a with scope, so the variable binding can not be
2187 // statically resolved. However, note that it was necessary to do a lookup
2188 // in the outer scope anyway, because if a binding exists in an outer
2189 // scope, the associated variable has to be marked as potentially being
2190 // accessed from inside of an inner with scope (the property may not be in
2191 // the 'with' object).
2192 if (!var->is_dynamic() && var->IsUnallocated()) {
2193 DCHECK(!scope->already_resolved_);
2194 var->set_is_used();
2196 if (proxy->is_assigned()) var->SetMaybeAssigned();
2197 }
2198 if (cache_scope) cache_scope->variables_.Remove(var);
2199 Scope* target = cache_scope == nullptr ? scope : cache_scope;
2200 Variable* dynamic =
2201 target->NonLocal(proxy->raw_name(), VariableMode::kDynamic);
2202 dynamic->set_local_if_not_shadowed(var);
2203 return dynamic;
2204}
2205
2207 Scope* outer_scope_end, Scope* cache_scope,
2208 bool force_context_allocation) {
2209 DCHECK(scope->is_declaration_scope() &&
2211
2212 // If we're compiling eval, it's possible that the outer scope is the first
2213 // ScopeInfo-backed scope. We use the next declaration scope as the cache for
2214 // this case, to avoid complexity around sloppy block function hoisting and
2215 // conflict detection through catch scopes in the eval.
2216 Scope* entry_cache =
2217 cache_scope == nullptr ? scope->outer_scope() : cache_scope;
2218 Variable* var =
2219 scope->outer_scope_->scope_info_.is_null()
2220 ? Lookup<kParsedScope>(proxy, scope->outer_scope_, outer_scope_end,
2221 nullptr, force_context_allocation)
2223 outer_scope_end, entry_cache);
2224 if (var == nullptr) return var;
2225
2226 // A variable binding may have been found in an outer scope, but the current
2227 // scope makes a sloppy 'eval' call, so the found variable may not be the
2228 // correct one (the 'eval' may introduce a binding with the same name). In
2229 // that case, change the lookup result to reflect this situation. Only
2230 // scopes that can host var bindings (declaration scopes) need be considered
2231 // here (this excludes block and catch scopes), and variable lookups at
2232 // script scope are always dynamic.
2233 if (var->IsGlobalObjectProperty()) {
2234 Scope* target = cache_scope == nullptr ? scope : cache_scope;
2235 var = target->NonLocal(proxy->raw_name(), VariableMode::kDynamicGlobal);
2236 }
2237
2238 if (var->is_dynamic()) return var;
2239
2240 Variable* invalidated = var;
2241 if (cache_scope != nullptr) cache_scope->variables_.Remove(invalidated);
2242
2243 Scope* target = cache_scope == nullptr ? scope : cache_scope;
2244 var = target->NonLocal(proxy->raw_name(), VariableMode::kDynamicLocal);
2245 var->set_local_if_not_shadowed(invalidated);
2246
2247 return var;
2248}
2249
2251 DCHECK(!proxy->is_resolved());
2252 Variable* var;
2253 if (V8_UNLIKELY(proxy->is_home_object())) {
2254 // VariableProxies of the home object cannot be resolved like a normal
2255 // variable. Consider the case of a super.property usage in heritage
2256 // position:
2257 //
2258 // class C extends super.foo { m() { super.bar(); } }
2259 //
2260 // The super.foo property access is logically nested under C's class scope,
2261 // which also has a home object due to its own method m's usage of
2262 // super.bar(). However, super.foo must resolve super in C's outer scope.
2263 //
2264 // Because of the above, start resolving home objects directly at the home
2265 // object scope instead of the current scope.
2266 Scope* scope = GetHomeObjectScope();
2267 DCHECK_NOT_NULL(scope);
2268 if (scope->scope_info_.is_null()) {
2269 var = Lookup<kParsedScope>(proxy, scope, nullptr);
2270 } else {
2271 var = Lookup<kDeserializedScope>(proxy, scope, nullptr, scope);
2272 }
2273 } else {
2274 var = Lookup<kParsedScope>(proxy, this, nullptr);
2275 }
2276 DCHECK_NOT_NULL(var);
2277 ResolveTo(proxy, var);
2278}
2279
2280namespace {
2281
2282void SetNeedsHoleCheck(Variable* var, VariableProxy* proxy,
2283 Variable::ForceHoleInitializationFlag flag) {
2284 proxy->set_needs_hole_check();
2285 var->ForceHoleInitialization(flag);
2286}
2287
2288void UpdateNeedsHoleCheck(Variable* var, VariableProxy* proxy, Scope* scope) {
2289 if (var->mode() == VariableMode::kDynamicLocal) {
2290 // Dynamically introduced variables never need a hole check (since they're
2291 // VariableMode::kVar bindings, either from var or function declarations),
2292 // but the variable they shadow might need a hole check, which we want to do
2293 // if we decide that no shadowing variable was dynamically introduced.
2294 DCHECK_EQ(kCreatedInitialized, var->initialization_flag());
2295 return UpdateNeedsHoleCheck(var->local_if_not_shadowed(), proxy, scope);
2296 }
2297
2298 if (var->initialization_flag() == kCreatedInitialized) return;
2299
2300 // It's impossible to eliminate module import hole checks here, because it's
2301 // unknown at compilation time whether the binding referred to in the
2302 // exporting module itself requires hole checks.
2303 if (var->location() == VariableLocation::MODULE && !var->IsExport()) {
2304 SetNeedsHoleCheck(var, proxy, Variable::kHasHoleCheckUseInUnknownScope);
2305 return;
2306 }
2307
2308 // Check if the binding really needs an initialization check. The check
2309 // can be skipped in the following situation: we have a VariableMode::kLet or
2310 // VariableMode::kConst binding, both the Variable and the VariableProxy have
2311 // the same declaration scope (i.e. they are both in global code, in the same
2312 // function or in the same eval code), the VariableProxy is in the source
2313 // physically located after the initializer of the variable, and that the
2314 // initializer cannot be skipped due to a nonlinear scope.
2315 //
2316 // The condition on the closure scopes is a conservative check for
2317 // nested functions that access a binding and are called before the
2318 // binding is initialized:
2319 // function() { f(); let x = 1; function f() { x = 2; } }
2320 //
2321 // The check cannot be skipped on non-linear scopes, namely switch
2322 // scopes, to ensure tests are done in cases like the following:
2323 // switch (1) { case 0: let x = 2; case 1: f(x); }
2324 // The scope of the variable needs to be checked, in case the use is
2325 // in a sub-block which may be linear.
2326 if (var->scope()->GetClosureScope() != scope->GetClosureScope()) {
2327 SetNeedsHoleCheck(var, proxy,
2328 Variable::kHasHoleCheckUseInDifferentClosureScope);
2329 return;
2330 }
2331
2332 // We should always have valid source positions.
2333 DCHECK_NE(var->initializer_position(), kNoSourcePosition);
2334 DCHECK_NE(proxy->position(), kNoSourcePosition);
2335
2336 if (var->scope()->is_nonlinear() ||
2337 var->initializer_position() >= proxy->position()) {
2338 SetNeedsHoleCheck(var, proxy, Variable::kHasHoleCheckUseInSameClosureScope);
2339 return;
2340 }
2341}
2342
2343} // anonymous namespace
2344
2346 DCHECK_NOT_NULL(var);
2347 UpdateNeedsHoleCheck(var, proxy, this);
2348 proxy->BindTo(var);
2349}
2350
2352 Scope* end) {
2353 // Resolve the variable in all parsed scopes to force context allocation.
2354 for (; scope != end; scope = scope->outer_scope_) {
2355 Variable* var = scope->LookupLocal(proxy->raw_name());
2356 if (var != nullptr) {
2357 var->set_is_used();
2358 if (!var->is_dynamic()) {
2360 if (proxy->is_assigned()) var->SetMaybeAssigned();
2361 return;
2362 }
2363 }
2364 }
2365}
2366
2368 // Lazy parsed declaration scopes are already partially analyzed. If there are
2369 // unresolved references remaining, they just need to be resolved in outer
2370 // scopes.
2371 if (WasLazilyParsed(this)) {
2373 // Resolve in all parsed scopes except for the script scope.
2374 if (!end->is_script_scope()) end = end->outer_scope();
2375
2376 for (VariableProxy* proxy : unresolved_list_) {
2378 }
2379 } else {
2380 // Resolve unresolved variables for this scope.
2381 for (VariableProxy* proxy : unresolved_list_) {
2382 ResolveVariable(proxy);
2383 }
2384
2385 // Resolve unresolved variables for inner scopes.
2386 for (Scope* scope = inner_scope_; scope != nullptr;
2387 scope = scope->sibling_) {
2388 if (!scope->ResolveVariablesRecursively(end)) return false;
2389 }
2390 }
2391 return true;
2392}
2393
2396 // Give var a read/write use if there is a chance it might be accessed
2397 // via an eval() call. This is only possible if the variable has a
2398 // visible name.
2399 if (!var->raw_name()->IsEmpty() &&
2401 var->set_is_used();
2402 if (inner_scope_calls_eval_ && !var->is_this()) var->SetMaybeAssigned();
2403 }
2404 CHECK(!var->has_forced_context_allocation() || var->is_used());
2405 // Global variables do not need to be allocated.
2406 return !var->IsGlobalObjectProperty() && var->is_used();
2407}
2408
2409
2411 // If var is accessed from an inner scope, or if there is a possibility
2412 // that it might be accessed from the current or an inner scope (through
2413 // an eval() call or a runtime with lookup), it must be allocated in the
2414 // context.
2415 //
2416 // Temporary variables are always stack-allocated. Catch-bound variables are
2417 // always context-allocated.
2418 VariableMode mode = var->mode();
2419 if (mode == VariableMode::kTemporary) return false;
2420 if (is_catch_scope()) return true;
2421 if (is_script_scope() || is_eval_scope()) {
2422 if (IsLexicalVariableMode(mode)) {
2423 return true;
2424 }
2425 }
2427}
2428
2436
2437
2441
2444
2445 bool has_mapped_arguments = false;
2446 if (arguments_ != nullptr) {
2447 DCHECK(!is_arrow_scope());
2448 if (MustAllocate(arguments_) && !has_arguments_parameter_) {
2449 // 'arguments' is used and does not refer to a function
2450 // parameter of the same name. If the arguments object
2451 // aliases formal parameters, we conservatively allocate
2452 // them specially in the loop below.
2453 has_mapped_arguments =
2454 GetArgumentsType() == CreateArgumentsType::kMappedArguments;
2455 } else {
2456 // 'arguments' is unused. Tell the code generator that it does not need to
2457 // allocate the arguments object by nulling out arguments_.
2458 arguments_ = nullptr;
2459 }
2460 }
2461
2462 // The same parameter may occur multiple times in the parameters_ list.
2463 // If it does, and if it is not copied into the context object, it must
2464 // receive the highest parameter index for that parameter; thus iteration
2465 // order is relevant!
2466 for (int i = num_parameters() - 1; i >= 0; --i) {
2467 Variable* var = params_[i];
2468 DCHECK_NOT_NULL(var);
2469 DCHECK(!has_rest_ || var != rest_parameter());
2470 DCHECK_EQ(this, var->scope());
2471 if (has_mapped_arguments) {
2472 var->set_is_used();
2473 var->SetMaybeAssigned();
2475 }
2476 AllocateParameter(var, i);
2477 }
2478}
2479
2481 if (!MustAllocate(var)) return;
2483 MustAllocateInContext(var)) {
2484 DCHECK(var->IsUnallocated() || var->IsContextSlot());
2485 if (var->IsUnallocated()) AllocateHeapSlot(var);
2486 } else {
2487 DCHECK(var->IsUnallocated() || var->IsParameter());
2488 if (var->IsUnallocated()) {
2490 }
2491 }
2492}
2493
2495 if (!has_this_declaration()) return;
2497 DCHECK_EQ(receiver()->scope(), this);
2498 AllocateParameter(receiver(), -1);
2499}
2500
2502 DCHECK_EQ(var->scope(), this);
2503 if (var->IsUnallocated() && MustAllocate(var)) {
2504 if (MustAllocateInContext(var)) {
2505 AllocateHeapSlot(var);
2508 } else {
2509 AllocateStackSlot(var);
2510 }
2511 }
2512}
2513
2515 if (is_declaration_scope() && AsDeclarationScope()->is_arrow_scope()) {
2516 // In arrow functions, allocate non-temporaries first and then all the
2517 // temporaries to make the local variable ordering stable when reparsing to
2518 // collect source positions.
2519 for (Variable* local : locals_) {
2520 if (local->mode() != VariableMode::kTemporary)
2522 }
2523
2524 for (Variable* local : locals_) {
2525 if (local->mode() == VariableMode::kTemporary)
2527 }
2528 } else {
2529 for (Variable* local : locals_) {
2531 }
2532 }
2533
2534 if (is_declaration_scope()) {
2536 }
2537}
2538
2540 // For now, function_ must be allocated at the very end. If it gets
2541 // allocated in the context, it must be the last slot in the context,
2542 // because of the current ScopeInfo implementation (see
2543 // ScopeInfo::ScopeInfo(FunctionScope* scope) constructor).
2544 if (function_ != nullptr && MustAllocate(function_)) {
2546 } else {
2547 function_ = nullptr;
2548 }
2549
2550 DCHECK(!has_rest_ || !MustAllocate(rest_parameter()) ||
2551 !rest_parameter()->IsUnallocated());
2552
2553 if (new_target_ != nullptr && !MustAllocate(new_target_)) {
2554 new_target_ = nullptr;
2555 }
2556
2557 NullifyRareVariableIf(RareVariable::kThisFunction, [=, this](Variable* var) {
2558 return !MustAllocate(var);
2559 });
2560}
2561
2563 for (const auto& it : module()->regular_imports()) {
2564 Variable* var = LookupLocal(it.first);
2565 var->AllocateTo(VariableLocation::MODULE, it.second->cell_index);
2566 DCHECK(!var->IsExport());
2567 }
2568
2569 for (const auto& it : module()->regular_exports()) {
2570 Variable* var = LookupLocal(it.first);
2571 var->AllocateTo(VariableLocation::MODULE, it.second->cell_index);
2572 DCHECK(var->IsExport());
2573 }
2574}
2575
2576// Needs to be kept in sync with ScopeInfo::UniqueIdInScript and
2577// SharedFunctionInfo::UniqueIdInScript.
2579 // Script scopes start "before" the script to avoid clashing with a scope that
2580 // starts on character 0.
2581 if (is_script_scope() || scope_type() == EVAL_SCOPE ||
2582 scope_type() == MODULE_SCOPE) {
2583 return -2;
2584 }
2585 // Wrapped functions start before the function body, but after the script
2586 // start, to avoid clashing with a scope starting on character 0.
2587 if (is_wrapped_function()) {
2588 return -1;
2589 }
2590 if (is_declaration_scope()) {
2591 // Default constructors have the same start position as their parent class
2592 // scope. Use the next char position to distinguish this scope.
2593 return start_position() +
2594 IsDefaultConstructor(AsDeclarationScope()->function_kind());
2595 }
2596 return start_position();
2597}
2598
2600 this->ForEach([](Scope* scope) -> Iteration {
2601 DCHECK(!scope->already_resolved_);
2602 if (WasLazilyParsed(scope)) return Iteration::kContinue;
2603 if (scope->sloppy_eval_can_extend_vars_) {
2605 }
2607
2608 // Allocate variables for this scope.
2609 // Parameters must be allocated first, if any.
2610 if (scope->is_declaration_scope()) {
2612 if (scope->is_function_scope()) {
2614 }
2615 }
2617
2618 // Force allocation of a context for this scope if necessary. For a 'with'
2619 // scope and for a function scope that makes an 'eval' call we need a
2620 // context, even if no local variables were statically allocated in the
2621 // scope. Likewise for modules and function scopes representing asm.js
2622 // modules. Also force a context, if the scope is stricter than the outer
2623 // scope.
2624 bool must_have_context =
2625 scope->is_with_scope() || scope->is_module_scope() ||
2626#if V8_ENABLE_WEBASSEMBLY
2627 scope->IsAsmModule() ||
2628#endif // V8_ENABLE_WEBASSEMBLY
2629 scope->ForceContextForLanguageMode() ||
2630 (scope->is_function_scope() &&
2632 (scope->is_block_scope() && scope->is_declaration_scope() &&
2634
2635 // If we didn't allocate any locals in the local context, then we only
2636 // need the minimal number of slots if we must have a context.
2637 if (scope->num_heap_slots_ == scope->ContextHeaderLength() &&
2638 !must_have_context) {
2639 scope->num_heap_slots_ = 0;
2640 }
2641
2642 // Allocation done.
2643 DCHECK(scope->num_heap_slots_ == 0 ||
2644 scope->num_heap_slots_ >= scope->ContextHeaderLength());
2645 return Iteration::kDescend;
2646 });
2647}
2648
2649template <typename IsolateT>
2651 IsolateT* isolate, MaybeHandle<ScopeInfo> outer_scope,
2652 std::unordered_map<int, Handle<ScopeInfo>>& scope_infos_to_reuse) {
2653 DCHECK(scope_info_.is_null());
2654 MaybeHandle<ScopeInfo> next_outer_scope = outer_scope;
2655
2656 auto it = scope_infos_to_reuse.find(UniqueIdInScript());
2657 if (it != scope_infos_to_reuse.end()) {
2658 scope_info_ = it->second;
2659 DCHECK(!scope_info_.is_null());
2660 CHECK_EQ(scope_info_->scope_type(), scope_type_);
2661 CHECK_EQ(scope_info_->HasContext(), NeedsContext());
2662 CHECK_EQ(scope_info_->ContextLength(), num_heap_slots_);
2663#ifdef DEBUG
2664 // Consume the scope info.
2665 it->second = {};
2666#endif
2667 } else if (NeedsScopeInfo()) {
2668 scope_info_ = ScopeInfo::Create(isolate, zone(), this, outer_scope);
2669#ifdef DEBUG
2670 // Mark this ID as being used.
2671 if (v8_flags.reuse_scope_infos) {
2672 scope_infos_to_reuse[UniqueIdInScript()] = {};
2673 DCHECK_EQ(UniqueIdInScript(), scope_info_->UniqueIdInScript());
2674 }
2675#endif
2676 }
2677
2678 // The ScopeInfo chain mirrors the context chain, so we only link to the
2679 // next outer scope that needs a context.
2680 if (NeedsContext()) next_outer_scope = scope_info_;
2681
2682 // Allocate ScopeInfos for inner scopes.
2683 for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) {
2684#ifdef DEBUG
2685 DCHECK_GT(scope->UniqueIdInScript(), UniqueIdInScript());
2686 DCHECK_IMPLIES(scope->sibling_, scope->sibling_->UniqueIdInScript() !=
2687 scope->UniqueIdInScript());
2688#endif
2689 if (!scope->is_function_scope() ||
2690 scope->AsDeclarationScope()->ShouldEagerCompile()) {
2691 scope->AllocateScopeInfosRecursively(isolate, next_outer_scope,
2692 scope_infos_to_reuse);
2693 } else if (v8_flags.reuse_scope_infos) {
2694 auto scope_it = scope_infos_to_reuse.find(scope->UniqueIdInScript());
2695 if (scope_it != scope_infos_to_reuse.end()) {
2696 scope->scope_info_ = scope_it->second;
2697#ifdef DEBUG
2698 // Consume the scope info
2699 scope_it->second = {};
2700#endif
2701 }
2702 }
2703 }
2704}
2705
2709 std::unordered_map<int, Handle<ScopeInfo>>& scope_infos_to_reuse);
2713 std::unordered_map<int, Handle<ScopeInfo>>& scope_infos_to_reuse);
2714
2716 // The outermost scope in a class heritage expression is marked to skip the
2717 // class scope during private name resolution. It is possible, however, that
2718 // either the class scope won't require a Context and ScopeInfo, or the
2719 // outermost scope in the heritage position won't. Simply copying the bit from
2720 // full parse into the ScopeInfo will break lazy compilation. In the former
2721 // case the scope that is marked to skip its outer scope will incorrectly skip
2722 // a different class scope than the one we intended to skip. In the latter
2723 // case variables resolved through an inner scope will incorrectly check the
2724 // class scope since we lost the skip bit from the outermost heritage scope.
2725 //
2726 // This method fixes both cases by, in outermost to innermost order, copying
2727 // the value of the skip bit from outer scopes that don't require a Context.
2728 DCHECK(needs_private_name_context_chain_recalc_);
2729 this->ForEach([](Scope* scope) {
2730 Scope* outer = scope->outer_scope();
2731 if (!outer) return Iteration::kDescend;
2732 if (!outer->NeedsContext()) {
2735 }
2736 if (!scope->is_function_scope() ||
2738 return Iteration::kDescend;
2739 }
2740 return Iteration::kContinue;
2741 });
2742}
2743
2745 DCHECK_EQ(GetClosureScope(), this);
2746 DeclarationScope* scope;
2747 for (scope = this; scope != nullptr;
2748 scope = scope->outer_scope() != nullptr
2749 ? scope->outer_scope()->GetClosureScope()
2750 : nullptr) {
2753 }
2754}
2755
2756// static
2757template <typename IsolateT>
2759 DirectHandle<Script> script,
2760 IsolateT* isolate) {
2761 DeclarationScope* scope = parse_info->literal()->scope();
2762
2763 // No one else should have allocated a scope info for this scope yet.
2764 DCHECK(scope->scope_info_.is_null());
2765
2767 if (scope->outer_scope_ != nullptr) {
2768 DCHECK((std::is_same<Isolate, v8::internal::Isolate>::value));
2770 }
2771
2774 }
2775
2776 Tagged<WeakFixedArray> infos = script->infos();
2777 std::unordered_map<int, Handle<ScopeInfo>> scope_infos_to_reuse;
2778 if (v8_flags.reuse_scope_infos && infos->length() != 0) {
2779 Tagged<SharedFunctionInfo> parse_info_sfi =
2780 *parse_info->literal()->shared_function_info();
2781 Tagged<ScopeInfo> outer = parse_info_sfi->HasOuterScopeInfo()
2782 ? parse_info_sfi->GetOuterScopeInfo()
2784 // Look at all inner functions whether they have scope infos that we should
2785 // reuse. Also look at the compiled function itself, and reuse its function
2786 // scope info if it exists.
2787 for (int i = parse_info->literal()->function_literal_id();
2788 i <= parse_info->max_info_id(); ++i) {
2789 Tagged<MaybeObject> maybe_info = infos->get(i);
2790 if (maybe_info.IsWeak()) {
2791 Tagged<Object> info = maybe_info.GetHeapObjectAssumeWeak();
2793 if (Is<SharedFunctionInfo>(info)) {
2795 if (!sfi->scope_info()->IsEmpty()) {
2796 scope_info = sfi->scope_info();
2797 } else if (sfi->HasOuterScopeInfo()) {
2798 scope_info = sfi->GetOuterScopeInfo();
2799 } else {
2800 continue;
2801 }
2802 } else {
2804 }
2805 while (true) {
2806 if (scope_info == outer) break;
2807 int id = scope_info->UniqueIdInScript();
2808 auto it = scope_infos_to_reuse.find(id);
2809 if (it != scope_infos_to_reuse.end()) {
2810 if (V8_LIKELY(*it->second == scope_info)) break;
2811
2812 // TODO(crbug.com/401059828): remove once crashes are gone.
2813 int last_checked_field_index = 0;
2814 bool equal_scopes =
2815 it->second->Equals(scope_info, parse_info_sfi->live_edited(),
2816 &last_checked_field_index);
2817
2818 std::unique_ptr<char[]> script_source;
2819 size_t script_source_length = 0;
2820 std::unique_ptr<char[]> function_source;
2821 size_t function_source_length = 0;
2822 if (IsString(script->source())) {
2823 script_source = Cast<String>(script->source())
2824 ->ToCString(&script_source_length);
2825
2826 function_source =
2827 Cast<String>(script->source())
2828 ->ToCString(parse_info_sfi->StartPosition(),
2829 parse_info_sfi->EndPosition() -
2830 parse_info_sfi->StartPosition(),
2831 &function_source_length);
2832 }
2833
2834 std::vector<Address> data{
2835 scope_info->ptr(),
2836 it->second->ptr(),
2837 static_cast<Address>(equal_scopes),
2838 static_cast<Address>(last_checked_field_index),
2839 parse_info_sfi.ptr(),
2840 outer.ptr(),
2841 0xcafe0000,
2842 infos.ptr(),
2843 static_cast<Address>(
2844 parse_info->literal()->function_literal_id()),
2845 static_cast<Address>(parse_info->max_info_id()),
2846 static_cast<Address>(i),
2847 0xcafe0001,
2848 info.ptr(),
2849 static_cast<Address>(id),
2850 outer_scope.is_null() ? 0
2851 : outer_scope.ToHandleChecked()->ptr(),
2852 0xcafe0002,
2853 scope_info->HasOuterScopeInfo()
2854 ? scope_info->OuterScopeInfo().ptr()
2855 : 0,
2856 it->second->HasOuterScopeInfo()
2857 ? it->second->OuterScopeInfo().ptr()
2858 : 0,
2859 0xcafe0003,
2860 script->ptr(),
2861 script->GetNameOrSourceURL().ptr(),
2862 static_cast<Address>(parse_info_sfi->StartPosition()),
2863 static_cast<Address>(parse_info_sfi->EndPosition()),
2864 0xcafe0004,
2865 script->source().ptr(),
2866 reinterpret_cast<Address>(script_source.get()),
2867 script_source_length,
2868 reinterpret_cast<Address>(script_source.get() +
2869 parse_info_sfi->StartPosition()),
2870 reinterpret_cast<Address>(script_source.get() +
2871 parse_info_sfi->EndPosition()),
2872 0xcafe0005,
2873 parse_info_sfi->Name().ptr(),
2874 reinterpret_cast<Address>(function_source.get()),
2875 function_source_length,
2876 reinterpret_cast<Address>(function_source.get() +
2877 function_source_length),
2878
2879 0xcafeffff,
2880 };
2881
2882 Isolate* main_thread_isolate =
2883 isolate->GetMainThreadIsolateUnsafe();
2885 std::is_same_v<IsolateT, Isolate>
2888 StackTraceFailureMessage message(main_thread_isolate, mode,
2889 &data[0], data.size());
2890 message.Print();
2891 if (equal_scopes) {
2892 // Proceed execution if the scopes are structurally equal.
2893 // isolate->PushStackTraceAndContinue(...);
2895 break;
2896 }
2897 // The scopes are different, stop here.
2898 // isolate->PushStackTraceAndDie(...);
2900 }
2901 scope_infos_to_reuse[id] = handle(scope_info, isolate);
2902 if (!scope_info->HasOuterScopeInfo()) break;
2903 scope_info = scope_info->OuterScopeInfo();
2904 }
2905 }
2906 }
2907 }
2908
2910 scope_infos_to_reuse);
2911
2912 // The debugger expects all shared function infos to contain a scope info.
2913 // Since the top-most scope will end up in a shared function info, make sure
2914 // it has one, even if it doesn't need a scope info.
2915 // TODO(yangguo): Remove this requirement.
2916 if (scope->scope_info_.is_null()) {
2917 scope->scope_info_ =
2918 ScopeInfo::Create(isolate, scope->zone(), scope, outer_scope);
2919 }
2920
2921 // Ensuring that the outer script scope has a scope info avoids having
2922 // special case for native contexts vs other contexts.
2923 if (parse_info->script_scope() &&
2924 parse_info->script_scope()->scope_info_.is_null()) {
2925 parse_info->script_scope()->scope_info_ =
2926 isolate->factory()->empty_scope_info();
2927 }
2928}
2929
2931 ParseInfo* info, DirectHandle<Script> script, Isolate* isolate);
2933 ParseInfo* info, DirectHandle<Script> script, LocalIsolate* isolate);
2934
2936 if (num_heap_slots() == 0) return 0;
2937 Variable* function =
2939 bool is_function_var_in_context =
2940 function != nullptr && function->IsContextSlot();
2941 return num_heap_slots() - ContextHeaderLength() -
2942 (is_function_var_in_context ? 1 : 0);
2943}
2944
2946 switch (a) {
2951 default:
2952 return false;
2953 }
2954}
2955
2957 VariableMode mode,
2958 IsStaticFlag is_static_flag,
2959 bool* was_added) {
2960 Variable* result = EnsureRareData()->private_name_map.Declare(
2961 zone(), this, name, mode, NORMAL_VARIABLE,
2963 is_static_flag, was_added);
2964 if (*was_added) {
2965 locals_.Add(result);
2966 has_static_private_methods_ |=
2967 (result->is_static() &&
2969 } else if (IsComplementaryAccessorPair(result->mode(), mode) &&
2970 result->is_static_flag() == is_static_flag) {
2971 *was_added = true;
2973 }
2975 return result;
2976}
2977
2979 RareData* rare_data = GetRareData();
2980 if (rare_data == nullptr) {
2981 return nullptr;
2982 }
2983 return rare_data->private_name_map.Lookup(name);
2984}
2985
2987 RareData* rare_data = GetRareData();
2988 if (rare_data == nullptr) {
2989 return UnresolvedList::Iterator();
2990 }
2991 return rare_data->unresolved_private_names.end();
2992}
2993
2995 RareData* rare_data = GetRareData();
2996 if (rare_data == nullptr ||
2997 rare_data->unresolved_private_names.end() == tail) {
2998 return;
2999 }
3000
3001 bool tail_is_empty = tail == UnresolvedList::Iterator();
3002 if (tail_is_empty) {
3003 // If the saved tail is empty, the list used to be empty, so clear it.
3004 rare_data->unresolved_private_names.Clear();
3005 } else {
3006 rare_data->unresolved_private_names.Rewind(tail);
3007 }
3008}
3009
3011 AstNodeFactory* ast_node_factory, UnresolvedList::Iterator tail) {
3012 RareData* rare_data = GetRareData();
3013 if (rare_data == nullptr ||
3014 rare_data->unresolved_private_names.end() == tail) {
3015 return;
3016 }
3017 UnresolvedList migrated_names;
3018
3019 // If the saved tail is empty, the list used to be empty, so we should
3020 // migrate everything after the head.
3021 bool tail_is_empty = tail == UnresolvedList::Iterator();
3023 tail_is_empty ? rare_data->unresolved_private_names.begin() : tail;
3024
3025 for (; it != rare_data->unresolved_private_names.end(); ++it) {
3026 VariableProxy* proxy = *it;
3027 VariableProxy* copy = ast_node_factory->CopyVariableProxy(proxy);
3028 migrated_names.Add(copy);
3029 }
3030
3031 // Replace with the migrated copies.
3032 if (tail_is_empty) {
3033 rare_data->unresolved_private_names.Clear();
3034 } else {
3035 rare_data->unresolved_private_names.Rewind(tail);
3036 }
3037 rare_data->unresolved_private_names.Append(std::move(migrated_names));
3038}
3039
3041 DCHECK(!scope_info_.is_null());
3042 DCHECK_NULL(LookupLocalPrivateName(name));
3044
3045 VariableLookupResult lookup_result;
3046 int index = scope_info_->ContextSlotIndex(name->string(), &lookup_result);
3047 if (index < 0) {
3048 return nullptr;
3049 }
3050
3054
3055 // Add the found private name to the map to speed up subsequent
3056 // lookups for the same name.
3057 bool was_added;
3058 Variable* var = DeclarePrivateName(name, lookup_result.mode,
3059 lookup_result.is_static_flag, &was_added);
3060 DCHECK(was_added);
3062 return var;
3063}
3064
3066 DCHECK(!proxy->is_resolved());
3067
3068 for (PrivateNameScopeIterator scope_iter(this); !scope_iter.Done();
3069 scope_iter.Next()) {
3070 ClassScope* scope = scope_iter.GetScope();
3071 // Try finding it in the private name map first, if it can't be found,
3072 // try the deserialized scope info.
3073 Variable* var = scope->LookupLocalPrivateName(proxy->raw_name());
3074 if (var == nullptr && !scope->scope_info_.is_null()) {
3075 var = scope->LookupPrivateNameInScopeInfo(proxy->raw_name());
3076 }
3077 if (var != nullptr) {
3078 return var;
3079 }
3080 }
3081 return nullptr;
3082}
3083
3085 RareData* rare_data = GetRareData();
3086 if (rare_data == nullptr || rare_data->unresolved_private_names.is_empty()) {
3087 return true;
3088 }
3089
3090 UnresolvedList& list = rare_data->unresolved_private_names;
3091 for (VariableProxy* proxy : list) {
3092 Variable* var = LookupPrivateName(proxy);
3093 if (var == nullptr) {
3094 // It's only possible to fail to resolve private names here if
3095 // this is at the top level or the private name is accessed through eval.
3096 DCHECK(info->flags().is_eval() || outer_scope_->is_script_scope());
3097 Scanner::Location loc = proxy->location();
3098 info->pending_error_handler()->ReportMessageAt(
3099 loc.beg_pos, loc.end_pos,
3100 MessageTemplate::kInvalidPrivateFieldResolution, proxy->raw_name());
3101 return false;
3102 } else {
3103 proxy->BindTo(var);
3104 }
3105 }
3106
3107 // By now all unresolved private names should be resolved so
3108 // clear the list.
3109 list.Clear();
3110 return true;
3111}
3112
3114 RareData* rare_data = GetRareData();
3115 if (rare_data == nullptr || rare_data->unresolved_private_names.is_empty()) {
3116 return nullptr;
3117 }
3118
3119 PrivateNameScopeIterator private_name_scope_iter(this);
3120 private_name_scope_iter.Next();
3121 UnresolvedList& unresolved = rare_data->unresolved_private_names;
3122 bool has_private_names = rare_data->private_name_map.capacity() > 0;
3123
3124 // If the class itself does not have private names, nor does it have
3125 // an outer private name scope, then we are certain any private name access
3126 // inside cannot be resolved.
3127 if (!has_private_names && private_name_scope_iter.Done() &&
3128 !unresolved.is_empty()) {
3129 return unresolved.first();
3130 }
3131
3132 for (VariableProxy* proxy = unresolved.first(); proxy != nullptr;) {
3133 DCHECK(proxy->IsPrivateName());
3134 VariableProxy* next = proxy->next_unresolved();
3135 unresolved.Remove(proxy);
3136 Variable* var = nullptr;
3137
3138 // If we can find private name in the current class scope, we can bind
3139 // them immediately because it's going to shadow any outer private names.
3140 if (has_private_names) {
3141 var = LookupLocalPrivateName(proxy->raw_name());
3142 if (var != nullptr) {
3143 var->set_is_used();
3144 proxy->BindTo(var);
3145 // If the variable being accessed is a static private method, we need to
3146 // save the class variable in the context to check that the receiver is
3147 // the class during runtime.
3148 has_explicit_static_private_methods_access_ |=
3149 (var->is_static() &&
3151 }
3152 }
3153
3154 // If the current scope does not have declared private names,
3155 // try looking from the outer class scope later.
3156 if (var == nullptr) {
3157 // There's no outer private name scope so we are certain that the variable
3158 // cannot be resolved later.
3159 if (private_name_scope_iter.Done()) {
3160 return proxy;
3161 }
3162
3163 // The private name may be found later in the outer private name scope, so
3164 // push it to the outer scope.
3165 private_name_scope_iter.AddUnresolvedPrivateName(proxy);
3166 }
3167
3168 proxy = next;
3169 }
3170
3171 DCHECK(unresolved.is_empty());
3172 return nullptr;
3173}
3174
3176 IsStaticFlag is_static_flag,
3177 int class_token_pos) {
3178 DCHECK_IMPLIES(GetRareData() != nullptr, GetRareData()->brand == nullptr);
3179 bool was_added;
3180 Variable* brand = Declare(zone(), ast_value_factory->dot_brand_string(),
3184 DCHECK(was_added);
3185 brand->set_is_static_flag(is_static_flag);
3186 brand->ForceContextAllocation();
3187 brand->set_is_used();
3188 EnsureRareData()->brand = brand;
3189 brand->set_initializer_position(class_token_pos);
3190 return brand;
3191}
3192
3194 const AstRawString* name,
3195 int class_token_pos) {
3196 DCHECK_NULL(class_variable_);
3197 DCHECK_NOT_NULL(name);
3198 bool was_added;
3199 class_variable_ =
3200 Declare(zone(), name->IsEmpty() ? ast_value_factory->dot_string() : name,
3204 DCHECK(was_added);
3205 class_variable_->set_initializer_position(class_token_pos);
3206 return class_variable_;
3207}
3208
3210 : start_scope_(start), current_scope_(start) {
3211 if (!start->is_class_scope() || start->AsClassScope()->IsParsingHeritage()) {
3212 Next();
3213 }
3214}
3215
3217 DCHECK(!Done());
3218 Scope* inner = current_scope_;
3219 Scope* scope = inner->outer_scope();
3220 while (scope != nullptr) {
3221 if (scope->is_class_scope()) {
3223 current_scope_ = scope;
3224 return;
3225 }
3226 skipped_any_scopes_ = true;
3227 }
3228 inner = scope;
3229 scope = scope->outer_scope();
3230 }
3231 current_scope_ = nullptr;
3232}
3233
3235 // During a reparse, current_scope_->already_resolved_ may be true here,
3236 // because the class scope is deserialized while the function scope inside may
3237 // be new.
3238 DCHECK(!proxy->is_resolved());
3239 DCHECK(proxy->IsPrivateName());
3240
3241 // Use dynamic lookup for top-level scopes in debug-evaluate.
3242 if (Done()) {
3244 return;
3245 }
3246
3248 // Any closure scope that contain uses of private names that skips over a
3249 // class scope due to heritage expressions need private name context chain
3250 // recalculation, since not all scopes require a Context or ScopeInfo. See
3251 // comment in DeclarationScope::RecalcPrivateNameContextChain.
3254 }
3255}
3256
3257} // namespace internal
3258} // namespace v8
Address * arguments_
Builtins::Kind kind
Definition builtins.cc:40
#define SBXCHECK(condition)
Definition check.h:61
SourcePosition pos
virtual void DumpWithoutCrashing()
static void Abort()
Entry * Next(Entry *entry) const
Definition hashmap.h:345
uint32_t occupancy() const
Definition hashmap.h:111
uint32_t capacity() const
Definition hashmap.h:116
void Prepend(ThreadedListBase &&list)
void MoveTail(ThreadedListBase *from_list, Iterator from_location)
void Append(ThreadedListBase &&list)
void Rewind(Iterator reset_point)
void set_lookup_hoisting_mode(LookupHoistingMode mode)
Definition ast.h:2180
Variable * CopyVariable(Variable *variable)
Definition ast.h:3316
VariableProxy * CopyVariableProxy(VariableProxy *proxy)
Definition ast.h:3312
Assignment * NewAssignment(Token::Value op, Expression *target, Expression *value, int pos)
Definition ast.h:3416
VariableDeclaration * NewVariableDeclaration(int pos)
Definition ast.h:3040
VariableProxy * NewVariableProxy(Variable *var, int start_position=kNoSourcePosition)
Definition ast.h:3299
AstValueFactory * ast_value_factory() const
Definition ast.h:3038
ExpressionStatement * NewExpressionStatement(Expression *expression, int pos)
Definition ast.h:3106
const AstRawString * GetString(Tagged< String > literal, const SharedStringAccessGuardIfNeeded &)
V8_INLINE RareData * EnsureRareData()
Definition scopes.h:1510
Variable * LookupLocalPrivateName(const AstRawString *name)
Definition scopes.cc:2978
void ResetUnresolvedPrivateNameTail(UnresolvedList::Iterator tail)
Definition scopes.cc:2994
Variable * DeclareClassVariable(AstValueFactory *ast_value_factory, const AstRawString *name, int class_token_pos)
Definition scopes.cc:3193
void MigrateUnresolvedPrivateNameTail(AstNodeFactory *ast_node_factory, UnresolvedList::Iterator tail)
Definition scopes.cc:3010
Variable * DeclarePrivateName(const AstRawString *name, VariableMode mode, IsStaticFlag is_static_flag, bool *was_added)
Definition scopes.cc:2956
V8_WARN_UNUSED_RESULT bool ResolvePrivateNames(ParseInfo *info)
Definition scopes.cc:3084
Variable * LookupPrivateNameInScopeInfo(const AstRawString *name)
Definition scopes.cc:3040
Variable * LookupPrivateName(VariableProxy *proxy)
Definition scopes.cc:3065
VariableProxy * ResolvePrivateNamesPartially()
Definition scopes.cc:3113
UnresolvedList::Iterator GetUnresolvedPrivateNameTail()
Definition scopes.cc:2986
Variable * DeclareBrandVariable(AstValueFactory *ast_value_factory, IsStaticFlag is_static_flag, int class_token_pos)
Definition scopes.cc:3175
V8_INLINE bool IsParsingHeritage()
Definition scopes.h:1455
void ResetAfterPreparsing(AstValueFactory *ast_value_factory, bool aborted)
Definition scopes.cc:1640
void SetScriptScopeInfo(Handle< ScopeInfo > scope_info)
Definition scopes.h:976
static V8_WARN_UNUSED_RESULT bool Analyze(ParseInfo *info)
Definition scopes.cc:687
static V8_EXPORT_PRIVATE void AllocateScopeInfos(ParseInfo *info, DirectHandle< Script > script, IsolateT *isolate)
FunctionKind function_kind() const
Definition scopes.h:863
bool should_ban_arguments() const
Definition scopes.h:987
void DeserializeReceiver(AstValueFactory *ast_value_factory)
Definition scopes.cc:1343
V8_INLINE void AllocateParameterLocals()
Definition scopes.cc:2442
V8_INLINE RareData * EnsureRareData()
Definition scopes.h:1314
Variable * function_var() const
Definition scopes.h:1046
bool ShouldEagerCompile() const
Definition scopes.h:970
void AddLocal(Variable *var)
Definition scopes.cc:901
void SavePreparseDataForDeclarationScope(Parser *parser)
Definition scopes.cc:1706
Variable * DeclareGeneratorObjectVar(const AstRawString *name)
Definition scopes.cc:836
void HoistSloppyBlockFunctions(AstNodeFactory *factory)
Definition scopes.cc:581
bool needs_private_name_context_chain_recalc() const
Definition scopes.h:1219
bool AllocateVariables(ParseInfo *info)
Definition scopes.cc:1358
void RecordParameter(bool is_rest)
Definition scopes.cc:1046
void RecordNeedsPrivateNameContextChainRecalc()
Definition scopes.cc:2744
void DeclareSloppyBlockFunction(SloppyBlockFunctionStatement *sloppy_block_function)
Definition scopes.cc:576
void AnalyzePartially(Parser *parser, AstNodeFactory *ast_node_factory, bool maybe_in_arrowhead)
Definition scopes.cc:1711
bool AllowsLazyCompilation() const
Definition scopes.cc:1424
void DeclareThis(AstValueFactory *ast_value_factory)
Definition scopes.cc:739
V8_INLINE void AllocateParameter(Variable *var, int index)
Definition scopes.cc:2480
PreparseDataBuilder * preparse_data_builder() const
Definition scopes.h:1208
Declaration * CheckConflictingVarDeclarations(bool *allowed_catch_binding_var_redeclaration)
Definition scopes.cc:1264
bool sloppy_eval_can_extend_vars() const
Definition scopes.h:926
Variable * generator_object_var() const
Definition scopes.h:1051
bool was_lazily_parsed() const
Definition scopes.h:930
bool has_this_declaration() const
Definition scopes.h:1039
Variable * DeclareParameter(const AstRawString *name, VariableMode mode, bool is_optional, bool is_rest, AstValueFactory *ast_value_factory, int position)
Definition scopes.cc:1012
PreparseDataBuilder * preparse_data_builder_
Definition scopes.h:1298
void DeclareArguments(AstValueFactory *ast_value_factory)
Definition scopes.cc:760
Variable * DeclareFunctionVar(const AstRawString *name, Scope *cache=nullptr)
Definition scopes.cc:813
base::ThreadedList< SloppyBlockFunctionStatement > sloppy_block_functions_
Definition scopes.h:1287
V8_INLINE void AllocateLocals()
Definition scopes.cc:2539
bool has_simple_parameters() const
Definition scopes.h:1076
void DeclareDefaultFunctionVariables(AstValueFactory *ast_value_factory)
Definition scopes.cc:792
Variable * DeclareDynamicGlobal(const AstRawString *name, VariableKind variable_kind, Scope *cache)
Definition scopes.cc:1234
V8_INLINE void AllocateReceiver()
Definition scopes.cc:2494
int function_literal_id() const
Definition ast.h:2408
Handle< SharedFunctionInfo > shared_function_info() const
Definition ast.h:2356
DeclarationScope * scope() const
Definition ast.h:2315
Isolate * GetMainThreadIsolateUnsafe()
Definition isolate.h:2189
ModuleScope(DeclarationScope *script_scope, AstValueFactory *avfactory)
Definition scopes.cc:164
void set_has_module_in_scope_chain()
Definition parse-info.h:353
DeclarationScope * script_scope() const
Definition parse-info.h:305
FunctionLiteral * literal() const
Definition parse-info.h:319
void AddUnresolvedPrivateName(VariableProxy *proxy)
Definition scopes.cc:3234
static Handle< ScopeInfo > Create(IsolateT *isolate, Zone *zone, Scope *scope, MaybeDirectHandle< ScopeInfo > outer_scope)
Definition scope-info.cc:79
base::ThreadedList< Variable >::Iterator top_local_
Definition scopes.h:147
UnresolvedList::Iterator top_unresolved_
Definition scopes.h:146
void Reparent(DeclarationScope *new_parent)
Definition scopes.cc:908
int ContextLocalCount() const
Definition scopes.cc:2935
bool HasSimpleParameters()
Definition scopes.cc:383
void AllocateNonParameterLocal(Variable *var)
Definition scopes.cc:2501
int num_heap_slots() const
Definition scopes.h:503
bool IsOuterScopeOf(Scope *other) const
Definition scopes.cc:1591
V8_INLINE void AllocateHeapSlot(Variable *var)
Definition scopes.cc:2438
Variable * LookupInScopeInfo(const AstRawString *name, Scope *cache)
Definition scopes.cc:958
bool NeedsScopeInfo() const
Definition scopes.cc:1488
bool is_wrapped_function_
Definition scopes.h:849
bool HasThisReference() const
Definition scopes.cc:1385
void set_language_mode(LanguageMode language_mode)
Definition scopes.h:657
bool is_repl_mode_scope() const
Definition scopes.h:610
void set_end_position(int statement_pos)
Definition scopes.h:343
bool has_using_declaration_
Definition scopes.h:844
static Variable * LookupSloppyEval(VariableProxy *proxy, Scope *scope, Scope *outer_scope_end, Scope *cache_scope, bool force_context_allocation)
Definition scopes.cc:2206
Variable * Declare(Zone *zone, const AstRawString *name, VariableMode mode, VariableKind kind, InitializationFlag initialization_flag, MaybeAssignedFlag maybe_assigned_flag, bool *was_added)
Definition scopes.h:662
void AllocateScopeInfosRecursively(IsolateT *isolate, MaybeHandle< ScopeInfo > outer_scope, std::unordered_map< int, IndirectHandle< ScopeInfo > > &scope_infos_to_reuse)
bool AllowsLazyParsingWithoutUnresolvedVariables(const Scope *outer) const
Definition scopes.cc:1400
friend class ClassScope
Definition scopes.h:759
int UniqueIdInScript() const
Definition scopes.cc:2578
bool private_name_lookup_skips_outer_class() const
Definition scopes.h:388
static Variable * Lookup(VariableProxy *proxy, Scope *scope, Scope *outer_scope_end, Scope *cache_scope=nullptr, bool force_context_allocation=false)
Definition scopes.cc:2072
Scope * outer_scope() const
Definition scopes.h:488
bool is_debug_evaluate_scope_
Definition scopes.h:824
Scope * GetOuterScopeWithContext()
Definition scopes.cc:1550
DeclarationScope * AsDeclarationScope()
static Scope * DeserializeScopeChain(IsolateT *isolate, Zone *zone, Tagged< ScopeInfo > scope_info, DeclarationScope *script_scope, AstValueFactory *ast_value_factory, DeserializationMode deserialization_mode, ParseInfo *info=nullptr)
Definition scopes.cc:416
static void SetScriptScopeInfo(IsolateT *isolate, DeclarationScope *script_scope)
Definition scopes.cc:515
int ContextChainLength(Scope *scope) const
Definition scopes.cc:1431
bool IsConstructorScope() const
Definition scopes.cc:1586
ClassScope * AsClassScope()
Definition scopes.cc:566
base::ThreadedList< Variable > * locals()
Definition scopes.h:231
base::ThreadedList< Declaration > decls_
Definition scopes.h:781
Scope * inner_scope_
Definition scopes.h:765
bool is_home_object_scope() const
Definition scopes.h:374
DeclarationScope * GetScriptScope()
Definition scopes.cc:1542
base::ThreadedList< Variable > locals_
Definition scopes.h:776
bool is_script_scope() const
Definition scopes.h:364
bool private_name_lookup_skips_outer_class_
Definition scopes.h:836
const ScopeType scope_type_
Definition scopes.h:807
bool RemoveInnerScope(Scope *inner_scope)
Definition scopes.h:622
friend class DeclarationScope
Definition scopes.h:758
Scope * outer_scope_
Definition scopes.h:764
int ContextHeaderLength() const
Definition scopes.h:522
ModuleScope * AsModuleScope()
Definition scopes.cc:556
void AllocateVariablesRecursively()
Definition scopes.cc:2599
DeclarationScope * GetReceiverScope()
Definition scopes.cc:1501
bool is_declaration_scope_
Definition scopes.h:831
bool is_debug_evaluate_scope() const
Definition scopes.h:608
bool is_class_scope() const
Definition scopes.h:373
VariableMap variables_
Definition scopes.h:773
void AddInnerScope(Scope *inner_scope)
Definition scopes.h:750
Handle< ScopeInfo > scope_info() const
Definition scopes.h:581
void DeleteUnresolved(VariableProxy *var)
Definition scopes.cc:1245
bool has_forced_context_allocation_for_parameters() const
Definition scopes.h:353
Variable * DeclareHomeObjectVariable(AstValueFactory *ast_value_factory)
Definition scopes.cc:114
Variable * DeclareCatchVariableName(const AstRawString *name)
Definition scopes.cc:1213
bool is_eval_scope() const
Definition scopes.h:361
V8_WARN_UNUSED_RESULT bool ResolveVariablesRecursively(Scope *end)
Definition scopes.cc:2367
bool is_function_scope() const
Definition scopes.h:362
ScopeType scope_type() const
Definition scopes.h:474
Scope(Zone *zone, Scope *outer_scope, ScopeType scope_type)
Definition scopes.cc:103
bool needs_home_object_
Definition scopes.h:840
bool force_context_allocation_for_parameters_
Definition scopes.h:828
V8_INLINE void AllocateNonParameterLocalsAndDeclaredGlobals()
Definition scopes.cc:2514
void AllocateStackSlot(Variable *var)
Definition scopes.cc:2429
bool has_await_using_declaration_
Definition scopes.h:845
Variable * DeclareStaticHomeObjectVariable(AstValueFactory *ast_value_factory)
Definition scopes.cc:126
bool MustAllocateInContext(Variable *var)
Definition scopes.cc:2410
void AnalyzePartially(DeclarationScope *max_outer_scope, AstNodeFactory *ast_node_factory, UnresolvedList *new_unresolved_list, bool maybe_in_arrowhead)
Definition scopes.cc:1600
Scope * inner_scope() const
Definition scopes.h:484
void SavePreparseData(Parser *parser)
Definition scopes.cc:1694
Variable * DeclareVariableName(const AstRawString *name, VariableMode mode, bool *was_added, VariableKind kind=NORMAL_VARIABLE)
Definition scopes.cc:1177
DeclarationScope * GetClosureScope()
Definition scopes.cc:1480
UnresolvedList unresolved_list_
Definition scopes.h:779
static Variable * LookupWith(VariableProxy *proxy, Scope *scope, Scope *outer_scope_end, Scope *cache_scope, bool force_context_allocation)
Definition scopes.cc:2172
bool is_hidden() const
Definition scopes.h:346
static void ResolvePreparsedVariable(VariableProxy *proxy, Scope *scope, Scope *end)
Definition scopes.cc:2351
void ResolveTo(VariableProxy *proxy, Variable *var)
Definition scopes.cc:2345
Variable * NonLocal(const AstRawString *name, VariableMode mode)
Definition scopes.cc:2049
bool NeedsContext() const
Definition scopes.h:430
bool is_wrapped_function() const
Definition scopes.h:397
DeclarationScope * GetNonEvalDeclarationScope()
Definition scopes.cc:1464
bool is_block_scope_for_object_literal_
Definition scopes.h:841
Zone * zone() const
Definition scopes.h:179
Variable * NewTemporary(const AstRawString *name)
Definition scopes.cc:1250
const AstRawString * FindVariableDeclaredIn(Scope *scope, VariableMode mode_limit)
Definition scopes.cc:1331
void ResolveVariable(VariableProxy *proxy)
Definition scopes.cc:2250
bool inner_scope_calls_eval_
Definition scopes.h:827
bool is_with_scope() const
Definition scopes.h:371
void set_start_position(int statement_pos)
Definition scopes.h:339
Scope * GetHomeObjectScope()
Definition scopes.cc:1523
Variable * DeclareLocal(const AstRawString *name, VariableMode mode, VariableKind kind, bool *was_added, InitializationFlag init_flag=kCreatedInitialized)
Definition scopes.cc:1055
void RecordEvalCall()
Definition scopes.h:1340
Variable * DeclareVariable(Declaration *declaration, const AstRawString *name, int pos, VariableMode mode, VariableKind kind, InitializationFlag init, bool *was_added, bool *sloppy_mode_block_scope_function_redefinition, bool *ok)
Definition scopes.cc:1091
bool is_block_scope() const
Definition scopes.h:368
Scope * FinalizeBlockScope()
Definition scopes.cc:847
void set_is_debug_evaluate_scope()
Definition scopes.h:607
void RewriteReplGlobalVariables()
Definition scopes.cc:1764
int ContextChainLengthUntilOutermostSloppyEval() const
Definition scopes.cc:1440
bool IsSkippableFunctionScope()
Definition scopes.cc:1682
bool must_use_preparsed_scope_data_
Definition scopes.h:838
V8_INLINE void ForEach(FunctionType callback)
int end_position() const
Definition scopes.h:342
bool MustAllocate(Variable *var)
Definition scopes.cc:2394
DeclarationScope * GetDeclarationScope()
Definition scopes.cc:1456
void ForceDynamicLookup(VariableProxy *proxy)
Definition scopes.cc:2061
bool sloppy_eval_can_extend_vars_
Definition scopes.h:818
void AddUnresolved(VariableProxy *proxy)
Definition scopes.cc:1225
LanguageMode language_mode() const
Definition scopes.h:477
DeclarationScope * GetConstructorScope()
Definition scopes.cc:1511
Scope * sibling() const
Definition scopes.h:485
Variable * LookupInScopeOrScopeInfo(const AstRawString *name, Scope *cache)
Definition scopes.h:638
bool HasReceiverToDeserialize() const
Definition scopes.cc:1381
bool is_catch_scope() const
Definition scopes.h:367
int start_position() const
Definition scopes.h:338
bool is_module_scope() const
Definition scopes.h:363
IndirectHandle< ScopeInfo > scope_info_
Definition scopes.h:784
bool ForceContextForLanguageMode() const
Definition scopes.h:419
bool is_declaration_scope() const
Definition scopes.h:372
Variable * LookupLocal(const AstRawString *name)
Definition scopes.h:200
bool ShouldBanArguments()
Definition scopes.cc:1497
V8_INLINE constexpr StorageType ptr() const
constexpr bool IsWeak() const
Tagged< HeapObject > GetHeapObjectAssumeWeak() const
static V8_EXPORT_PRIVATE v8::Platform * GetCurrentPlatform()
Definition v8.cc:282
V8_EXPORT_PRIVATE Variable * Lookup(const AstRawString *name)
Definition scopes.cc:84
void Add(Variable *var)
Definition scopes.cc:75
VariableMap(Zone *zone)
Definition scopes.cc:40
Zone * zone() const
Definition scopes.h:74
void Remove(Variable *var)
Definition scopes.cc:70
Variable * Declare(Zone *zone, Scope *scope, const AstRawString *name, VariableMode mode, VariableKind kind, InitializationFlag initialization_flag, MaybeAssignedFlag maybe_assigned_flag, IsStaticFlag is_static_flag, bool *was_added)
Definition scopes.cc:46
bool is_home_object() const
Definition ast.h:1578
void mark_removed_from_unresolved()
Definition ast.h:1574
void BindTo(Variable *var)
Definition ast.cc:173
V8_INLINE VariableProxy * next_unresolved()
Definition ast.h:1569
bool IsPrivateName() const
Definition ast.h:1564
bool is_assigned() const
Definition ast.h:1531
const AstRawString * raw_name() const
Definition ast.h:1513
bool is_resolved() const
Definition ast.h:1542
bool is_dynamic() const
Definition variables.h:138
VariableMode mode() const
Definition variables.h:66
bool is_parameter() const
Definition variables.h:256
bool IsParameter() const
Definition variables.h:127
bool is_this() const
Definition variables.h:251
bool is_sloppy_block_function()
Definition variables.h:257
void AllocateTo(VariableLocation location, int index)
Definition variables.h:295
VariableLocation location() const
Definition variables.h:276
void set_local_if_not_shadowed(Variable *local)
Definition variables.h:272
bool has_forced_context_allocation() const
Definition variables.h:78
void set_initializer_position(int pos)
Definition variables.h:122
bool IsExport() const
Definition variables.h:289
bool IsGlobalObjectProperty() const
Definition variables.cc:25
bool is_static() const
Definition variables.h:76
void set_is_static_flag(IsStaticFlag is_static_flag)
Definition variables.h:70
void ForceHoleInitialization(ForceHoleInitializationFlag flag)
Definition variables.h:197
Scope * scope() const
Definition variables.h:58
void set_scope(Scope *scope)
Definition variables.h:62
const AstRawString * raw_name() const
Definition variables.h:65
void ForceContextAllocation()
Definition variables.h:81
bool IsContextSlot() const
Definition variables.h:130
bool IsUnallocated() const
Definition variables.h:124
T * New(Args &&... args)
Definition zone.h:114
const JSFunctionRef function_
const ScopeInfoRef scope_info_
int start
int end
Scope * start_scope_
Label label
#define EXPORT_TEMPLATE_DEFINE(export)
Isolate * isolate
Node * receiver_
TNode< Object > receiver
TNode< Object > callback
ZoneVector< RpoNumber > & result
int position
Definition liveedit.cc:290
int n
Definition mul-fft.cc:296
constexpr auto Header(size_t size)
SnapshotTable< OpIndex, VariableData >::Key Variable
Definition operations.h:82
bool(* FunctionType)(const Operation &op, Zone *zone)
Definition use-map.h:12
V8_INLINE IndirectHandle< T > handle(Tagged< T > object, Isolate *isolate)
Definition handles-inl.h:72
@ kNeedsInitialization
Definition globals.h:2225
@ kCreatedInitialized
Definition globals.h:2225
bool IsArrowFunction(FunctionKind kind)
bool is_sloppy(LanguageMode language_mode)
Definition globals.h:773
constexpr int kNoSourcePosition
Definition globals.h:850
bool IsClassConstructor(FunctionKind kind)
bool Is(IndirectHandle< U > value)
Definition handles-inl.h:51
bool IsLexicalVariableMode(VariableMode mode)
Definition globals.h:2155
bool IsDeclaredVariableMode(VariableMode mode)
Definition globals.h:2120
void PrintF(const char *format,...)
Definition utils.cc:39
@ SHADOW_REALM_SCOPE
Definition globals.h:1903
Tagged(T object) -> Tagged< T >
bool IsGeneratorFunction(FunctionKind kind)
bool IsDerivedConstructor(FunctionKind kind)
bool IsConciseMethod(FunctionKind kind)
bool IsAsyncFunction(FunctionKind kind)
bool IsAccessorFunction(FunctionKind kind)
too high values may cause the compiler to set high thresholds for inlining to as much as possible avoid inlined allocation of objects that cannot escape trace load stores from virtual maglev objects use TurboFan fast string builder analyze liveness of environment slots and zap dead values trace TurboFan load elimination emit data about basic block usage in builtins to this enable builtin reordering when run mksnapshot flag for emit warnings when applying builtin profile data verify register allocation in TurboFan randomly schedule instructions to stress dependency tracking enable store store elimination in TurboFan rewrite far to near simulate GC compiler thread race related to allow float parameters to be passed in simulator mode JS Wasm Run additional turbo_optimize_inlined_js_wasm_wrappers enable experimental feedback collection in generic lowering enable Turboshaft s WasmLoadElimination enable Turboshaft s low level load elimination for JS enable Turboshaft s escape analysis for string concatenation use enable Turbolev features that we want to ship in the not too far future trace individual Turboshaft reduction steps trace intermediate Turboshaft reduction steps invocation count threshold for early optimization Enables optimizations which favor memory size over execution speed Enables sampling allocation profiler with X as a sample interval min size of a semi the new space consists of two semi spaces max size of the Collect garbage after Collect garbage after keeps maps alive for< n > old space garbage collections print one detailed trace line in name
Definition flags.cc:2086
too high values may cause the compiler to set high thresholds for inlining to as much as possible avoid inlined allocation of objects that cannot escape trace load stores from virtual maglev objects use TurboFan fast string builder analyze liveness of environment slots and zap dead values trace TurboFan load elimination emit data about basic block usage in builtins to this enable builtin reordering when run mksnapshot flag for emit warnings when applying builtin profile data verify register allocation in TurboFan randomly schedule instructions to stress dependency tracking enable store store elimination in TurboFan rewrite far to near simulate GC compiler thread race related to allow float parameters to be passed in simulator mode JS Wasm Run additional turbo_optimize_inlined_js_wasm_wrappers enable experimental feedback collection in generic lowering enable Turboshaft s WasmLoadElimination enable Turboshaft s low level load elimination for JS enable Turboshaft s escape analysis for string concatenation use enable Turbolev features that we want to ship in the not too far future trace individual Turboshaft reduction steps trace intermediate Turboshaft reduction steps invocation count threshold for early optimization Enables optimizations which favor memory size over execution speed Enables sampling allocation profiler with X as a sample interval min size of a semi the new space consists of two semi spaces max size of the Collect garbage after Collect garbage after keeps maps alive for< n > old space garbage collections print one detailed trace line in allocation gc speed threshold for starting incremental marking via a task in percent of available threshold for starting incremental marking immediately in percent of available Use a single schedule for determining a marking schedule between JS and C objects schedules the minor GC task with kUserVisible priority max worker number of concurrent for NumberOfWorkerThreads start background threads that allocate memory concurrent_array_buffer_sweeping use parallel threads to clear weak refs in the atomic pause trace progress of the incremental marking trace object counts and memory usage report a tick only when allocated zone memory changes by this amount TracingFlags::gc_stats TracingFlags::gc_stats track native contexts that are expected to be garbage collected verify heap pointers before and after GC memory reducer runs GC with ReduceMemoryFootprint flag Maximum number of memory reducer GCs scheduled Old gen GC speed is computed directly from gc tracer counters Perform compaction on full GCs based on V8 s default heuristics Perform compaction on every full GC Perform code space compaction when finalizing a full GC with stack Stress GC compaction to flush out bugs with moving objects flush of baseline code when it has not been executed recently Use time base code flushing instead of age Use a progress bar to scan large objects in increments when incremental marking is active force incremental marking for small heaps and run it more often force marking at random points between and force scavenge at random points between and reclaim otherwise unreachable unmodified wrapper objects when possible less compaction in non memory reducing mode use high priority threads for concurrent Marking Test mode only flag It allows an unit test to select evacuation candidates use incremental marking for CppHeap cppheap_concurrent_marking c value for membalancer A special constant to balance between memory and space tradeoff The smaller the more memory it uses enable use of SSE4 instructions if available enable use of AVX VNNI instructions if available enable use of POPCNT instruction if available force all emitted branches to be in long mode(MIPS/PPC only)") DEFINE_BOOL(partial_constant_pool
void Print(Tagged< Object > obj)
Definition objects.h:774
@ SLOPPY_FUNCTION_NAME_VARIABLE
Definition globals.h:2113
@ SLOPPY_BLOCK_FUNCTION_VARIABLE
Definition globals.h:2112
bool BindsSuper(FunctionKind kind)
bool is_strict(LanguageMode language_mode)
Definition globals.h:777
V8_EXPORT_PRIVATE FlagValues v8_flags
bool IsClassMembersInitializerFunction(FunctionKind kind)
bool IsPrivateMethodOrAccessorVariableMode(VariableMode mode)
Definition globals.h:2135
!IsContextMap this
Definition map-inl.h:872
bool IsDynamicVariableMode(VariableMode mode)
Definition globals.h:2116
bool IsImmutableLexicalOrPrivateVariableMode(VariableMode mode)
Definition globals.h:2150
bool IsDefaultConstructor(FunctionKind kind)
bool IsComplementaryAccessorPair(VariableMode a, VariableMode b)
Definition scopes.cc:2945
const char * FunctionKind2String(FunctionKind kind)
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
Definition casting.h:150
#define RCS_SCOPE(...)
#define DCHECK_NULL(val)
Definition logging.h:491
#define CHECK(condition)
Definition logging.h:124
#define DCHECK_NOT_NULL(val)
Definition logging.h:492
#define DCHECK_IMPLIES(v1, v2)
Definition logging.h:493
#define DCHECK_NE(v1, v2)
Definition logging.h:486
#define CHECK_EQ(lhs, rhs)
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
#define DCHECK_GT(v1, v2)
Definition logging.h:487
#define V8_EXPORT_PRIVATE
Definition macros.h:460
UnresolvedList unresolved_private_names
Definition scopes.h:1502
MaybeAssignedFlag maybe_assigned_flag
Definition scope-info.h:40
Symbol declaration
Symbol statement
#define V8_LIKELY(condition)
Definition v8config.h:661
#define V8_UNLIKELY(condition)
Definition v8config.h:660