Bug Summary

File:out/../deps/v8/src/ast/scopes.cc
Warning:line 1159, column 54
Dereference of null pointer (loaded from variable 'sloppy_mode_block_scope_function_redefinition')

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name scopes.cc -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/home/maurizio/node-v18.6.0/out -resource-dir /usr/local/lib/clang/16.0.0 -D _GLIBCXX_USE_CXX11_ABI=1 -D NODE_OPENSSL_CONF_NAME=nodejs_conf -D NODE_OPENSSL_HAS_QUIC -D V8_GYP_BUILD -D V8_TYPED_ARRAY_MAX_SIZE_IN_HEAP=64 -D __STDC_FORMAT_MACROS -D OPENSSL_NO_PINSHARED -D OPENSSL_THREADS -D V8_TARGET_ARCH_X64 -D V8_HAVE_TARGET_OS -D V8_TARGET_OS_LINUX -D V8_EMBEDDER_STRING="-node.8" -D ENABLE_DISASSEMBLER -D V8_PROMISE_INTERNAL_FIELD_COUNT=1 -D V8_SHORT_BUILTIN_CALLS -D OBJECT_PRINT -D V8_INTL_SUPPORT -D V8_ATOMIC_OBJECT_FIELD_WRITES -D V8_ENABLE_LAZY_SOURCE_POSITIONS -D V8_USE_SIPHASH -D V8_SHARED_RO_HEAP -D V8_WIN64_UNWINDING_INFO -D V8_ENABLE_REGEXP_INTERPRETER_THREADED_DISPATCH -D V8_SNAPSHOT_COMPRESSION -D V8_ENABLE_WEBASSEMBLY -D V8_ENABLE_JAVASCRIPT_PROMISE_HOOKS -D V8_ALLOCATION_FOLDING -D V8_ALLOCATION_SITE_TRACKING -D V8_SCRIPTORMODULE_LEGACY_LIFETIME -D V8_ADVANCED_BIGINT_ALGORITHMS -D ICU_UTIL_DATA_IMPL=ICU_UTIL_DATA_STATIC -D UCONFIG_NO_SERVICE=1 -D U_ENABLE_DYLOAD=0 -D U_STATIC_IMPLEMENTATION=1 -D U_HAVE_STD_STRING=1 -D UCONFIG_NO_BREAK_ITERATION=0 -I ../deps/v8 -I ../deps/v8/include -I /home/maurizio/node-v18.6.0/out/Release/obj/gen/inspector-generated-output-root -I ../deps/v8/third_party/inspector_protocol -I /home/maurizio/node-v18.6.0/out/Release/obj/gen -I /home/maurizio/node-v18.6.0/out/Release/obj/gen/generate-bytecode-output-root -I ../deps/icu-small/source/i18n -I ../deps/icu-small/source/common -I ../deps/v8/third_party/zlib -I ../deps/v8/third_party/zlib/google -internal-isystem /usr/lib/gcc/x86_64-redhat-linux/8/../../../../include/c++/8 -internal-isystem /usr/lib/gcc/x86_64-redhat-linux/8/../../../../include/c++/8/x86_64-redhat-linux -internal-isystem /usr/lib/gcc/x86_64-redhat-linux/8/../../../../include/c++/8/backward -internal-isystem /usr/local/lib/clang/16.0.0/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-redhat-linux/8/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O3 -Wno-unused-parameter -Wno-return-type -std=gnu++17 -fdeprecated-macro -fdebug-compilation-dir=/home/maurizio/node-v18.6.0/out -ferror-limit 19 -fno-rtti -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2022-08-22-142216-507842-1 -x c++ ../deps/v8/src/ast/scopes.cc
1// Copyright 2012 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "src/ast/scopes.h"
6
7#include <set>
8
9#include "src/ast/ast.h"
10#include "src/base/logging.h"
11#include "src/base/optional.h"
12#include "src/builtins/accessors.h"
13#include "src/common/message-template.h"
14#include "src/heap/local-factory-inl.h"
15#include "src/init/bootstrapper.h"
16#include "src/logging/runtime-call-stats-scope.h"
17#include "src/objects/module-inl.h"
18#include "src/objects/objects-inl.h"
19#include "src/objects/scope-info.h"
20#include "src/objects/string-set-inl.h"
21#include "src/parsing/parse-info.h"
22#include "src/parsing/parser.h"
23#include "src/parsing/preparse-data.h"
24#include "src/zone/zone-list-inl.h"
25#include "src/zone/zone.h"
26
27namespace v8 {
28namespace internal {
29
30// ----------------------------------------------------------------------------
31// Implementation of LocalsMap
32//
33// Note: We are storing the handle locations as key values in the hash map.
34// When inserting a new variable via Declare(), we rely on the fact that
35// the handle location remains alive for the duration of that variable
36// use. Because a Variable holding a handle with the same location exists
37// this is ensured.
38
39static_assert(sizeof(VariableMap) == (sizeof(void*) + 2 * sizeof(uint32_t) +
40 sizeof(ZoneAllocationPolicy)),
41 "Empty base optimization didn't kick in for VariableMap");
42
43VariableMap::VariableMap(Zone* zone)
44 : ZoneHashMap(8, ZoneAllocationPolicy(zone)) {}
45
46VariableMap::VariableMap(const VariableMap& other, Zone* zone)
47 : ZoneHashMap(other, ZoneAllocationPolicy(zone)) {}
48
49Variable* VariableMap::Declare(Zone* zone, Scope* scope,
50 const AstRawString* name, VariableMode mode,
51 VariableKind kind,
52 InitializationFlag initialization_flag,
53 MaybeAssignedFlag maybe_assigned_flag,
54 IsStaticFlag is_static_flag, bool* was_added) {
55 DCHECK_EQ(zone, allocator().zone())((void) 0);
56 // AstRawStrings are unambiguous, i.e., the same string is always represented
57 // by the same AstRawString*.
58 // FIXME(marja): fix the type of Lookup.
59 Entry* p = ZoneHashMap::LookupOrInsert(const_cast<AstRawString*>(name),
60 name->Hash());
61 *was_added = p->value == nullptr;
62 if (*was_added) {
63 // The variable has not been declared yet -> insert it.
64 DCHECK_EQ(name, p->key)((void) 0);
65 Variable* variable =
66 zone->New<Variable>(scope, name, mode, kind, initialization_flag,
67 maybe_assigned_flag, is_static_flag);
68 p->value = variable;
69 }
70 return reinterpret_cast<Variable*>(p->value);
71}
72
73void VariableMap::Remove(Variable* var) {
74 const AstRawString* name = var->raw_name();
75 ZoneHashMap::Remove(const_cast<AstRawString*>(name), name->Hash());
76}
77
78void VariableMap::Add(Variable* var) {
79 const AstRawString* name = var->raw_name();
80 Entry* p = ZoneHashMap::LookupOrInsert(const_cast<AstRawString*>(name),
81 name->Hash());
82 DCHECK_NULL(p->value)((void) 0);
83 DCHECK_EQ(name, p->key)((void) 0);
84 p->value = var;
85}
86
87Variable* VariableMap::Lookup(const AstRawString* name) {
88 Entry* p = ZoneHashMap::Lookup(const_cast<AstRawString*>(name), name->Hash());
89 if (p != nullptr) {
90 DCHECK(reinterpret_cast<const AstRawString*>(p->key) == name)((void) 0);
91 DCHECK_NOT_NULL(p->value)((void) 0);
92 return reinterpret_cast<Variable*>(p->value);
93 }
94 return nullptr;
95}
96
97// ----------------------------------------------------------------------------
98// Implementation of Scope
99
100Scope::Scope(Zone* zone)
101 : outer_scope_(nullptr), variables_(zone), scope_type_(SCRIPT_SCOPE) {
102 SetDefaults();
103}
104
105Scope::Scope(Zone* zone, Scope* outer_scope, ScopeType scope_type)
106 : outer_scope_(outer_scope), variables_(zone), scope_type_(scope_type) {
107 DCHECK_NE(SCRIPT_SCOPE, scope_type)((void) 0);
108 SetDefaults();
109 set_language_mode(outer_scope->language_mode());
110 private_name_lookup_skips_outer_class_ =
111 outer_scope->is_class_scope() &&
112 outer_scope->AsClassScope()->IsParsingHeritage();
113 outer_scope_->AddInnerScope(this);
114}
115
116Variable* Scope::DeclareHomeObjectVariable(AstValueFactory* ast_value_factory) {
117 bool was_added;
118 Variable* home_object_variable = Declare(
119 zone(), ast_value_factory->dot_home_object_string(), VariableMode::kConst,
120 NORMAL_VARIABLE, InitializationFlag::kCreatedInitialized,
121 MaybeAssignedFlag::kNotAssigned, &was_added);
122 DCHECK(was_added)((void) 0);
123 home_object_variable->set_is_used();
124 home_object_variable->ForceContextAllocation();
125 return home_object_variable;
126}
127
128Variable* Scope::DeclareStaticHomeObjectVariable(
129 AstValueFactory* ast_value_factory) {
130 bool was_added;
131 Variable* static_home_object_variable =
132 Declare(zone(), ast_value_factory->dot_static_home_object_string(),
133 VariableMode::kConst, NORMAL_VARIABLE,
134 InitializationFlag::kCreatedInitialized,
135 MaybeAssignedFlag::kNotAssigned, &was_added);
136 DCHECK(was_added)((void) 0);
137 static_home_object_variable->set_is_used();
138 static_home_object_variable->ForceContextAllocation();
139 return static_home_object_variable;
140}
141
142DeclarationScope::DeclarationScope(Zone* zone,
143 AstValueFactory* ast_value_factory,
144 REPLMode repl_mode)
145 : Scope(zone),
146 function_kind_(repl_mode == REPLMode::kYes
147 ? FunctionKind::kAsyncFunction
148 : FunctionKind::kNormalFunction),
149 params_(4, zone) {
150 DCHECK_EQ(scope_type_, SCRIPT_SCOPE)((void) 0);
151 SetDefaults();
152 is_repl_mode_scope_ = repl_mode == REPLMode::kYes;
153 receiver_ = DeclareDynamicGlobal(ast_value_factory->this_string(),
154 THIS_VARIABLE, this);
155}
156
157DeclarationScope::DeclarationScope(Zone* zone, Scope* outer_scope,
158 ScopeType scope_type,
159 FunctionKind function_kind)
160 : Scope(zone, outer_scope, scope_type),
161 function_kind_(function_kind),
162 params_(4, zone) {
163 DCHECK_NE(scope_type, SCRIPT_SCOPE)((void) 0);
164 SetDefaults();
165}
166
167ModuleScope::ModuleScope(DeclarationScope* script_scope,
168 AstValueFactory* avfactory)
169 : DeclarationScope(avfactory->single_parse_zone(), script_scope,
170 MODULE_SCOPE, FunctionKind::kModule),
171 module_descriptor_(
172 avfactory->single_parse_zone()->New<SourceTextModuleDescriptor>(
173 avfactory->single_parse_zone())) {
174 set_language_mode(LanguageMode::kStrict);
175 DeclareThis(avfactory);
176}
177
178ModuleScope::ModuleScope(Handle<ScopeInfo> scope_info,
179 AstValueFactory* avfactory)
180 : DeclarationScope(avfactory->single_parse_zone(), MODULE_SCOPE, avfactory,
181 scope_info),
182 module_descriptor_(nullptr) {
183 set_language_mode(LanguageMode::kStrict);
184}
185
186ClassScope::ClassScope(Zone* zone, Scope* outer_scope, bool is_anonymous)
187 : Scope(zone, outer_scope, CLASS_SCOPE),
188 rare_data_and_is_parsing_heritage_(nullptr),
189 is_anonymous_class_(is_anonymous) {
190 set_language_mode(LanguageMode::kStrict);
191}
192
193template <typename IsolateT>
194ClassScope::ClassScope(IsolateT* isolate, Zone* zone,
195 AstValueFactory* ast_value_factory,
196 Handle<ScopeInfo> scope_info)
197 : Scope(zone, CLASS_SCOPE, ast_value_factory, scope_info),
198 rare_data_and_is_parsing_heritage_(nullptr) {
199 set_language_mode(LanguageMode::kStrict);
200 if (scope_info->ClassScopeHasPrivateBrand()) {
201 Variable* brand =
202 LookupInScopeInfo(ast_value_factory->dot_brand_string(), this);
203 DCHECK_NOT_NULL(brand)((void) 0);
204 EnsureRareData()->brand = brand;
205 }
206
207 // If the class variable is context-allocated and its index is
208 // saved for deserialization, deserialize it.
209 if (scope_info->HasSavedClassVariable()) {
210 String name;
211 int index;
212 std::tie(name, index) = scope_info->SavedClassVariable();
213 DCHECK_EQ(scope_info->ContextLocalMode(index), VariableMode::kConst)((void) 0);
214 DCHECK_EQ(scope_info->ContextLocalInitFlag(index),((void) 0)
215 InitializationFlag::kNeedsInitialization)((void) 0);
216 DCHECK_EQ(scope_info->ContextLocalMaybeAssignedFlag(index),((void) 0)
217 MaybeAssignedFlag::kMaybeAssigned)((void) 0);
218 Variable* var = DeclareClassVariable(
219 ast_value_factory,
220 ast_value_factory->GetString(name,
221 SharedStringAccessGuardIfNeeded(isolate)),
222 kNoSourcePosition);
223 var->AllocateTo(VariableLocation::CONTEXT,
224 Context::MIN_CONTEXT_SLOTS + index);
225 }
226
227 DCHECK(scope_info->HasPositionInfo())((void) 0);
228 set_start_position(scope_info->StartPosition());
229 set_end_position(scope_info->EndPosition());
230}
231template ClassScope::ClassScope(Isolate* isolate, Zone* zone,
232 AstValueFactory* ast_value_factory,
233 Handle<ScopeInfo> scope_info);
234template ClassScope::ClassScope(LocalIsolate* isolate, Zone* zone,
235 AstValueFactory* ast_value_factory,
236 Handle<ScopeInfo> scope_info);
237
238Scope::Scope(Zone* zone, ScopeType scope_type,
239 AstValueFactory* ast_value_factory, Handle<ScopeInfo> scope_info)
240 : outer_scope_(nullptr),
241 variables_(zone),
242 scope_info_(scope_info),
243 scope_type_(scope_type) {
244 DCHECK(!scope_info.is_null())((void) 0);
245 SetDefaults();
246#ifdef DEBUG
247 already_resolved_ = true;
248#endif
249 set_language_mode(scope_info->language_mode());
250 DCHECK_EQ(ContextHeaderLength(), num_heap_slots_)((void) 0);
251 private_name_lookup_skips_outer_class_ =
252 scope_info->PrivateNameLookupSkipsOuterClass();
253 // We don't really need to use the preparsed scope data; this is just to
254 // shorten the recursion in SetMustUsePreparseData.
255 must_use_preparsed_scope_data_ = true;
256
257 if (scope_type == BLOCK_SCOPE) {
258 // Set is_block_scope_for_object_literal_ based on the existince of the home
259 // object variable (we don't store it explicitly).
260 DCHECK_NOT_NULL(ast_value_factory)((void) 0);
261 int home_object_index = scope_info->ContextSlotIndex(
262 ast_value_factory->dot_home_object_string()->string());
263 DCHECK_IMPLIES(home_object_index >= 0,((void) 0)
264 scope_type == CLASS_SCOPE || scope_type == BLOCK_SCOPE)((void) 0);
265 if (home_object_index >= 0) {
266 is_block_scope_for_object_literal_ = true;
267 }
268 }
269}
270
271DeclarationScope::DeclarationScope(Zone* zone, ScopeType scope_type,
272 AstValueFactory* ast_value_factory,
273 Handle<ScopeInfo> scope_info)
274 : Scope(zone, scope_type, ast_value_factory, scope_info),
275 function_kind_(scope_info->function_kind()),
276 params_(0, zone) {
277 DCHECK_NE(scope_type, SCRIPT_SCOPE)((void) 0);
278 SetDefaults();
279 if (scope_info->SloppyEvalCanExtendVars()) {
280 DCHECK(!is_eval_scope())((void) 0);
281 sloppy_eval_can_extend_vars_ = true;
282 }
283 if (scope_info->ClassScopeHasPrivateBrand()) {
284 DCHECK(IsClassConstructor(function_kind()))((void) 0);
285 class_scope_has_private_brand_ = true;
286 }
287}
288
289Scope::Scope(Zone* zone, const AstRawString* catch_variable_name,
290 MaybeAssignedFlag maybe_assigned, Handle<ScopeInfo> scope_info)
291 : outer_scope_(nullptr),
292 variables_(zone),
293 scope_info_(scope_info),
294 scope_type_(CATCH_SCOPE) {
295 SetDefaults();
296#ifdef DEBUG
297 already_resolved_ = true;
298#endif
299 // Cache the catch variable, even though it's also available via the
300 // scope_info, as the parser expects that a catch scope always has the catch
301 // variable as first and only variable.
302 bool was_added;
303 Variable* variable =
304 Declare(zone, catch_variable_name, VariableMode::kVar, NORMAL_VARIABLE,
305 kCreatedInitialized, maybe_assigned, &was_added);
306 DCHECK(was_added)((void) 0);
307 AllocateHeapSlot(variable);
308}
309
310void DeclarationScope::SetDefaults() {
311 is_declaration_scope_ = true;
312 has_simple_parameters_ = true;
313#if V8_ENABLE_WEBASSEMBLY1
314 is_asm_module_ = false;
315#endif // V8_ENABLE_WEBASSEMBLY
316 force_eager_compilation_ = false;
317 has_arguments_parameter_ = false;
318 uses_super_property_ = false;
319 has_checked_syntax_ = false;
320 has_this_reference_ = false;
321 has_this_declaration_ =
322 (is_function_scope() && !is_arrow_scope()) || is_module_scope();
323 needs_private_name_context_chain_recalc_ = false;
324 has_rest_ = false;
325 receiver_ = nullptr;
326 new_target_ = nullptr;
327 function_ = nullptr;
328 arguments_ = nullptr;
329 rare_data_ = nullptr;
330 should_eager_compile_ = false;
331 was_lazily_parsed_ = false;
332 is_skipped_function_ = false;
333 preparse_data_builder_ = nullptr;
334 class_scope_has_private_brand_ = false;
335#ifdef DEBUG
336 DeclarationScope* outer_declaration_scope =
337 outer_scope_ ? outer_scope_->GetDeclarationScope() : nullptr;
338 is_being_lazily_parsed_ =
339 outer_declaration_scope ? outer_declaration_scope->is_being_lazily_parsed_
340 : false;
341#endif
342}
343
344void Scope::SetDefaults() {
345#ifdef DEBUG
346 scope_name_ = nullptr;
347 already_resolved_ = false;
348 needs_migration_ = false;
349#endif
350 inner_scope_ = nullptr;
351 sibling_ = nullptr;
352 unresolved_list_.Clear();
353
354 start_position_ = kNoSourcePosition;
355 end_position_ = kNoSourcePosition;
356
357 calls_eval_ = false;
358 sloppy_eval_can_extend_vars_ = false;
359 scope_nonlinear_ = false;
360 is_hidden_ = false;
361 is_debug_evaluate_scope_ = false;
362
363 inner_scope_calls_eval_ = false;
364 force_context_allocation_for_parameters_ = false;
365
366 is_declaration_scope_ = false;
367
368 private_name_lookup_skips_outer_class_ = false;
369
370 must_use_preparsed_scope_data_ = false;
371 is_repl_mode_scope_ = false;
372
373 deserialized_scope_uses_external_cache_ = false;
374
375 needs_home_object_ = false;
376 is_block_scope_for_object_literal_ = false;
377
378 num_stack_slots_ = 0;
379 num_heap_slots_ = ContextHeaderLength();
380
381 set_language_mode(LanguageMode::kSloppy);
382}
383
384bool Scope::HasSimpleParameters() {
385 DeclarationScope* scope = GetClosureScope();
386 return !scope->is_function_scope() || scope->has_simple_parameters();
387}
388
389void DeclarationScope::set_should_eager_compile() {
390 should_eager_compile_ = !was_lazily_parsed_;
391}
392
393#if V8_ENABLE_WEBASSEMBLY1
394void DeclarationScope::set_is_asm_module() { is_asm_module_ = true; }
395
396bool Scope::IsAsmModule() const {
397 return is_function_scope() && AsDeclarationScope()->is_asm_module();
398}
399
400bool Scope::ContainsAsmModule() const {
401 if (IsAsmModule()) return true;
402
403 // Check inner scopes recursively
404 for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) {
405 // Don't check inner functions which won't be eagerly compiled.
406 if (!scope->is_function_scope() ||
407 scope->AsDeclarationScope()->ShouldEagerCompile()) {
408 if (scope->ContainsAsmModule()) return true;
409 }
410 }
411
412 return false;
413}
414#endif // V8_ENABLE_WEBASSEMBLY
415
416template <typename IsolateT>
417Scope* Scope::DeserializeScopeChain(IsolateT* isolate, Zone* zone,
418 ScopeInfo scope_info,
419 DeclarationScope* script_scope,
420 AstValueFactory* ast_value_factory,
421 DeserializationMode deserialization_mode) {
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 bool cache_scope_found = false;
427 while (!scope_info.is_null()) {
428 if (scope_info.scope_type() == WITH_SCOPE) {
429 if (scope_info.IsDebugEvaluateScope()) {
430 outer_scope =
431 zone->New<DeclarationScope>(zone, FUNCTION_SCOPE, ast_value_factory,
432 handle(scope_info, isolate));
433 outer_scope->set_is_debug_evaluate_scope();
434 } else {
435 // For scope analysis, debug-evaluate is equivalent to a with scope.
436 outer_scope = zone->New<Scope>(zone, WITH_SCOPE, ast_value_factory,
437 handle(scope_info, isolate));
438 }
439
440 } else if (scope_info.scope_type() == SCRIPT_SCOPE) {
441 // If we reach a script scope, it's the outermost scope. Install the
442 // scope info of this script context onto the existing script scope to
443 // avoid nesting script scopes.
444 if (deserialization_mode == DeserializationMode::kIncludingVariables) {
445 script_scope->SetScriptScopeInfo(handle(scope_info, isolate));
446 }
447 if (scope_info.IsReplModeScope()) script_scope->set_is_repl_mode_scope();
448 DCHECK(!scope_info.HasOuterScopeInfo())((void) 0);
449 break;
450 } else if (scope_info.scope_type() == FUNCTION_SCOPE) {
451 outer_scope = zone->New<DeclarationScope>(
452 zone, FUNCTION_SCOPE, ast_value_factory, handle(scope_info, isolate));
453#if V8_ENABLE_WEBASSEMBLY1
454 if (scope_info.IsAsmModule()) {
455 outer_scope->AsDeclarationScope()->set_is_asm_module();
456 }
457#endif // V8_ENABLE_WEBASSEMBLY
458 } else if (scope_info.scope_type() == EVAL_SCOPE) {
459 outer_scope = zone->New<DeclarationScope>(
460 zone, EVAL_SCOPE, ast_value_factory, handle(scope_info, isolate));
461 } else if (scope_info.scope_type() == CLASS_SCOPE) {
462 outer_scope = zone->New<ClassScope>(isolate, zone, ast_value_factory,
463 handle(scope_info, isolate));
464 } else if (scope_info.scope_type() == BLOCK_SCOPE) {
465 if (scope_info.is_declaration_scope()) {
466 outer_scope = zone->New<DeclarationScope>(
467 zone, BLOCK_SCOPE, ast_value_factory, handle(scope_info, isolate));
468 } else {
469 outer_scope = zone->New<Scope>(zone, BLOCK_SCOPE, ast_value_factory,
470 handle(scope_info, isolate));
471 }
472 } else if (scope_info.scope_type() == MODULE_SCOPE) {
473 outer_scope = zone->New<ModuleScope>(handle(scope_info, isolate),
474 ast_value_factory);
475 } else {
476 DCHECK_EQ(scope_info.scope_type(), CATCH_SCOPE)((void) 0);
477 DCHECK_EQ(scope_info.ContextLocalCount(), 1)((void) 0);
478 DCHECK_EQ(scope_info.ContextLocalMode(0), VariableMode::kVar)((void) 0);
479 DCHECK_EQ(scope_info.ContextLocalInitFlag(0), kCreatedInitialized)((void) 0);
480 DCHECK(scope_info.HasInlinedLocalNames())((void) 0);
481 String name = scope_info.ContextInlinedLocalName(0);
482 MaybeAssignedFlag maybe_assigned =
483 scope_info.ContextLocalMaybeAssignedFlag(0);
484 outer_scope =
485 zone->New<Scope>(zone,
486 ast_value_factory->GetString(
487 name, SharedStringAccessGuardIfNeeded(isolate)),
488 maybe_assigned, handle(scope_info, isolate));
489 }
490 if (deserialization_mode == DeserializationMode::kScopesOnly) {
491 outer_scope->scope_info_ = Handle<ScopeInfo>::null();
492 }
493
494 if (cache_scope_found) {
495 outer_scope->set_deserialized_scope_uses_external_cache();
496 } else {
497 DCHECK(!cache_scope_found)((void) 0);
498 cache_scope_found =
499 outer_scope->is_declaration_scope() && !outer_scope->is_eval_scope();
500 }
501
502 if (current_scope != nullptr) {
503 outer_scope->AddInnerScope(current_scope);
504 }
505 current_scope = outer_scope;
506 if (innermost_scope == nullptr) innermost_scope = current_scope;
507 scope_info = scope_info.HasOuterScopeInfo() ? scope_info.OuterScopeInfo()
508 : ScopeInfo();
509 }
510
511 if (deserialization_mode == DeserializationMode::kIncludingVariables) {
512 SetScriptScopeInfo(isolate, script_scope);
513 }
514
515 if (innermost_scope == nullptr) return script_scope;
516 script_scope->AddInnerScope(current_scope);
517 return innermost_scope;
518}
519
520template <typename IsolateT>
521void Scope::SetScriptScopeInfo(IsolateT* isolate,
522 DeclarationScope* script_scope) {
523 if (script_scope->scope_info_.is_null()) {
524 script_scope->SetScriptScopeInfo(
525 ReadOnlyRoots(isolate).global_this_binding_scope_info_handle());
526 }
527}
528
529template EXPORT_TEMPLATE_DEFINE(
530 V8_EXPORT_PRIVATE) void Scope::SetScriptScopeInfo(Isolate* isolate,
531 DeclarationScope*
532 script_scope);
533template EXPORT_TEMPLATE_DEFINE(
534 V8_EXPORT_PRIVATE) void Scope::SetScriptScopeInfo(LocalIsolate* isolate,
535 DeclarationScope*
536 script_scope);
537
538template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)
539 Scope* Scope::DeserializeScopeChain(
540 Isolate* isolate, Zone* zone, ScopeInfo scope_info,
541 DeclarationScope* script_scope, AstValueFactory* ast_value_factory,
542 DeserializationMode deserialization_mode);
543template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)
544 Scope* Scope::DeserializeScopeChain(
545 LocalIsolate* isolate, Zone* zone, ScopeInfo scope_info,
546 DeclarationScope* script_scope, AstValueFactory* ast_value_factory,
547 DeserializationMode deserialization_mode);
548
549#ifdef DEBUG
550bool Scope::IsReparsedMemberInitializerScope() const {
551 return is_declaration_scope() &&
552 IsClassMembersInitializerFunction(
553 AsDeclarationScope()->function_kind()) &&
554 outer_scope()->AsClassScope()->is_reparsed_class_scope();
555}
556#endif
557
558DeclarationScope* Scope::AsDeclarationScope() {
559 DCHECK(is_declaration_scope())((void) 0);
560 return static_cast<DeclarationScope*>(this);
561}
562
563const DeclarationScope* Scope::AsDeclarationScope() const {
564 DCHECK(is_declaration_scope())((void) 0);
565 return static_cast<const DeclarationScope*>(this);
566}
567
568ModuleScope* Scope::AsModuleScope() {
569 DCHECK(is_module_scope())((void) 0);
570 return static_cast<ModuleScope*>(this);
571}
572
573const ModuleScope* Scope::AsModuleScope() const {
574 DCHECK(is_module_scope())((void) 0);
575 return static_cast<const ModuleScope*>(this);
576}
577
578ClassScope* Scope::AsClassScope() {
579 DCHECK(is_class_scope())((void) 0);
580 return static_cast<ClassScope*>(this);
581}
582
583const ClassScope* Scope::AsClassScope() const {
584 DCHECK(is_class_scope())((void) 0);
585 return static_cast<const ClassScope*>(this);
586}
587
588void DeclarationScope::DeclareSloppyBlockFunction(
589 SloppyBlockFunctionStatement* sloppy_block_function) {
590 sloppy_block_functions_.Add(sloppy_block_function);
591}
592
593void DeclarationScope::HoistSloppyBlockFunctions(AstNodeFactory* factory) {
594 DCHECK(is_sloppy(language_mode()))((void) 0);
595 DCHECK(is_function_scope() || is_eval_scope() || is_script_scope() ||((void) 0)
596 (is_block_scope() && outer_scope()->is_function_scope()))((void) 0);
597 DCHECK(HasSimpleParameters() || is_block_scope() || is_being_lazily_parsed_)((void) 0);
598 DCHECK_EQ(factory == nullptr, is_being_lazily_parsed_)((void) 0);
599
600 if (sloppy_block_functions_.is_empty()) return;
3
Assuming the condition is false
601
602 // In case of complex parameters the current scope is the body scope and the
603 // parameters are stored in the outer scope.
604 Scope* parameter_scope = HasSimpleParameters() ? this : outer_scope_;
4
Taking false branch
5
'?' condition is true
605 DCHECK(parameter_scope->is_function_scope() || is_eval_scope() ||((void) 0)
606 is_script_scope())((void) 0);
607
608 DeclarationScope* decl_scope = GetNonEvalDeclarationScope();
609 Scope* outer_scope = decl_scope->outer_scope();
610
611 // For each variable which is used as a function declaration in a sloppy
612 // block,
613 for (SloppyBlockFunctionStatement* sloppy_block_function :
614 sloppy_block_functions_) {
615 const AstRawString* name = sloppy_block_function->name();
616
617 // If the variable wouldn't conflict with a lexical declaration
618 // or parameter,
619
620 // Check if there's a conflict with a parameter.
621 Variable* maybe_parameter = parameter_scope->LookupLocal(name);
622 if (maybe_parameter != nullptr && maybe_parameter->is_parameter()) {
623 continue;
624 }
625
626 // Check if there's a conflict with a lexical declaration
627 Scope* query_scope = sloppy_block_function->scope()->outer_scope();
628 bool should_hoist = true;
629
630 // It is not sufficient to just do a Lookup on query_scope: for
631 // example, that does not prevent hoisting of the function in
632 // `{ let e; try {} catch (e) { function e(){} } }`
633 //
634 // Don't use a generic cache scope, as the cache scope would be the outer
635 // scope and we terminate the iteration there anyway.
636 do {
7
Loop condition is false. Exiting loop
637 Variable* var = query_scope->LookupInScopeOrScopeInfo(name, query_scope);
638 if (var != nullptr && IsLexicalVariableMode(var->mode())) {
639 should_hoist = false;
640 break;
641 }
642 query_scope = query_scope->outer_scope();
643 } while (query_scope != outer_scope);
6
Assuming 'query_scope' is equal to 'outer_scope'
644
645 if (!should_hoist
7.1
'should_hoist' is true
) continue;
8
Taking false branch
646
647 if (factory
8.1
'factory' is non-null
) {
9
Taking true branch
648 DCHECK(!is_being_lazily_parsed_)((void) 0);
649 int pos = sloppy_block_function->position();
650 bool ok = true;
651 bool was_added;
652 auto declaration = factory->NewVariableDeclaration(pos);
653 // Based on the preceding checks, it doesn't matter what we pass as
654 // sloppy_mode_block_scope_function_redefinition.
655 Variable* var = DeclareVariable(
11
Calling 'Scope::DeclareVariable'
656 declaration, name, pos, VariableMode::kVar, NORMAL_VARIABLE,
657 Variable::DefaultInitializationFlag(VariableMode::kVar), &was_added,
658 nullptr, &ok);
10
Passing null pointer value via 8th parameter 'sloppy_mode_block_scope_function_redefinition'
659 DCHECK(ok)((void) 0);
660 VariableProxy* source =
661 factory->NewVariableProxy(sloppy_block_function->var());
662 VariableProxy* target = factory->NewVariableProxy(var);
663 Assignment* assignment = factory->NewAssignment(
664 sloppy_block_function->init(), target, source, pos);
665 assignment->set_lookup_hoisting_mode(LookupHoistingMode::kLegacySloppy);
666 Statement* statement = factory->NewExpressionStatement(assignment, pos);
667 sloppy_block_function->set_statement(statement);
668 } else {
669 DCHECK(is_being_lazily_parsed_)((void) 0);
670 bool was_added;
671 Variable* var = DeclareVariableName(name, VariableMode::kVar, &was_added);
672 if (sloppy_block_function->init() == Token::ASSIGN) {
673 var->SetMaybeAssigned();
674 }
675 }
676 }
677}
678
679bool DeclarationScope::Analyze(ParseInfo* info) {
680 RCS_SCOPE(info->runtime_call_stats(),
681 RuntimeCallCounterId::kCompileScopeAnalysis,
682 RuntimeCallStats::kThreadSpecific);
683 DCHECK_NOT_NULL(info->literal())((void) 0);
684 DeclarationScope* scope = info->literal()->scope();
685
686 base::Optional<AllowHandleDereference> allow_deref;
687#ifdef DEBUG
688 if (scope->outer_scope() && !scope->outer_scope()->scope_info_.is_null()) {
689 allow_deref.emplace();
690 }
691#endif
692
693 if (scope->is_eval_scope() && is_sloppy(scope->language_mode())) {
1
Taking true branch
694 AstNodeFactory factory(info->ast_value_factory(), info->zone());
695 scope->HoistSloppyBlockFunctions(&factory);
2
Calling 'DeclarationScope::HoistSloppyBlockFunctions'
696 }
697
698 // We are compiling one of four cases:
699 // 1) top-level code,
700 // 2) a function/eval/module on the top-level
701 // 4) a class member initializer function scope
702 // 3) 4 function/eval in a scope that was already resolved.
703 DCHECK(scope->is_script_scope() || scope->outer_scope()->is_script_scope() ||((void) 0)
704 scope->IsReparsedMemberInitializerScope() ||((void) 0)
705 scope->outer_scope()->already_resolved_)((void) 0);
706
707 // The outer scope is never lazy.
708 scope->set_should_eager_compile();
709
710 if (scope->must_use_preparsed_scope_data_) {
711 DCHECK_EQ(scope->scope_type_, ScopeType::FUNCTION_SCOPE)((void) 0);
712 allow_deref.emplace();
713 info->consumed_preparse_data()->RestoreScopeAllocationData(
714 scope, info->ast_value_factory(), info->zone());
715 }
716
717 if (!scope->AllocateVariables(info)) return false;
718 scope->GetScriptScope()->RewriteReplGlobalVariables();
719
720#ifdef DEBUG
721 if (FLAG_print_scopes) {
722 PrintF("Global scope:\n");
723 scope->Print();
724 }
725 scope->CheckScopePositions();
726 scope->CheckZones();
727#endif
728
729 return true;
730}
731
732void DeclarationScope::DeclareThis(AstValueFactory* ast_value_factory) {
733 DCHECK(has_this_declaration())((void) 0);
734
735 bool derived_constructor = IsDerivedConstructor(function_kind_);
736
737 receiver_ = zone()->New<Variable>(
738 this, ast_value_factory->this_string(),
739 derived_constructor ? VariableMode::kConst : VariableMode::kVar,
740 THIS_VARIABLE,
741 derived_constructor ? kNeedsInitialization : kCreatedInitialized,
742 kNotAssigned);
743 locals_.Add(receiver_);
744}
745
746void DeclarationScope::DeclareArguments(AstValueFactory* ast_value_factory) {
747 DCHECK(is_function_scope())((void) 0);
748 DCHECK(!is_arrow_scope())((void) 0);
749
750 // Because when arguments_ is not nullptr, we already declared
751 // "arguments exotic object" to add it into parameters before
752 // impl()->InsertShadowingVarBindingInitializers, so here
753 // only declare "arguments exotic object" when arguments_
754 // is nullptr
755 if (arguments_ != nullptr) {
756 return;
757 }
758
759 // Declare 'arguments' variable which exists in all non arrow functions. Note
760 // that it might never be accessed, in which case it won't be allocated during
761 // variable allocation.
762 bool was_added = false;
763
764 arguments_ =
765 Declare(zone(), ast_value_factory->arguments_string(), VariableMode::kVar,
766 NORMAL_VARIABLE, kCreatedInitialized, kNotAssigned, &was_added);
767 // According to ES#sec-functiondeclarationinstantiation step 18
768 // we should set argumentsObjectNeeded to false if has lexical
769 // declared arguments only when hasParameterExpressions is false
770 if (!was_added && IsLexicalVariableMode(arguments_->mode()) &&
771 has_simple_parameters_) {
772 // Check if there's lexically declared variable named arguments to avoid
773 // redeclaration. See ES#sec-functiondeclarationinstantiation, step 20.
774 arguments_ = nullptr;
775 }
776}
777
778void DeclarationScope::DeclareDefaultFunctionVariables(
779 AstValueFactory* ast_value_factory) {
780 DCHECK(is_function_scope())((void) 0);
781 DCHECK(!is_arrow_scope())((void) 0);
782
783 DeclareThis(ast_value_factory);
784 bool was_added;
785 new_target_ = Declare(zone(), ast_value_factory->new_target_string(),
786 VariableMode::kConst, NORMAL_VARIABLE,
787 kCreatedInitialized, kNotAssigned, &was_added);
788 DCHECK(was_added)((void) 0);
789
790 if (IsConciseMethod(function_kind_) || IsClassConstructor(function_kind_) ||
791 IsAccessorFunction(function_kind_)) {
792 EnsureRareData()->this_function = Declare(
793 zone(), ast_value_factory->this_function_string(), VariableMode::kConst,
794 NORMAL_VARIABLE, kCreatedInitialized, kNotAssigned, &was_added);
795 DCHECK(was_added)((void) 0);
796 }
797}
798
799Variable* DeclarationScope::DeclareFunctionVar(const AstRawString* name,
800 Scope* cache) {
801 DCHECK(is_function_scope())((void) 0);
802 DCHECK_NULL(function_)((void) 0);
803 if (cache == nullptr) cache = this;
804 DCHECK(this->IsOuterScopeOf(cache))((void) 0);
805 DCHECK_NULL(cache->variables_.Lookup(name))((void) 0);
806 VariableKind kind = is_sloppy(language_mode()) ? SLOPPY_FUNCTION_NAME_VARIABLE
807 : NORMAL_VARIABLE;
808 function_ = zone()->New<Variable>(this, name, VariableMode::kConst, kind,
809 kCreatedInitialized);
810 if (sloppy_eval_can_extend_vars()) {
811 cache->NonLocal(name, VariableMode::kDynamic);
812 } else {
813 cache->variables_.Add(function_);
814 }
815 return function_;
816}
817
818Variable* DeclarationScope::DeclareGeneratorObjectVar(
819 const AstRawString* name) {
820 DCHECK(is_function_scope() || is_module_scope() || is_repl_mode_scope())((void) 0);
821 DCHECK_NULL(generator_object_var())((void) 0);
822
823 Variable* result = EnsureRareData()->generator_object =
824 NewTemporary(name, kNotAssigned);
825 result->set_is_used();
826 return result;
827}
828
829Scope* Scope::FinalizeBlockScope() {
830 DCHECK(is_block_scope())((void) 0);
831#ifdef DEBUG
832 DCHECK_NE(sibling_, this)((void) 0);
833#endif
834
835 if (variables_.occupancy() > 0 ||
836 (is_declaration_scope() &&
837 AsDeclarationScope()->sloppy_eval_can_extend_vars())) {
838 return this;
839 }
840
841 DCHECK(!is_class_scope())((void) 0);
842
843 // Remove this scope from outer scope.
844 outer_scope()->RemoveInnerScope(this);
845
846 // Reparent inner scopes.
847 if (inner_scope_ != nullptr) {
848 Scope* scope = inner_scope_;
849 scope->outer_scope_ = outer_scope();
850 while (scope->sibling_ != nullptr) {
851 scope = scope->sibling_;
852 scope->outer_scope_ = outer_scope();
853 }
854 scope->sibling_ = outer_scope()->inner_scope_;
855 outer_scope()->inner_scope_ = inner_scope_;
856 inner_scope_ = nullptr;
857 }
858
859 // Move unresolved variables
860 if (!unresolved_list_.is_empty()) {
861 outer_scope()->unresolved_list_.Prepend(std::move(unresolved_list_));
862 unresolved_list_.Clear();
863 }
864
865 if (inner_scope_calls_eval_) outer_scope()->inner_scope_calls_eval_ = true;
866
867 // No need to propagate sloppy_eval_can_extend_vars_, since if it was relevant
868 // to this scope we would have had to bail out at the top.
869 DCHECK(!is_declaration_scope() ||((void) 0)
870 !AsDeclarationScope()->sloppy_eval_can_extend_vars())((void) 0);
871
872 // This block does not need a context.
873 num_heap_slots_ = 0;
874
875 // Mark scope as removed by making it its own sibling.
876#ifdef DEBUG
877 sibling_ = this;
878#endif
879
880 return nullptr;
881}
882
883void DeclarationScope::AddLocal(Variable* var) {
884 DCHECK(!already_resolved_)((void) 0);
885 // Temporaries are only placed in ClosureScopes.
886 DCHECK_EQ(GetClosureScope(), this)((void) 0);
887 locals_.Add(var);
888}
889
890void Scope::Snapshot::Reparent(DeclarationScope* new_parent) {
891 DCHECK(!IsCleared())((void) 0);
892 DCHECK_EQ(new_parent, outer_scope_and_calls_eval_.GetPointer()->inner_scope_)((void) 0);
893 DCHECK_EQ(new_parent->outer_scope_, outer_scope_and_calls_eval_.GetPointer())((void) 0);
894 DCHECK_EQ(new_parent, new_parent->GetClosureScope())((void) 0);
895 DCHECK_NULL(new_parent->inner_scope_)((void) 0);
896 DCHECK(new_parent->unresolved_list_.is_empty())((void) 0);
897 Scope* inner_scope = new_parent->sibling_;
898 if (inner_scope != top_inner_scope_) {
899 for (; inner_scope->sibling() != top_inner_scope_;
900 inner_scope = inner_scope->sibling()) {
901 inner_scope->outer_scope_ = new_parent;
902 if (inner_scope->inner_scope_calls_eval_) {
903 new_parent->inner_scope_calls_eval_ = true;
904 }
905 DCHECK_NE(inner_scope, new_parent)((void) 0);
906 }
907 inner_scope->outer_scope_ = new_parent;
908 if (inner_scope->inner_scope_calls_eval_) {
909 new_parent->inner_scope_calls_eval_ = true;
910 }
911 new_parent->inner_scope_ = new_parent->sibling_;
912 inner_scope->sibling_ = nullptr;
913 // Reset the sibling rather than the inner_scope_ since we
914 // want to keep new_parent there.
915 new_parent->sibling_ = top_inner_scope_;
916 }
917
918 Scope* outer_scope = outer_scope_and_calls_eval_.GetPointer();
919 new_parent->unresolved_list_.MoveTail(&outer_scope->unresolved_list_,
920 top_unresolved_);
921
922 // Move temporaries allocated for complex parameter initializers.
923 DeclarationScope* outer_closure = outer_scope->GetClosureScope();
924 for (auto it = top_local_; it != outer_closure->locals()->end(); ++it) {
925 Variable* local = *it;
926 DCHECK_EQ(VariableMode::kTemporary, local->mode())((void) 0);
927 DCHECK_EQ(local->scope(), local->scope()->GetClosureScope())((void) 0);
928 DCHECK_NE(local->scope(), new_parent)((void) 0);
929 local->set_scope(new_parent);
930 }
931 new_parent->locals_.MoveTail(outer_closure->locals(), top_local_);
932 outer_closure->locals_.Rewind(top_local_);
933
934 // Move eval calls since Snapshot's creation into new_parent.
935 if (outer_scope_and_calls_eval_->calls_eval_) {
936 new_parent->RecordDeclarationScopeEvalCall();
937 new_parent->inner_scope_calls_eval_ = true;
938 }
939
940 // We are in the arrow function case. The calls eval we may have recorded
941 // is intended for the inner scope and we should simply restore the
942 // original "calls eval" flag of the outer scope.
943 RestoreEvalFlag();
944 Clear();
945}
946
947void Scope::ReplaceOuterScope(Scope* outer) {
948 DCHECK_NOT_NULL(outer)((void) 0);
949 DCHECK_NOT_NULL(outer_scope_)((void) 0);
950 DCHECK(!already_resolved_)((void) 0);
951 outer_scope_->RemoveInnerScope(this);
952 outer->AddInnerScope(this);
953 outer_scope_ = outer;
954}
955
956Variable* Scope::LookupInScopeInfo(const AstRawString* name, Scope* cache) {
957 DCHECK(!scope_info_.is_null())((void) 0);
958 DCHECK(this->IsOuterScopeOf(cache))((void) 0);
959 DCHECK(!cache->deserialized_scope_uses_external_cache())((void) 0);
960 // The case where where the cache can be another scope is when the cache scope
961 // is the last scope that doesn't use an external cache.
962 DCHECK_IMPLIES(((void) 0)
963 cache != this,((void) 0)
964 cache->outer_scope()->deserialized_scope_uses_external_cache())((void) 0);
965 DCHECK_NULL(cache->variables_.Lookup(name))((void) 0);
966 DisallowGarbageCollection no_gc;
967
968 String name_handle = *name->string();
969 ScopeInfo scope_info = *scope_info_;
970 // The Scope is backed up by ScopeInfo. This means it cannot operate in a
971 // heap-independent mode, and all strings must be internalized immediately. So
972 // it's ok to get the Handle<String> here.
973 bool found = false;
974
975 VariableLocation location;
976 int index;
977 VariableLookupResult lookup_result;
978
979 {
980 location = VariableLocation::CONTEXT;
981 index = scope_info.ContextSlotIndex(name->string(), &lookup_result);
982 found = index >= 0;
983 }
984
985 if (!found && is_module_scope()) {
986 location = VariableLocation::MODULE;
987 index = scope_info.ModuleIndex(name_handle, &lookup_result.mode,
988 &lookup_result.init_flag,
989 &lookup_result.maybe_assigned_flag);
990 found = index != 0;
991 }
992
993 if (!found) {
994 index = scope_info.FunctionContextSlotIndex(name_handle);
995 if (index < 0) return nullptr; // Nowhere found.
996 Variable* var = AsDeclarationScope()->DeclareFunctionVar(name, cache);
997 DCHECK_EQ(VariableMode::kConst, var->mode())((void) 0);
998 var->AllocateTo(VariableLocation::CONTEXT, index);
999 return cache->variables_.Lookup(name);
1000 }
1001
1002 if (!is_module_scope()) {
1003 DCHECK_NE(index, scope_info.ReceiverContextSlotIndex())((void) 0);
1004 }
1005
1006 bool was_added;
1007 Variable* var = cache->variables_.Declare(
1008 zone(), this, name, lookup_result.mode, NORMAL_VARIABLE,
1009 lookup_result.init_flag, lookup_result.maybe_assigned_flag,
1010 IsStaticFlag::kNotStatic, &was_added);
1011 DCHECK(was_added)((void) 0);
1012 var->AllocateTo(location, index);
1013 return var;
1014}
1015
1016Variable* DeclarationScope::DeclareParameter(const AstRawString* name,
1017 VariableMode mode,
1018 bool is_optional, bool is_rest,
1019 AstValueFactory* ast_value_factory,
1020 int position) {
1021 DCHECK(!already_resolved_)((void) 0);
1022 DCHECK(is_function_scope() || is_module_scope())((void) 0);
1023 DCHECK(!has_rest_)((void) 0);
1024 DCHECK(!is_optional || !is_rest)((void) 0);
1025 DCHECK(!is_being_lazily_parsed_)((void) 0);
1026 DCHECK(!was_lazily_parsed_)((void) 0);
1027 Variable* var;
1028 if (mode == VariableMode::kTemporary) {
1029 var = NewTemporary(name);
1030 } else {
1031 var = LookupLocal(name);
1032 DCHECK_EQ(mode, VariableMode::kVar)((void) 0);
1033 DCHECK(var->is_parameter())((void) 0);
1034 }
1035 has_rest_ = is_rest;
1036 var->set_initializer_position(position);
1037 params_.Add(var, zone());
1038 if (!is_rest) ++num_parameters_;
1039 if (name == ast_value_factory->arguments_string()) {
1040 has_arguments_parameter_ = true;
1041 }
1042 // Params are automatically marked as used to make sure that the debugger and
1043 // function.arguments sees them.
1044 // TODO(verwaest): Reevaluate whether we always need to do this, since
1045 // strict-mode function.arguments does not make the arguments available.
1046 var->set_is_used();
1047 return var;
1048}
1049
1050void DeclarationScope::RecordParameter(bool is_rest) {
1051 DCHECK(!already_resolved_)((void) 0);
1052 DCHECK(is_function_scope() || is_module_scope())((void) 0);
1053 DCHECK(is_being_lazily_parsed_)((void) 0);
1054 DCHECK(!has_rest_)((void) 0);
1055 has_rest_ = is_rest;
1056 if (!is_rest) ++num_parameters_;
1057}
1058
1059Variable* Scope::DeclareLocal(const AstRawString* name, VariableMode mode,
1060 VariableKind kind, bool* was_added,
1061 InitializationFlag init_flag) {
1062 DCHECK(!already_resolved_)((void) 0);
1063 // Private methods should be declared with ClassScope::DeclarePrivateName()
1064 DCHECK(!IsPrivateMethodOrAccessorVariableMode(mode))((void) 0);
1065 // This function handles VariableMode::kVar, VariableMode::kLet, and
1066 // VariableMode::kConst modes. VariableMode::kDynamic variables are
1067 // introduced during variable allocation, and VariableMode::kTemporary
1068 // variables are allocated via NewTemporary().
1069 DCHECK(IsDeclaredVariableMode(mode))((void) 0);
1070 DCHECK_IMPLIES(GetDeclarationScope()->is_being_lazily_parsed(),((void) 0)
1071 mode == VariableMode::kVar || mode == VariableMode::kLet ||((void) 0)
1072 mode == VariableMode::kConst)((void) 0);
1073 DCHECK(!GetDeclarationScope()->was_lazily_parsed())((void) 0);
1074 Variable* var =
1075 Declare(zone(), name, mode, kind, init_flag, kNotAssigned, was_added);
1076
1077 // Pessimistically assume that top-level variables will be assigned and used.
1078 //
1079 // Top-level variables in a script can be accessed by other scripts or even
1080 // become global properties. While this does not apply to top-level variables
1081 // in a module (assuming they are not exported), we must still mark these as
1082 // assigned because they might be accessed by a lazily parsed top-level
1083 // function, which, for efficiency, we preparse without variable tracking.
1084 if (is_script_scope() || is_module_scope()) {
1085 if (mode != VariableMode::kConst) var->SetMaybeAssigned();
1086 var->set_is_used();
1087 }
1088
1089 return var;
1090}
1091
1092Variable* Scope::DeclareVariable(
1093 Declaration* declaration, const AstRawString* name, int pos,
1094 VariableMode mode, VariableKind kind, InitializationFlag init,
1095 bool* was_added, bool* sloppy_mode_block_scope_function_redefinition,
1096 bool* ok) {
1097 // Private methods should be declared with ClassScope::DeclarePrivateName()
1098 DCHECK(!IsPrivateMethodOrAccessorVariableMode(mode))((void) 0);
1099 DCHECK(IsDeclaredVariableMode(mode))((void) 0);
1100 DCHECK(!already_resolved_)((void) 0);
1101 DCHECK(!GetDeclarationScope()->is_being_lazily_parsed())((void) 0);
1102 DCHECK(!GetDeclarationScope()->was_lazily_parsed())((void) 0);
1103
1104 if (mode
11.1
'mode' is equal to kVar
15.1
'mode' is equal to kVar
19.1
'mode' is equal to kVar
== VariableMode::kVar && !is_declaration_scope()) {
12
Assuming the condition is true
13
Taking true branch
16
Assuming the condition is true
17
Taking true branch
20
Assuming the condition is false
21
Taking false branch
1105 return GetDeclarationScope()->DeclareVariable(
15
Calling 'Scope::DeclareVariable'
19
Calling 'Scope::DeclareVariable'
1106 declaration, name, pos, mode, kind, init, was_added,
1107 sloppy_mode_block_scope_function_redefinition, ok);
14
Passing null pointer value via 8th parameter 'sloppy_mode_block_scope_function_redefinition'
18
Passing null pointer value via 8th parameter 'sloppy_mode_block_scope_function_redefinition'
1108 }
1109 DCHECK(!is_catch_scope())((void) 0);
1110 DCHECK(!is_with_scope())((void) 0);
1111 DCHECK(is_declaration_scope() ||((void) 0)
1112 (IsLexicalVariableMode(mode) && is_block_scope()))((void) 0);
1113
1114 DCHECK_NOT_NULL(name)((void) 0);
1115
1116 Variable* var = LookupLocal(name);
1117 // Declare the variable in the declaration scope.
1118 *was_added = var == nullptr;
22
Assuming the condition is false
1119 if (V8_LIKELY(*was_added)(__builtin_expect(!!(*was_added), 1))) {
23
Taking false branch
1120 if (V8_UNLIKELY(is_eval_scope() && is_sloppy(language_mode()) &&(__builtin_expect(!!(is_eval_scope() && is_sloppy(language_mode
()) && mode == VariableMode::kVar), 0))
1121 mode == VariableMode::kVar)(__builtin_expect(!!(is_eval_scope() && is_sloppy(language_mode
()) && mode == VariableMode::kVar), 0))
) {
1122 // In a var binding in a sloppy direct eval, pollute the enclosing scope
1123 // with this new binding by doing the following:
1124 // The proxy is bound to a lookup variable to force a dynamic declaration
1125 // using the DeclareEvalVar or DeclareEvalFunction runtime functions.
1126 DCHECK_EQ(NORMAL_VARIABLE, kind)((void) 0);
1127 var = NonLocal(name, VariableMode::kDynamic);
1128 // Mark the var as used in case anyone outside the eval wants to use it.
1129 var->set_is_used();
1130 } else {
1131 // Declare the name.
1132 var = DeclareLocal(name, mode, kind, was_added, init);
1133 DCHECK(*was_added)((void) 0);
1134 }
1135 } else {
1136 var->SetMaybeAssigned();
1137 if (V8_UNLIKELY(IsLexicalVariableMode(mode) ||(__builtin_expect(!!(IsLexicalVariableMode(mode) || IsLexicalVariableMode
(var->mode())), 0))
1138 IsLexicalVariableMode(var->mode()))(__builtin_expect(!!(IsLexicalVariableMode(mode) || IsLexicalVariableMode
(var->mode())), 0))
) {
1139 // The name was declared in this scope before; check for conflicting
1140 // re-declarations. We have a conflict if either of the declarations is
1141 // not a var (in script scope, we also have to ignore legacy const for
1142 // compatibility). There is similar code in runtime.cc in the Declare
1143 // functions. The function CheckConflictingVarDeclarations checks for
1144 // var and let bindings from different scopes whereas this is a check
1145 // for conflicting declarations within the same scope. This check also
1146 // covers the special case
1147 //
1148 // function () { let x; { var x; } }
1149 //
1150 // because the var declaration is hoisted to the function scope where
1151 // 'x' is already bound.
1152 //
1153 // In harmony we treat re-declarations as early errors. See ES5 16 for a
1154 // definition of early errors.
1155 //
1156 // Allow duplicate function decls for web compat, see bug 4693.
1157 *ok = var->is_sloppy_block_function() &&
1158 kind == SLOPPY_BLOCK_FUNCTION_VARIABLE;
1159 *sloppy_mode_block_scope_function_redefinition = *ok;
24
Dereference of null pointer (loaded from variable 'sloppy_mode_block_scope_function_redefinition')
1160 }
1161 }
1162 DCHECK_NOT_NULL(var)((void) 0);
1163
1164 // We add a declaration node for every declaration. The compiler
1165 // will only generate code if necessary. In particular, declarations
1166 // for inner local variables that do not represent functions won't
1167 // result in any generated code.
1168 //
1169 // This will lead to multiple declaration nodes for the
1170 // same variable if it is declared several times. This is not a
1171 // semantic issue, but it may be a performance issue since it may
1172 // lead to repeated DeclareEvalVar or DeclareEvalFunction calls.
1173 decls_.Add(declaration);
1174 declaration->set_var(var);
1175 return var;
1176}
1177
1178Variable* Scope::DeclareVariableName(const AstRawString* name,
1179 VariableMode mode, bool* was_added,
1180 VariableKind kind) {
1181 DCHECK(IsDeclaredVariableMode(mode))((void) 0);
1182 DCHECK(!already_resolved_)((void) 0);
1183 DCHECK(GetDeclarationScope()->is_being_lazily_parsed())((void) 0);
1184 // Private methods should be declared with ClassScope::DeclarePrivateName()
1185 DCHECK(!IsPrivateMethodOrAccessorVariableMode(mode))((void) 0);
1186 if (mode == VariableMode::kVar && !is_declaration_scope()) {
1187 return GetDeclarationScope()->DeclareVariableName(name, mode, was_added,
1188 kind);
1189 }
1190 DCHECK(!is_with_scope())((void) 0);
1191 DCHECK(!is_eval_scope())((void) 0);
1192 DCHECK(is_declaration_scope() || IsLexicalVariableMode(mode))((void) 0);
1193 DCHECK(scope_info_.is_null())((void) 0);
1194
1195 // Declare the variable in the declaration scope.
1196 Variable* var = DeclareLocal(name, mode, kind, was_added);
1197 if (!*was_added) {
1198 if (IsLexicalVariableMode(mode) || IsLexicalVariableMode(var->mode())) {
1199 if (!var->is_sloppy_block_function() ||
1200 kind != SLOPPY_BLOCK_FUNCTION_VARIABLE) {
1201 // Duplicate functions are allowed in the sloppy mode, but if this is
1202 // not a function declaration, it's an error. This is an error PreParser
1203 // hasn't previously detected.
1204 return nullptr;
1205 }
1206 // Sloppy block function redefinition.
1207 }
1208 var->SetMaybeAssigned();
1209 }
1210 var->set_is_used();
1211 return var;
1212}
1213
1214Variable* Scope::DeclareCatchVariableName(const AstRawString* name) {
1215 DCHECK(!already_resolved_)((void) 0);
1216 DCHECK(is_catch_scope())((void) 0);
1217 DCHECK(scope_info_.is_null())((void) 0);
1218
1219 bool was_added;
1220 Variable* result = Declare(zone(), name, VariableMode::kVar, NORMAL_VARIABLE,
1221 kCreatedInitialized, kNotAssigned, &was_added);
1222 DCHECK(was_added)((void) 0);
1223 return result;
1224}
1225
1226void Scope::AddUnresolved(VariableProxy* proxy) {
1227 DCHECK(!already_resolved_)((void) 0);
1228 DCHECK(!proxy->is_resolved())((void) 0);
1229 unresolved_list_.Add(proxy);
1230}
1231
1232Variable* DeclarationScope::DeclareDynamicGlobal(const AstRawString* name,
1233 VariableKind kind,
1234 Scope* cache) {
1235 DCHECK(is_script_scope())((void) 0);
1236 bool was_added;
1237 return cache->variables_.Declare(
1238 zone(), this, name, VariableMode::kDynamicGlobal, kind,
1239 kCreatedInitialized, kNotAssigned, IsStaticFlag::kNotStatic, &was_added);
1240 // TODO(neis): Mark variable as maybe-assigned?
1241}
1242
1243bool Scope::RemoveUnresolved(VariableProxy* var) {
1244 return unresolved_list_.Remove(var);
1245}
1246
1247void Scope::DeleteUnresolved(VariableProxy* var) {
1248 DCHECK(unresolved_list_.Contains(var))((void) 0);
1249 var->mark_removed_from_unresolved();
1250}
1251
1252Variable* Scope::NewTemporary(const AstRawString* name) {
1253 return NewTemporary(name, kMaybeAssigned);
1254}
1255
1256Variable* Scope::NewTemporary(const AstRawString* name,
1257 MaybeAssignedFlag maybe_assigned) {
1258 DeclarationScope* scope = GetClosureScope();
1259 Variable* var = zone()->New<Variable>(scope, name, VariableMode::kTemporary,
1260 NORMAL_VARIABLE, kCreatedInitialized);
1261 scope->AddLocal(var);
1262 if (maybe_assigned == kMaybeAssigned) var->SetMaybeAssigned();
1263 return var;
1264}
1265
1266Declaration* DeclarationScope::CheckConflictingVarDeclarations(
1267 bool* allowed_catch_binding_var_redeclaration) {
1268 if (has_checked_syntax_) return nullptr;
1269 for (Declaration* decl : decls_) {
1270 // Lexical vs lexical conflicts within the same scope have already been
1271 // captured in Parser::Declare. The only conflicts we still need to check
1272 // are lexical vs nested var.
1273 if (decl->IsVariableDeclaration() &&
1274 decl->AsVariableDeclaration()->AsNested() != nullptr) {
1275 Scope* current = decl->AsVariableDeclaration()->AsNested()->scope();
1276 DCHECK(decl->var()->mode() == VariableMode::kVar ||((void) 0)
1277 decl->var()->mode() == VariableMode::kDynamic)((void) 0);
1278 // Iterate through all scopes until the declaration scope.
1279 do {
1280 // There is a conflict if there exists a non-VAR binding.
1281 Variable* other_var = current->LookupLocal(decl->var()->raw_name());
1282 if (current->is_catch_scope()) {
1283 *allowed_catch_binding_var_redeclaration |= other_var != nullptr;
1284 current = current->outer_scope();
1285 continue;
1286 }
1287 if (other_var != nullptr) {
1288 DCHECK(IsLexicalVariableMode(other_var->mode()))((void) 0);
1289 return decl;
1290 }
1291 current = current->outer_scope();
1292 } while (current != this);
1293 }
1294 }
1295
1296 if (V8_LIKELY(!is_eval_scope())(__builtin_expect(!!(!is_eval_scope()), 1))) return nullptr;
1297 if (!is_sloppy(language_mode())) return nullptr;
1298
1299 // Var declarations in sloppy eval are hoisted to the first non-eval
1300 // declaration scope. Check for conflicts between the eval scope that
1301 // declaration scope.
1302 Scope* end = outer_scope()->GetNonEvalDeclarationScope()->outer_scope();
1303
1304 for (Declaration* decl : decls_) {
1305 if (IsLexicalVariableMode(decl->var()->mode())) continue;
1306 Scope* current = outer_scope_;
1307 // Iterate through all scopes until and including the declaration scope.
1308 do {
1309 // There is a conflict if there exists a non-VAR binding up to the
1310 // declaration scope in which this sloppy-eval runs.
1311 //
1312 // Use the current scope as the cache, since the general cache would be
1313 // the end scope.
1314 Variable* other_var =
1315 current->LookupInScopeOrScopeInfo(decl->var()->raw_name(), current);
1316 if (other_var != nullptr && !current->is_catch_scope()) {
1317 // If this is a VAR, then we know that it doesn't conflict with
1318 // anything, so we can't conflict with anything either. The one
1319 // exception is the binding variable in catch scopes, which is handled
1320 // by the if above.
1321 if (!IsLexicalVariableMode(other_var->mode())) break;
1322 return decl;
1323 }
1324 current = current->outer_scope();
1325 } while (current != end);
1326 }
1327 return nullptr;
1328}
1329
1330const AstRawString* Scope::FindVariableDeclaredIn(Scope* scope,
1331 VariableMode mode_limit) {
1332 const VariableMap& variables = scope->variables_;
1333 for (ZoneHashMap::Entry* p = variables.Start(); p != nullptr;
1334 p = variables.Next(p)) {
1335 const AstRawString* name = static_cast<const AstRawString*>(p->key);
1336 Variable* var = LookupLocal(name);
1337 if (var != nullptr && var->mode() <= mode_limit) return name;
1338 }
1339 return nullptr;
1340}
1341
1342void DeclarationScope::DeserializeReceiver(AstValueFactory* ast_value_factory) {
1343 if (is_script_scope()) {
1344 DCHECK_NOT_NULL(receiver_)((void) 0);
1345 return;
1346 }
1347 DCHECK(has_this_declaration())((void) 0);
1348 DeclareThis(ast_value_factory);
1349 if (is_debug_evaluate_scope()) {
1350 receiver_->AllocateTo(VariableLocation::LOOKUP, -1);
1351 } else {
1352 receiver_->AllocateTo(VariableLocation::CONTEXT,
1353 scope_info_->ReceiverContextSlotIndex());
1354 }
1355}
1356
1357bool DeclarationScope::AllocateVariables(ParseInfo* info) {
1358 // Module variables must be allocated before variable resolution
1359 // to ensure that UpdateNeedsHoleCheck() can detect import variables.
1360 if (is_module_scope()) AsModuleScope()->AllocateModuleVariables();
1361
1362 PrivateNameScopeIterator private_name_scope_iter(this);
1363 if (!private_name_scope_iter.Done() &&
1364 !private_name_scope_iter.GetScope()->ResolvePrivateNames(info)) {
1365 DCHECK(info->pending_error_handler()->has_pending_error())((void) 0);
1366 return false;
1367 }
1368
1369 if (!ResolveVariablesRecursively(info->scope())) {
1370 DCHECK(info->pending_error_handler()->has_pending_error())((void) 0);
1371 return false;
1372 }
1373
1374 // Don't allocate variables of preparsed scopes.
1375 if (!was_lazily_parsed()) AllocateVariablesRecursively();
1376
1377 return true;
1378}
1379
1380bool Scope::HasThisReference() const {
1381 if (is_declaration_scope() && AsDeclarationScope()->has_this_reference()) {
1382 return true;
1383 }
1384
1385 for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) {
1386 if (!scope->is_declaration_scope() ||
1387 !scope->AsDeclarationScope()->has_this_declaration()) {
1388 if (scope->HasThisReference()) return true;
1389 }
1390 }
1391
1392 return false;
1393}
1394
1395bool Scope::AllowsLazyParsingWithoutUnresolvedVariables(
1396 const Scope* outer) const {
1397 // If none of the outer scopes need to decide whether to context allocate
1398 // specific variables, we can preparse inner functions without unresolved
1399 // variables. Otherwise we need to find unresolved variables to force context
1400 // allocation of the matching declarations. We can stop at the outer scope for
1401 // the parse, since context allocation of those variables is already
1402 // guaranteed to be correct.
1403 for (const Scope* s = this; s != outer; s = s->outer_scope_) {
1404 // Eval forces context allocation on all outer scopes, so we don't need to
1405 // look at those scopes. Sloppy eval makes top-level non-lexical variables
1406 // dynamic, whereas strict-mode requires context allocation.
1407 if (s->is_eval_scope()) return is_sloppy(s->language_mode());
1408 // Catch scopes force context allocation of all variables.
1409 if (s->is_catch_scope()) continue;
1410 // With scopes do not introduce variables that need allocation.
1411 if (s->is_with_scope()) continue;
1412 DCHECK(s->is_module_scope() || s->is_block_scope() ||((void) 0)
1413 s->is_function_scope())((void) 0);
1414 return false;
1415 }
1416 return true;
1417}
1418
1419bool DeclarationScope::AllowsLazyCompilation() const {
1420 // Functions which force eager compilation and class member initializer
1421 // functions are not lazily compilable.
1422 return !force_eager_compilation_ &&
1423 !IsClassMembersInitializerFunction(function_kind());
1424}
1425
1426int Scope::ContextChainLength(Scope* scope) const {
1427 int n = 0;
1428 for (const Scope* s = this; s != scope; s = s->outer_scope_) {
1429 DCHECK_NOT_NULL(s)((void) 0); // scope must be in the scope chain
1430 if (s->NeedsContext()) n++;
1431 }
1432 return n;
1433}
1434
1435int Scope::ContextChainLengthUntilOutermostSloppyEval() const {
1436 int result = 0;
1437 int length = 0;
1438
1439 for (const Scope* s = this; s != nullptr; s = s->outer_scope()) {
1440 if (!s->NeedsContext()) continue;
1441 length++;
1442 if (s->is_declaration_scope() &&
1443 s->AsDeclarationScope()->sloppy_eval_can_extend_vars()) {
1444 result = length;
1445 }
1446 }
1447
1448 return result;
1449}
1450
1451DeclarationScope* Scope::GetDeclarationScope() {
1452 Scope* scope = this;
1453 while (!scope->is_declaration_scope()) {
1454 scope = scope->outer_scope();
1455 }
1456 return scope->AsDeclarationScope();
1457}
1458
1459DeclarationScope* Scope::GetNonEvalDeclarationScope() {
1460 Scope* scope = this;
1461 while (!scope->is_declaration_scope() || scope->is_eval_scope()) {
1462 scope = scope->outer_scope();
1463 }
1464 return scope->AsDeclarationScope();
1465}
1466
1467const DeclarationScope* Scope::GetClosureScope() const {
1468 const Scope* scope = this;
1469 while (!scope->is_declaration_scope() || scope->is_block_scope()) {
1470 scope = scope->outer_scope();
1471 }
1472 return scope->AsDeclarationScope();
1473}
1474
1475DeclarationScope* Scope::GetClosureScope() {
1476 Scope* scope = this;
1477 while (!scope->is_declaration_scope() || scope->is_block_scope()) {
1478 scope = scope->outer_scope();
1479 }
1480 return scope->AsDeclarationScope();
1481}
1482
1483bool Scope::NeedsScopeInfo() const {
1484 DCHECK(!already_resolved_)((void) 0);
1485 DCHECK(GetClosureScope()->ShouldEagerCompile())((void) 0);
1486 // The debugger expects all functions to have scope infos.
1487 // TODO(yangguo): Remove this requirement.
1488 if (is_function_scope()) return true;
1489 return NeedsContext();
1490}
1491
1492bool Scope::ShouldBanArguments() {
1493 return GetReceiverScope()->should_ban_arguments();
1494}
1495
1496DeclarationScope* Scope::GetReceiverScope() {
1497 Scope* scope = this;
1498 while (!scope->is_declaration_scope() ||
1499 (!scope->is_script_scope() &&
1500 !scope->AsDeclarationScope()->has_this_declaration())) {
1501 scope = scope->outer_scope();
1502 }
1503 return scope->AsDeclarationScope();
1504}
1505
1506DeclarationScope* Scope::GetConstructorScope() {
1507 Scope* scope = this;
1508 while (scope != nullptr && !scope->IsConstructorScope()) {
1509 scope = scope->outer_scope();
1510 }
1511 if (scope == nullptr) {
1512 return nullptr;
1513 }
1514 DCHECK(scope->IsConstructorScope())((void) 0);
1515 return scope->AsDeclarationScope();
1516}
1517
1518Scope* Scope::GetHomeObjectScope() {
1519 Scope* scope = this;
1520 while (scope != nullptr && !scope->is_home_object_scope()) {
1521 if (scope->is_function_scope()) {
1522 FunctionKind function_kind = scope->AsDeclarationScope()->function_kind();
1523 // "super" in arrow functions binds outside the arrow function. But if we
1524 // find a function which doesn't bind "super" (is not a method etc.) and
1525 // not an arrow function, we know "super" here doesn't bind anywhere and
1526 // we can return nullptr.
1527 if (!IsArrowFunction(function_kind) && !BindsSuper(function_kind)) {
1528 return nullptr;
1529 }
1530 }
1531 if (scope->private_name_lookup_skips_outer_class()) {
1532 DCHECK(scope->outer_scope()->is_class_scope())((void) 0);
1533 scope = scope->outer_scope()->outer_scope();
1534 } else {
1535 scope = scope->outer_scope();
1536 }
1537 }
1538 return scope;
1539}
1540
1541DeclarationScope* Scope::GetScriptScope() {
1542 Scope* scope = this;
1543 while (!scope->is_script_scope()) {
1544 scope = scope->outer_scope();
1545 }
1546 return scope->AsDeclarationScope();
1547}
1548
1549Scope* Scope::GetOuterScopeWithContext() {
1550 Scope* scope = outer_scope_;
1551 while (scope && !scope->NeedsContext()) {
1552 scope = scope->outer_scope();
1553 }
1554 return scope;
1555}
1556
1557namespace {
1558bool WasLazilyParsed(Scope* scope) {
1559 return scope->is_declaration_scope() &&
1560 scope->AsDeclarationScope()->was_lazily_parsed();
1561}
1562
1563} // namespace
1564
1565template <typename FunctionType>
1566void Scope::ForEach(FunctionType callback) {
1567 Scope* scope = this;
1568 while (true) {
1569 Iteration iteration = callback(scope);
1570 // Try to descend into inner scopes first.
1571 if ((iteration == Iteration::kDescend) && scope->inner_scope_ != nullptr) {
1572 scope = scope->inner_scope_;
1573 } else {
1574 // Find the next outer scope with a sibling.
1575 while (scope->sibling_ == nullptr) {
1576 if (scope == this) return;
1577 scope = scope->outer_scope_;
1578 }
1579 if (scope == this) return;
1580 scope = scope->sibling_;
1581 }
1582 }
1583}
1584
1585bool Scope::IsConstructorScope() const {
1586 return is_declaration_scope() &&
1587 IsClassConstructor(AsDeclarationScope()->function_kind());
1588}
1589
1590bool Scope::IsOuterScopeOf(Scope* other) const {
1591 Scope* scope = other;
1592 while (scope) {
1593 if (scope == this) return true;
1594 scope = scope->outer_scope();
1595 }
1596 return false;
1597}
1598
1599void Scope::CollectNonLocals(DeclarationScope* max_outer_scope,
1600 Isolate* isolate, Handle<StringSet>* non_locals) {
1601 this->ForEach([max_outer_scope, isolate, non_locals](Scope* scope) {
1602 // Module variables must be allocated before variable resolution
1603 // to ensure that UpdateNeedsHoleCheck() can detect import variables.
1604 if (scope->is_module_scope()) {
1605 scope->AsModuleScope()->AllocateModuleVariables();
1606 }
1607
1608 // Lazy parsed declaration scopes are already partially analyzed. If there
1609 // are unresolved references remaining, they just need to be resolved in
1610 // outer scopes.
1611 Scope* lookup = WasLazilyParsed(scope) ? scope->outer_scope() : scope;
1612
1613 for (VariableProxy* proxy : scope->unresolved_list_) {
1614 DCHECK(!proxy->is_resolved())((void) 0);
1615 Variable* var =
1616 Lookup<kParsedScope>(proxy, lookup, max_outer_scope->outer_scope());
1617 if (var == nullptr) {
1618 *non_locals = StringSet::Add(isolate, *non_locals, proxy->name());
1619 } else {
1620 // In this case we need to leave scopes in a way that they can be
1621 // allocated. If we resolved variables from lazy parsed scopes, we need
1622 // to context allocate the var.
1623 scope->ResolveTo(proxy, var);
1624 if (!var->is_dynamic() && lookup != scope)
1625 var->ForceContextAllocation();
1626 }
1627 }
1628
1629 // Clear unresolved_list_ as it's in an inconsistent state.
1630 scope->unresolved_list_.Clear();
1631 return Iteration::kDescend;
1632 });
1633}
1634
1635void Scope::AnalyzePartially(DeclarationScope* max_outer_scope,
1636 AstNodeFactory* ast_node_factory,
1637 UnresolvedList* new_unresolved_list,
1638 bool maybe_in_arrowhead) {
1639 this->ForEach([max_outer_scope, ast_node_factory, new_unresolved_list,
1640 maybe_in_arrowhead](Scope* scope) {
1641 DCHECK_IMPLIES(scope->is_declaration_scope(),((void) 0)
1642 !scope->AsDeclarationScope()->was_lazily_parsed())((void) 0);
1643
1644 for (VariableProxy* proxy = scope->unresolved_list_.first();
1645 proxy != nullptr; proxy = proxy->next_unresolved()) {
1646 if (proxy->is_removed_from_unresolved()) continue;
1647 DCHECK(!proxy->is_resolved())((void) 0);
1648 Variable* var =
1649 Lookup<kParsedScope>(proxy, scope, max_outer_scope->outer_scope());
1650 if (var == nullptr) {
1651 // Don't copy unresolved references to the script scope, unless it's a
1652 // reference to a private name or method. In that case keep it so we
1653 // can fail later.
1654 if (!max_outer_scope->outer_scope()->is_script_scope() ||
1655 maybe_in_arrowhead) {
1656 VariableProxy* copy = ast_node_factory->CopyVariableProxy(proxy);
1657 new_unresolved_list->Add(copy);
1658 }
1659 } else {
1660 var->set_is_used();
1661 if (proxy->is_assigned()) var->SetMaybeAssigned();
1662 }
1663 }
1664
1665 // Clear unresolved_list_ as it's in an inconsistent state.
1666 scope->unresolved_list_.Clear();
1667 return Iteration::kDescend;
1668 });
1669}
1670
1671Handle<StringSet> DeclarationScope::CollectNonLocals(
1672 Isolate* isolate, Handle<StringSet> non_locals) {
1673 Scope::CollectNonLocals(this, isolate, &non_locals);
1674 return non_locals;
1675}
1676
1677void DeclarationScope::ResetAfterPreparsing(AstValueFactory* ast_value_factory,
1678 bool aborted) {
1679 DCHECK(is_function_scope())((void) 0);
1680
1681 // Reset all non-trivial members.
1682 params_.DropAndClear();
1683 decls_.Clear();
1684 locals_.Clear();
1685 inner_scope_ = nullptr;
1686 unresolved_list_.Clear();
1687 sloppy_block_functions_.Clear();
1688 rare_data_ = nullptr;
1689 has_rest_ = false;
1690 function_ = nullptr;
1691
1692 DCHECK_NE(zone(), ast_value_factory->single_parse_zone())((void) 0);
1693 // Make sure this scope and zone aren't used for allocation anymore.
1694 {
1695 // Get the zone, while variables_ is still valid
1696 Zone* zone = this->zone();
1697 variables_.Invalidate();
1698 zone->Reset();
1699 }
1700
1701 if (aborted) {
1702 // Prepare scope for use in the outer zone.
1703 variables_ = VariableMap(ast_value_factory->single_parse_zone());
1704 if (!IsArrowFunction(function_kind_)) {
1705 has_simple_parameters_ = true;
1706 DeclareDefaultFunctionVariables(ast_value_factory);
1707 }
1708 }
1709
1710#ifdef DEBUG
1711 needs_migration_ = false;
1712 is_being_lazily_parsed_ = false;
1713#endif
1714
1715 was_lazily_parsed_ = !aborted;
1716}
1717
1718bool Scope::IsSkippableFunctionScope() {
1719 // Lazy non-arrow function scopes are skippable. Lazy functions are exactly
1720 // those Scopes which have their own PreparseDataBuilder object. This
1721 // logic ensures that the scope allocation data is consistent with the
1722 // skippable function data (both agree on where the lazy function boundaries
1723 // are).
1724 if (!is_function_scope()) return false;
1725 DeclarationScope* declaration_scope = AsDeclarationScope();
1726 return !declaration_scope->is_arrow_scope() &&
1727 declaration_scope->preparse_data_builder() != nullptr;
1728}
1729
1730void Scope::SavePreparseData(Parser* parser) {
1731 this->ForEach([parser](Scope* scope) {
1732 if (scope->IsSkippableFunctionScope()) {
1733 scope->AsDeclarationScope()->SavePreparseDataForDeclarationScope(parser);
1734 }
1735 return Iteration::kDescend;
1736 });
1737}
1738
1739void DeclarationScope::SavePreparseDataForDeclarationScope(Parser* parser) {
1740 if (preparse_data_builder_ == nullptr) return;
1741 preparse_data_builder_->SaveScopeAllocationData(this, parser);
1742}
1743
1744void DeclarationScope::AnalyzePartially(Parser* parser,
1745 AstNodeFactory* ast_node_factory,
1746 bool maybe_in_arrowhead) {
1747 DCHECK(!force_eager_compilation_)((void) 0);
1748 UnresolvedList new_unresolved_list;
1749 if (!IsArrowFunction(function_kind_) &&
1750 (!outer_scope_->is_script_scope() || maybe_in_arrowhead ||
1751 (preparse_data_builder_ != nullptr &&
1752 preparse_data_builder_->HasInnerFunctions()))) {
1753 // Try to resolve unresolved variables for this Scope and migrate those
1754 // which cannot be resolved inside. It doesn't make sense to try to resolve
1755 // them in the outer Scopes here, because they are incomplete.
1756 Scope::AnalyzePartially(this, ast_node_factory, &new_unresolved_list,
1757 maybe_in_arrowhead);
1758
1759 // Migrate function_ to the right Zone.
1760 if (function_ != nullptr) {
1761 function_ = ast_node_factory->CopyVariable(function_);
1762 }
1763
1764 SavePreparseData(parser);
1765 }
1766
1767#ifdef DEBUG
1768 if (FLAG_print_scopes) {
1769 PrintF("Inner function scope:\n");
1770 Print();
1771 }
1772#endif
1773
1774 ResetAfterPreparsing(ast_node_factory->ast_value_factory(), false);
1775
1776 unresolved_list_ = std::move(new_unresolved_list);
1777}
1778
1779void DeclarationScope::RewriteReplGlobalVariables() {
1780 DCHECK(is_script_scope())((void) 0);
1781 if (!is_repl_mode_scope()) return;
1782
1783 for (VariableMap::Entry* p = variables_.Start(); p != nullptr;
1784 p = variables_.Next(p)) {
1785 Variable* var = reinterpret_cast<Variable*>(p->value);
1786 var->RewriteLocationForRepl();
1787 }
1788}
1789
1790#ifdef DEBUG
1791namespace {
1792
1793const char* Header(ScopeType scope_type, FunctionKind function_kind,
1794 bool is_declaration_scope) {
1795 switch (scope_type) {
1796 case EVAL_SCOPE: return "eval";
1797 case FUNCTION_SCOPE:
1798 if (IsGeneratorFunction(function_kind)) return "function*";
1799 if (IsAsyncFunction(function_kind)) return "async function";
1800 if (IsArrowFunction(function_kind)) return "arrow";
1801 return "function";
1802 case MODULE_SCOPE: return "module";
1803 case SCRIPT_SCOPE: return "global";
1804 case CATCH_SCOPE: return "catch";
1805 case BLOCK_SCOPE: return is_declaration_scope ? "varblock" : "block";
1806 case CLASS_SCOPE:
1807 return "class";
1808 case WITH_SCOPE: return "with";
1809 }
1810 UNREACHABLE()V8_Fatal("unreachable code");
1811}
1812
1813void Indent(int n, const char* str) { PrintF("%*s%s", n, "", str); }
1814
1815void PrintName(const AstRawString* name) {
1816 PrintF("%.*s", name->length(), name->raw_data());
1817}
1818
1819void PrintLocation(Variable* var) {
1820 switch (var->location()) {
1821 case VariableLocation::UNALLOCATED:
1822 break;
1823 case VariableLocation::PARAMETER:
1824 PrintF("parameter[%d]", var->index());
1825 break;
1826 case VariableLocation::LOCAL:
1827 PrintF("local[%d]", var->index());
1828 break;
1829 case VariableLocation::CONTEXT:
1830 PrintF("context[%d]", var->index());
1831 break;
1832 case VariableLocation::LOOKUP:
1833 PrintF("lookup");
1834 break;
1835 case VariableLocation::MODULE:
1836 PrintF("module");
1837 break;
1838 case VariableLocation::REPL_GLOBAL:
1839 PrintF("repl global[%d]", var->index());
1840 break;
1841 }
1842}
1843
1844void PrintVar(int indent, Variable* var) {
1845 Indent(indent, VariableMode2String(var->mode()));
1846 PrintF(" ");
1847 if (var->raw_name()->IsEmpty())
1848 PrintF(".%p", reinterpret_cast<void*>(var));
1849 else
1850 PrintName(var->raw_name());
1851 PrintF("; // (%p) ", reinterpret_cast<void*>(var));
1852 PrintLocation(var);
1853 bool comma = !var->IsUnallocated();
1854 if (var->has_forced_context_allocation()) {
1855 if (comma) PrintF(", ");
1856 PrintF("forced context allocation");
1857 comma = true;
1858 }
1859 if (var->maybe_assigned() == kNotAssigned) {
1860 if (comma) PrintF(", ");
1861 PrintF("never assigned");
1862 comma = true;
1863 }
1864 if (var->initialization_flag() == kNeedsInitialization &&
1865 !var->binding_needs_init()) {
1866 if (comma) PrintF(", ");
1867 PrintF("hole initialization elided");
1868 }
1869 PrintF("\n");
1870}
1871
1872void PrintMap(int indent, const char* label, VariableMap* map, bool locals,
1873 Variable* function_var) {
1874 bool printed_label = false;
1875 for (VariableMap::Entry* p = map->Start(); p != nullptr; p = map->Next(p)) {
1876 Variable* var = reinterpret_cast<Variable*>(p->value);
1877 if (var == function_var) continue;
1878 bool local = !IsDynamicVariableMode(var->mode());
1879 if ((locals ? local : !local) &&
1880 (var->is_used() || !var->IsUnallocated())) {
1881 if (!printed_label) {
1882 Indent(indent, label);
1883 printed_label = true;
1884 }
1885 PrintVar(indent, var);
1886 }
1887 }
1888}
1889
1890} // anonymous namespace
1891
1892void DeclarationScope::PrintParameters() {
1893 PrintF(" (");
1894 for (int i = 0; i < params_.length(); i++) {
1895 if (i > 0) PrintF(", ");
1896 const AstRawString* name = params_[i]->raw_name();
1897 if (name->IsEmpty()) {
1898 PrintF(".%p", reinterpret_cast<void*>(params_[i]));
1899 } else {
1900 PrintName(name);
1901 }
1902 }
1903 PrintF(")");
1904}
1905
1906void Scope::Print(int n) {
1907 int n0 = (n > 0 ? n : 0);
1908 int n1 = n0 + 2; // indentation
1909
1910 // Print header.
1911 FunctionKind function_kind = is_function_scope()
1912 ? AsDeclarationScope()->function_kind()
1913 : FunctionKind::kNormalFunction;
1914 Indent(n0, Header(scope_type_, function_kind, is_declaration_scope()));
1915 if (scope_name_ != nullptr && !scope_name_->IsEmpty()) {
1916 PrintF(" ");
1917 PrintName(scope_name_);
1918 }
1919
1920 // Print parameters, if any.
1921 Variable* function = nullptr;
1922 if (is_function_scope()) {
1923 AsDeclarationScope()->PrintParameters();
1924 function = AsDeclarationScope()->function_var();
1925 }
1926
1927 PrintF(" { // (%p) (%d, %d)\n", reinterpret_cast<void*>(this),
1928 start_position(), end_position());
1929 if (is_hidden()) {
1930 Indent(n1, "// is hidden\n");
1931 }
1932
1933 // Function name, if any (named function literals, only).
1934 if (function != nullptr) {
1935 Indent(n1, "// (local) function name: ");
1936 PrintName(function->raw_name());
1937 PrintF("\n");
1938 }
1939
1940 // Scope info.
1941 if (is_strict(language_mode())) {
1942 Indent(n1, "// strict mode scope\n");
1943 }
1944#if V8_ENABLE_WEBASSEMBLY1
1945 if (IsAsmModule()) Indent(n1, "// scope is an asm module\n");
1946#endif // V8_ENABLE_WEBASSEMBLY
1947 if (is_declaration_scope() &&
1948 AsDeclarationScope()->sloppy_eval_can_extend_vars()) {
1949 Indent(n1, "// scope calls sloppy 'eval'\n");
1950 }
1951 if (private_name_lookup_skips_outer_class()) {
1952 Indent(n1, "// scope skips outer class for #-names\n");
1953 }
1954 if (inner_scope_calls_eval_) Indent(n1, "// inner scope calls 'eval'\n");
1955 if (is_declaration_scope()) {
1956 DeclarationScope* scope = AsDeclarationScope();
1957 if (scope->was_lazily_parsed()) Indent(n1, "// lazily parsed\n");
1958 if (scope->ShouldEagerCompile()) Indent(n1, "// will be compiled\n");
1959 if (scope->needs_private_name_context_chain_recalc()) {
1960 Indent(n1, "// needs #-name context chain recalc\n");
1961 }
1962 Indent(n1, "// ");
1963 PrintF("%s\n", FunctionKind2String(scope->function_kind()));
1964 if (scope->class_scope_has_private_brand()) {
1965 Indent(n1, "// class scope has private brand\n");
1966 }
1967 }
1968 if (num_stack_slots_ > 0) {
1969 Indent(n1, "// ");
1970 PrintF("%d stack slots\n", num_stack_slots_);
1971 }
1972 if (num_heap_slots_ > 0) {
1973 Indent(n1, "// ");
1974 PrintF("%d heap slots\n", num_heap_slots_);
1975 }
1976
1977 // Print locals.
1978 if (function != nullptr) {
1979 Indent(n1, "// function var:\n");
1980 PrintVar(n1, function);
1981 }
1982
1983 // Print temporaries.
1984 {
1985 bool printed_header = false;
1986 for (Variable* local : locals_) {
1987 if (local->mode() != VariableMode::kTemporary) continue;
1988 if (!printed_header) {
1989 printed_header = true;
1990 Indent(n1, "// temporary vars:\n");
1991 }
1992 PrintVar(n1, local);
1993 }
1994 }
1995
1996 if (variables_.occupancy() > 0) {
1997 PrintMap(n1, "// local vars:\n", &variables_, true, function);
1998 PrintMap(n1, "// dynamic vars:\n", &variables_, false, function);
1999 }
2000
2001 if (is_class_scope()) {
2002 ClassScope* class_scope = AsClassScope();
2003 if (class_scope->GetRareData() != nullptr) {
2004 PrintMap(n1, "// private name vars:\n",
2005 &(class_scope->GetRareData()->private_name_map), true, function);
2006 Variable* brand = class_scope->brand();
2007 if (brand != nullptr) {
2008 Indent(n1, "// brand var:\n");
2009 PrintVar(n1, brand);
2010 }
2011 }
2012 if (class_scope->class_variable() != nullptr) {
2013 Indent(n1, "// class var");
2014 PrintF("%s%s:\n",
2015 class_scope->class_variable()->is_used() ? ", used" : ", unused",
2016 class_scope->should_save_class_variable_index()
2017 ? ", index saved"
2018 : ", index not saved");
2019 PrintVar(n1, class_scope->class_variable());
2020 }
2021 }
2022
2023 // Print inner scopes (disable by providing negative n).
2024 if (n >= 0) {
2025 for (Scope* scope = inner_scope_; scope != nullptr;
2026 scope = scope->sibling_) {
2027 PrintF("\n");
2028 scope->Print(n1);
2029 }
2030 }
2031
2032 Indent(n0, "}\n");
2033}
2034
2035void Scope::CheckScopePositions() {
2036 this->ForEach([](Scope* scope) {
2037 // Visible leaf scopes must have real positions.
2038 if (!scope->is_hidden() && scope->inner_scope_ == nullptr) {
2039 DCHECK_NE(kNoSourcePosition, scope->start_position())((void) 0);
2040 DCHECK_NE(kNoSourcePosition, scope->end_position())((void) 0);
2041 }
2042 return Iteration::kDescend;
2043 });
2044}
2045
2046void Scope::CheckZones() {
2047 DCHECK(!needs_migration_)((void) 0);
2048 this->ForEach([](Scope* scope) {
2049 if (WasLazilyParsed(scope)) {
2050 DCHECK_NULL(scope->zone())((void) 0);
2051 DCHECK_NULL(scope->inner_scope_)((void) 0);
2052 return Iteration::kContinue;
2053 }
2054 return Iteration::kDescend;
2055 });
2056}
2057#endif // DEBUG
2058
2059Variable* Scope::NonLocal(const AstRawString* name, VariableMode mode) {
2060 // Declare a new non-local.
2061 DCHECK(IsDynamicVariableMode(mode))((void) 0);
2062 bool was_added;
2063 Variable* var = variables_.Declare(zone(), this, name, mode, NORMAL_VARIABLE,
2064 kCreatedInitialized, kNotAssigned,
2065 IsStaticFlag::kNotStatic, &was_added);
2066 // Allocate it by giving it a dynamic lookup.
2067 var->AllocateTo(VariableLocation::LOOKUP, -1);
2068 return var;
2069}
2070
2071// static
2072template <Scope::ScopeLookupMode mode>
2073Variable* Scope::Lookup(VariableProxy* proxy, Scope* scope,
2074 Scope* outer_scope_end, Scope* cache_scope,
2075 bool force_context_allocation) {
2076 // If we have already passed the cache scope in earlier recursions, we should
2077 // first quickly check if the current scope uses the cache scope before
2078 // continuing.
2079 if (mode == kDeserializedScope &&
2080 scope->deserialized_scope_uses_external_cache()) {
2081 Variable* var = cache_scope->variables_.Lookup(proxy->raw_name());
2082 if (var != nullptr) return var;
2083 }
2084
2085 while (true) {
2086 DCHECK_IMPLIES(mode == kParsedScope, !scope->is_debug_evaluate_scope_)((void) 0);
2087 // Short-cut: whenever we find a debug-evaluate scope, just look everything
2088 // up dynamically. Debug-evaluate doesn't properly create scope info for the
2089 // lookups it does. It may not have a valid 'this' declaration, and anything
2090 // accessed through debug-evaluate might invalidly resolve to
2091 // stack-allocated variables.
2092 // TODO(yangguo): Remove once debug-evaluate creates proper ScopeInfo for
2093 // the scopes in which it's evaluating.
2094 if (mode == kDeserializedScope &&
2095 V8_UNLIKELY(scope->is_debug_evaluate_scope_)(__builtin_expect(!!(scope->is_debug_evaluate_scope_), 0))) {
2096 DCHECK(scope->deserialized_scope_uses_external_cache() ||((void) 0)
2097 scope == cache_scope)((void) 0);
2098 return cache_scope->NonLocal(proxy->raw_name(), VariableMode::kDynamic);
2099 }
2100
2101 // Try to find the variable in this scope.
2102 Variable* var;
2103 if (mode == kParsedScope) {
2104 var = scope->LookupLocal(proxy->raw_name());
2105 } else {
2106 DCHECK_EQ(mode, kDeserializedScope)((void) 0);
2107 bool external_cache = scope->deserialized_scope_uses_external_cache();
2108 if (!external_cache) {
2109 // Check the cache on each deserialized scope, up to the main cache
2110 // scope when we get to it (we may still have deserialized scopes
2111 // in-between the initial and cache scopes so we can't just check the
2112 // cache before the loop).
2113 var = scope->variables_.Lookup(proxy->raw_name());
2114 if (var != nullptr) return var;
2115 }
2116 var = scope->LookupInScopeInfo(proxy->raw_name(),
2117 external_cache ? cache_scope : scope);
2118 }
2119
2120 // We found a variable and we are done. (Even if there is an 'eval' in this
2121 // scope which introduces the same variable again, the resulting variable
2122 // remains the same.)
2123 //
2124 // For sloppy eval though, we skip dynamic variable to avoid resolving to a
2125 // variable when the variable and proxy are in the same eval execution. The
2126 // variable is not available on subsequent lazy executions of functions in
2127 // the eval, so this avoids inner functions from looking up different
2128 // variables during eager and lazy compilation.
2129 //
2130 // TODO(leszeks): Maybe we want to restrict this to e.g. lookups of a proxy
2131 // living in a different scope to the current one, or some other
2132 // optimisation.
2133 if (var != nullptr &&
2134 !(scope->is_eval_scope() && var->mode() == VariableMode::kDynamic)) {
2135 if (mode == kParsedScope && force_context_allocation &&
2136 !var->is_dynamic()) {
2137 var->ForceContextAllocation();
2138 }
2139 return var;
2140 }
2141
2142 if (scope->outer_scope_ == outer_scope_end) break;
2143
2144 DCHECK(!scope->is_script_scope())((void) 0);
2145 if (V8_UNLIKELY(scope->is_with_scope())(__builtin_expect(!!(scope->is_with_scope()), 0))) {
2146 return LookupWith(proxy, scope, outer_scope_end, cache_scope,
2147 force_context_allocation);
2148 }
2149 if (V8_UNLIKELY((__builtin_expect(!!(scope->is_declaration_scope() &&
scope->AsDeclarationScope()->sloppy_eval_can_extend_vars
()), 0))
2150 scope->is_declaration_scope() &&(__builtin_expect(!!(scope->is_declaration_scope() &&
scope->AsDeclarationScope()->sloppy_eval_can_extend_vars
()), 0))
2151 scope->AsDeclarationScope()->sloppy_eval_can_extend_vars())(__builtin_expect(!!(scope->is_declaration_scope() &&
scope->AsDeclarationScope()->sloppy_eval_can_extend_vars
()), 0))
) {
2152 return LookupSloppyEval(proxy, scope, outer_scope_end, cache_scope,
2153 force_context_allocation);
2154 }
2155
2156 force_context_allocation |= scope->is_function_scope();
2157 scope = scope->outer_scope_;
2158
2159 // TODO(verwaest): Separate through AnalyzePartially.
2160 if (mode == kParsedScope && !scope->scope_info_.is_null()) {
2161 DCHECK_NULL(cache_scope)((void) 0);
2162 cache_scope = scope->GetNonEvalDeclarationScope();
2163 return Lookup<kDeserializedScope>(proxy, scope, outer_scope_end,
2164 cache_scope);
2165 }
2166 }
2167
2168 // We may just be trying to find all free variables. In that case, don't
2169 // declare them in the outer scope.
2170 // TODO(marja): Separate Lookup for preparsed scopes better.
2171 if (mode == kParsedScope && !scope->is_script_scope()) {
2172 return nullptr;
2173 }
2174
2175 // No binding has been found. Declare a variable on the global object.
2176 return scope->AsDeclarationScope()->DeclareDynamicGlobal(
2177 proxy->raw_name(), NORMAL_VARIABLE,
2178 mode == kDeserializedScope ? cache_scope : scope);
2179}
2180
2181template Variable* Scope::Lookup<Scope::kParsedScope>(
2182 VariableProxy* proxy, Scope* scope, Scope* outer_scope_end,
2183 Scope* cache_scope, bool force_context_allocation);
2184template Variable* Scope::Lookup<Scope::kDeserializedScope>(
2185 VariableProxy* proxy, Scope* scope, Scope* outer_scope_end,
2186 Scope* cache_scope, bool force_context_allocation);
2187
2188Variable* Scope::LookupWith(VariableProxy* proxy, Scope* scope,
2189 Scope* outer_scope_end, Scope* cache_scope,
2190 bool force_context_allocation) {
2191 DCHECK(scope->is_with_scope())((void) 0);
2192
2193 Variable* var =
2194 scope->outer_scope_->scope_info_.is_null()
2195 ? Lookup<kParsedScope>(proxy, scope->outer_scope_, outer_scope_end,
2196 nullptr, force_context_allocation)
2197 : Lookup<kDeserializedScope>(proxy, scope->outer_scope_,
2198 outer_scope_end, cache_scope);
2199
2200 if (var == nullptr) return var;
2201
2202 // The current scope is a with scope, so the variable binding can not be
2203 // statically resolved. However, note that it was necessary to do a lookup
2204 // in the outer scope anyway, because if a binding exists in an outer
2205 // scope, the associated variable has to be marked as potentially being
2206 // accessed from inside of an inner with scope (the property may not be in
2207 // the 'with' object).
2208 if (!var->is_dynamic() && var->IsUnallocated()) {
2209 DCHECK(!scope->already_resolved_)((void) 0);
2210 var->set_is_used();
2211 var->ForceContextAllocation();
2212 if (proxy->is_assigned()) var->SetMaybeAssigned();
2213 }
2214 Scope* target_scope;
2215 if (scope->deserialized_scope_uses_external_cache()) {
2216 DCHECK_NOT_NULL(cache_scope)((void) 0);
2217 cache_scope->variables_.Remove(var);
2218 target_scope = cache_scope;
2219 } else {
2220 target_scope = scope;
2221 }
2222 Variable* dynamic =
2223 target_scope->NonLocal(proxy->raw_name(), VariableMode::kDynamic);
2224 dynamic->set_local_if_not_shadowed(var);
2225 return dynamic;
2226}
2227
2228Variable* Scope::LookupSloppyEval(VariableProxy* proxy, Scope* scope,
2229 Scope* outer_scope_end, Scope* cache_scope,
2230 bool force_context_allocation) {
2231 DCHECK(scope->is_declaration_scope() &&((void) 0)
2232 scope->AsDeclarationScope()->sloppy_eval_can_extend_vars())((void) 0);
2233
2234 // If we're compiling eval, it's possible that the outer scope is the first
2235 // ScopeInfo-backed scope. We use the next declaration scope as the cache for
2236 // this case, to avoid complexity around sloppy block function hoisting and
2237 // conflict detection through catch scopes in the eval.
2238 Scope* entry_cache = cache_scope == nullptr
2239 ? scope->outer_scope()->GetNonEvalDeclarationScope()
2240 : cache_scope;
2241 Variable* var =
2242 scope->outer_scope_->scope_info_.is_null()
2243 ? Lookup<kParsedScope>(proxy, scope->outer_scope_, outer_scope_end,
2244 nullptr, force_context_allocation)
2245 : Lookup<kDeserializedScope>(proxy, scope->outer_scope_,
2246 outer_scope_end, entry_cache);
2247 if (var == nullptr) return var;
2248
2249 // We may not want to use the cache scope, change it back to the given scope
2250 // if necessary.
2251 if (!scope->deserialized_scope_uses_external_cache()) {
2252 // For a deserialized scope, we'll be replacing the cache_scope.
2253 DCHECK_IMPLIES(!scope->scope_info_.is_null(), cache_scope != nullptr)((void) 0);
2254 cache_scope = scope;
2255 }
2256
2257 // A variable binding may have been found in an outer scope, but the current
2258 // scope makes a sloppy 'eval' call, so the found variable may not be the
2259 // correct one (the 'eval' may introduce a binding with the same name). In
2260 // that case, change the lookup result to reflect this situation. Only
2261 // scopes that can host var bindings (declaration scopes) need be considered
2262 // here (this excludes block and catch scopes), and variable lookups at
2263 // script scope are always dynamic.
2264 if (var->IsGlobalObjectProperty()) {
2265 Scope* target = cache_scope == nullptr ? scope : cache_scope;
2266 var = target->NonLocal(proxy->raw_name(), VariableMode::kDynamicGlobal);
2267 }
2268
2269 if (var->is_dynamic()) return var;
2270
2271 Variable* invalidated = var;
2272 if (cache_scope != nullptr) cache_scope->variables_.Remove(invalidated);
2273
2274 Scope* target = cache_scope == nullptr ? scope : cache_scope;
2275 var = target->NonLocal(proxy->raw_name(), VariableMode::kDynamicLocal);
2276 var->set_local_if_not_shadowed(invalidated);
2277
2278 return var;
2279}
2280
2281void Scope::ResolveVariable(VariableProxy* proxy) {
2282 DCHECK(!proxy->is_resolved())((void) 0);
2283 Variable* var = Lookup<kParsedScope>(proxy, this, nullptr);
2284 DCHECK_NOT_NULL(var)((void) 0);
2285 ResolveTo(proxy, var);
2286}
2287
2288namespace {
2289
2290void SetNeedsHoleCheck(Variable* var, VariableProxy* proxy) {
2291 proxy->set_needs_hole_check();
2292 var->ForceHoleInitialization();
2293}
2294
2295void UpdateNeedsHoleCheck(Variable* var, VariableProxy* proxy, Scope* scope) {
2296 if (var->mode() == VariableMode::kDynamicLocal) {
2297 // Dynamically introduced variables never need a hole check (since they're
2298 // VariableMode::kVar bindings, either from var or function declarations),
2299 // but the variable they shadow might need a hole check, which we want to do
2300 // if we decide that no shadowing variable was dynamically introoduced.
2301 DCHECK_EQ(kCreatedInitialized, var->initialization_flag())((void) 0);
2302 return UpdateNeedsHoleCheck(var->local_if_not_shadowed(), proxy, scope);
2303 }
2304
2305 if (var->initialization_flag() == kCreatedInitialized) return;
2306
2307 // It's impossible to eliminate module import hole checks here, because it's
2308 // unknown at compilation time whether the binding referred to in the
2309 // exporting module itself requires hole checks.
2310 if (var->location() == VariableLocation::MODULE && !var->IsExport()) {
2311 return SetNeedsHoleCheck(var, proxy);
2312 }
2313
2314 // Check if the binding really needs an initialization check. The check
2315 // can be skipped in the following situation: we have a VariableMode::kLet or
2316 // VariableMode::kConst binding, both the Variable and the VariableProxy have
2317 // the same declaration scope (i.e. they are both in global code, in the same
2318 // function or in the same eval code), the VariableProxy is in the source
2319 // physically located after the initializer of the variable, and that the
2320 // initializer cannot be skipped due to a nonlinear scope.
2321 //
2322 // The condition on the closure scopes is a conservative check for
2323 // nested functions that access a binding and are called before the
2324 // binding is initialized:
2325 // function() { f(); let x = 1; function f() { x = 2; } }
2326 //
2327 // The check cannot be skipped on non-linear scopes, namely switch
2328 // scopes, to ensure tests are done in cases like the following:
2329 // switch (1) { case 0: let x = 2; case 1: f(x); }
2330 // The scope of the variable needs to be checked, in case the use is
2331 // in a sub-block which may be linear.
2332 if (var->scope()->GetClosureScope() != scope->GetClosureScope()) {
2333 return SetNeedsHoleCheck(var, proxy);
2334 }
2335
2336 // We should always have valid source positions.
2337 DCHECK_NE(var->initializer_position(), kNoSourcePosition)((void) 0);
2338 DCHECK_NE(proxy->position(), kNoSourcePosition)((void) 0);
2339
2340 if (var->scope()->is_nonlinear() ||
2341 var->initializer_position() >= proxy->position()) {
2342 return SetNeedsHoleCheck(var, proxy);
2343 }
2344}
2345
2346} // anonymous namespace
2347
2348void Scope::ResolveTo(VariableProxy* proxy, Variable* var) {
2349 DCHECK_NOT_NULL(var)((void) 0);
2350 UpdateNeedsHoleCheck(var, proxy, this);
2351 proxy->BindTo(var);
2352}
2353
2354void Scope::ResolvePreparsedVariable(VariableProxy* proxy, Scope* scope,
2355 Scope* end) {
2356 // Resolve the variable in all parsed scopes to force context allocation.
2357 for (; scope != end; scope = scope->outer_scope_) {
2358 Variable* var = scope->LookupLocal(proxy->raw_name());
2359 if (var != nullptr) {
2360 var->set_is_used();
2361 if (!var->is_dynamic()) {
2362 var->ForceContextAllocation();
2363 if (proxy->is_assigned()) var->SetMaybeAssigned();
2364 return;
2365 }
2366 }
2367 }
2368}
2369
2370bool Scope::ResolveVariablesRecursively(Scope* end) {
2371 // Lazy parsed declaration scopes are already partially analyzed. If there are
2372 // unresolved references remaining, they just need to be resolved in outer
2373 // scopes.
2374 if (WasLazilyParsed(this)) {
2375 DCHECK_EQ(variables_.occupancy(), 0)((void) 0);
2376 // Resolve in all parsed scopes except for the script scope.
2377 if (!end->is_script_scope()) end = end->outer_scope();
2378
2379 for (VariableProxy* proxy : unresolved_list_) {
2380 ResolvePreparsedVariable(proxy, outer_scope(), end);
2381 }
2382 } else {
2383 // Resolve unresolved variables for this scope.
2384 for (VariableProxy* proxy : unresolved_list_) {
2385 ResolveVariable(proxy);
2386 }
2387
2388 // Resolve unresolved variables for inner scopes.
2389 for (Scope* scope = inner_scope_; scope != nullptr;
2390 scope = scope->sibling_) {
2391 if (!scope->ResolveVariablesRecursively(end)) return false;
2392 }
2393 }
2394 return true;
2395}
2396
2397bool Scope::MustAllocate(Variable* var) {
2398 DCHECK(var->location() != VariableLocation::MODULE)((void) 0);
2399 // Give var a read/write use if there is a chance it might be accessed
2400 // via an eval() call. This is only possible if the variable has a
2401 // visible name.
2402 if (!var->raw_name()->IsEmpty() &&
2403 (inner_scope_calls_eval_ || is_catch_scope() || is_script_scope())) {
2404 var->set_is_used();
2405 if (inner_scope_calls_eval_ && !var->is_this()) var->SetMaybeAssigned();
2406 }
2407 DCHECK(!var->has_forced_context_allocation() || var->is_used())((void) 0);
2408 // Global variables do not need to be allocated.
2409 return !var->IsGlobalObjectProperty() && var->is_used();
2410}
2411
2412
2413bool Scope::MustAllocateInContext(Variable* var) {
2414 // If var is accessed from an inner scope, or if there is a possibility
2415 // that it might be accessed from the current or an inner scope (through
2416 // an eval() call or a runtime with lookup), it must be allocated in the
2417 // context.
2418 //
2419 // Temporary variables are always stack-allocated. Catch-bound variables are
2420 // always context-allocated.
2421 VariableMode mode = var->mode();
2422 if (mode == VariableMode::kTemporary) return false;
2423 if (is_catch_scope()) return true;
2424 if (is_script_scope() || is_eval_scope()) {
2425 if (IsLexicalVariableMode(mode)) {
2426 return true;
2427 }
2428 }
2429 return var->has_forced_context_allocation() || inner_scope_calls_eval_;
2430}
2431
2432void Scope::AllocateStackSlot(Variable* var) {
2433 if (is_block_scope()) {
2434 outer_scope()->GetDeclarationScope()->AllocateStackSlot(var);
2435 } else {
2436 var->AllocateTo(VariableLocation::LOCAL, num_stack_slots_++);
2437 }
2438}
2439
2440
2441void Scope::AllocateHeapSlot(Variable* var) {
2442 var->AllocateTo(VariableLocation::CONTEXT, num_heap_slots_++);
2443}
2444
2445void DeclarationScope::AllocateParameterLocals() {
2446 DCHECK(is_function_scope())((void) 0);
2447
2448 bool has_mapped_arguments = false;
2449 if (arguments_ != nullptr) {
2450 DCHECK(!is_arrow_scope())((void) 0);
2451 if (MustAllocate(arguments_) && !has_arguments_parameter_) {
2452 // 'arguments' is used and does not refer to a function
2453 // parameter of the same name. If the arguments object
2454 // aliases formal parameters, we conservatively allocate
2455 // them specially in the loop below.
2456 has_mapped_arguments =
2457 GetArgumentsType() == CreateArgumentsType::kMappedArguments;
2458 } else {
2459 // 'arguments' is unused. Tell the code generator that it does not need to
2460 // allocate the arguments object by nulling out arguments_.
2461 arguments_ = nullptr;
2462 }
2463 }
2464
2465 // The same parameter may occur multiple times in the parameters_ list.
2466 // If it does, and if it is not copied into the context object, it must
2467 // receive the highest parameter index for that parameter; thus iteration
2468 // order is relevant!
2469 for (int i = num_parameters() - 1; i >= 0; --i) {
2470 Variable* var = params_[i];
2471 DCHECK_NOT_NULL(var)((void) 0);
2472 DCHECK(!has_rest_ || var != rest_parameter())((void) 0);
2473 DCHECK_EQ(this, var->scope())((void) 0);
2474 if (has_mapped_arguments) {
2475 var->set_is_used();
2476 var->SetMaybeAssigned();
2477 var->ForceContextAllocation();
2478 }
2479 AllocateParameter(var, i);
2480 }
2481}
2482
2483void DeclarationScope::AllocateParameter(Variable* var, int index) {
2484 if (!MustAllocate(var)) return;
2485 if (has_forced_context_allocation_for_parameters() ||
2486 MustAllocateInContext(var)) {
2487 DCHECK(var->IsUnallocated() || var->IsContextSlot())((void) 0);
2488 if (var->IsUnallocated()) AllocateHeapSlot(var);
2489 } else {
2490 DCHECK(var->IsUnallocated() || var->IsParameter())((void) 0);
2491 if (var->IsUnallocated()) {
2492 var->AllocateTo(VariableLocation::PARAMETER, index);
2493 }
2494 }
2495}
2496
2497void DeclarationScope::AllocateReceiver() {
2498 if (!has_this_declaration()) return;
2499 DCHECK_NOT_NULL(receiver())((void) 0);
2500 DCHECK_EQ(receiver()->scope(), this)((void) 0);
2501 AllocateParameter(receiver(), -1);
2502}
2503
2504void Scope::AllocateNonParameterLocal(Variable* var) {
2505 DCHECK_EQ(var->scope(), this)((void) 0);
2506 if (var->IsUnallocated() && MustAllocate(var)) {
2507 if (MustAllocateInContext(var)) {
2508 AllocateHeapSlot(var);
2509 DCHECK_IMPLIES(is_catch_scope(),((void) 0)
2510 var->index() == Context::THROWN_OBJECT_INDEX)((void) 0);
2511 } else {
2512 AllocateStackSlot(var);
2513 }
2514 }
2515}
2516
2517void Scope::AllocateNonParameterLocalsAndDeclaredGlobals() {
2518 if (is_declaration_scope() && AsDeclarationScope()->is_arrow_scope()) {
2519 // In arrow functions, allocate non-temporaries first and then all the
2520 // temporaries to make the local variable ordering stable when reparsing to
2521 // collect source positions.
2522 for (Variable* local : locals_) {
2523 if (local->mode() != VariableMode::kTemporary)
2524 AllocateNonParameterLocal(local);
2525 }
2526
2527 for (Variable* local : locals_) {
2528 if (local->mode() == VariableMode::kTemporary)
2529 AllocateNonParameterLocal(local);
2530 }
2531 } else {
2532 for (Variable* local : locals_) {
2533 AllocateNonParameterLocal(local);
2534 }
2535 }
2536
2537 if (is_declaration_scope()) {
2538 AsDeclarationScope()->AllocateLocals();
2539 }
2540}
2541
2542void DeclarationScope::AllocateLocals() {
2543 // For now, function_ must be allocated at the very end. If it gets
2544 // allocated in the context, it must be the last slot in the context,
2545 // because of the current ScopeInfo implementation (see
2546 // ScopeInfo::ScopeInfo(FunctionScope* scope) constructor).
2547 if (function_ != nullptr && MustAllocate(function_)) {
2548 AllocateNonParameterLocal(function_);
2549 } else {
2550 function_ = nullptr;
2551 }
2552
2553 DCHECK(!has_rest_ || !MustAllocate(rest_parameter()) ||((void) 0)
2554 !rest_parameter()->IsUnallocated())((void) 0);
2555
2556 if (new_target_ != nullptr && !MustAllocate(new_target_)) {
2557 new_target_ = nullptr;
2558 }
2559
2560 NullifyRareVariableIf(RareVariable::kThisFunction,
2561 [=](Variable* var) { return !MustAllocate(var); });
2562}
2563
2564void ModuleScope::AllocateModuleVariables() {
2565 for (const auto& it : module()->regular_imports()) {
2566 Variable* var = LookupLocal(it.first);
2567 var->AllocateTo(VariableLocation::MODULE, it.second->cell_index);
2568 DCHECK(!var->IsExport())((void) 0);
2569 }
2570
2571 for (const auto& it : module()->regular_exports()) {
2572 Variable* var = LookupLocal(it.first);
2573 var->AllocateTo(VariableLocation::MODULE, it.second->cell_index);
2574 DCHECK(var->IsExport())((void) 0);
2575 }
2576}
2577
2578void Scope::AllocateVariablesRecursively() {
2579 this->ForEach([](Scope* scope) -> Iteration {
2580 DCHECK(!scope->already_resolved_)((void) 0);
2581 if (WasLazilyParsed(scope)) return Iteration::kContinue;
2582 DCHECK_EQ(scope->ContextHeaderLength(), scope->num_heap_slots_)((void) 0);
2583
2584 // Allocate variables for this scope.
2585 // Parameters must be allocated first, if any.
2586 if (scope->is_declaration_scope()) {
2587 scope->AsDeclarationScope()->AllocateReceiver();
2588 if (scope->is_function_scope()) {
2589 scope->AsDeclarationScope()->AllocateParameterLocals();
2590 }
2591 }
2592 scope->AllocateNonParameterLocalsAndDeclaredGlobals();
2593
2594 // Force allocation of a context for this scope if necessary. For a 'with'
2595 // scope and for a function scope that makes an 'eval' call we need a
2596 // context, even if no local variables were statically allocated in the
2597 // scope. Likewise for modules and function scopes representing asm.js
2598 // modules. Also force a context, if the scope is stricter than the outer
2599 // scope.
2600 bool must_have_context =
2601 scope->is_with_scope() || scope->is_module_scope() ||
2602#if V8_ENABLE_WEBASSEMBLY1
2603 scope->IsAsmModule() ||
2604#endif // V8_ENABLE_WEBASSEMBLY
2605 scope->ForceContextForLanguageMode() ||
2606 (scope->is_function_scope() &&
2607 scope->AsDeclarationScope()->sloppy_eval_can_extend_vars()) ||
2608 (scope->is_block_scope() && scope->is_declaration_scope() &&
2609 scope->AsDeclarationScope()->sloppy_eval_can_extend_vars());
2610
2611 // If we didn't allocate any locals in the local context, then we only
2612 // need the minimal number of slots if we must have a context.
2613 if (scope->num_heap_slots_ == scope->ContextHeaderLength() &&
2614 !must_have_context) {
2615 scope->num_heap_slots_ = 0;
2616 }
2617
2618 // Allocation done.
2619 DCHECK(scope->num_heap_slots_ == 0 ||((void) 0)
2620 scope->num_heap_slots_ >= scope->ContextHeaderLength())((void) 0);
2621 return Iteration::kDescend;
2622 });
2623}
2624
2625template <typename IsolateT>
2626void Scope::AllocateScopeInfosRecursively(IsolateT* isolate,
2627 MaybeHandle<ScopeInfo> outer_scope) {
2628 DCHECK(scope_info_.is_null())((void) 0);
2629 MaybeHandle<ScopeInfo> next_outer_scope = outer_scope;
2630
2631 if (NeedsScopeInfo()) {
2632 scope_info_ = ScopeInfo::Create(isolate, zone(), this, outer_scope);
2633 // The ScopeInfo chain should mirror the context chain, so we only link to
2634 // the next outer scope that needs a context.
2635 if (NeedsContext()) next_outer_scope = scope_info_;
2636 }
2637
2638 // Allocate ScopeInfos for inner scopes.
2639 for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) {
2640 if (!scope->is_function_scope() ||
2641 scope->AsDeclarationScope()->ShouldEagerCompile()) {
2642 scope->AllocateScopeInfosRecursively(isolate, next_outer_scope);
2643 }
2644 }
2645}
2646
2647template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) void Scope::
2648 AllocateScopeInfosRecursively<Isolate>(Isolate* isolate,
2649 MaybeHandle<ScopeInfo> outer_scope);
2650template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) void Scope::
2651 AllocateScopeInfosRecursively<LocalIsolate>(
2652 LocalIsolate* isolate, MaybeHandle<ScopeInfo> outer_scope);
2653
2654void DeclarationScope::RecalcPrivateNameContextChain() {
2655 // The outermost scope in a class heritage expression is marked to skip the
2656 // class scope during private name resolution. It is possible, however, that
2657 // either the class scope won't require a Context and ScopeInfo, or the
2658 // outermost scope in the heritage position won't. Simply copying the bit from
2659 // full parse into the ScopeInfo will break lazy compilation. In the former
2660 // case the scope that is marked to skip its outer scope will incorrectly skip
2661 // a different class scope than the one we intended to skip. In the latter
2662 // case variables resolved through an inner scope will incorrectly check the
2663 // class scope since we lost the skip bit from the outermost heritage scope.
2664 //
2665 // This method fixes both cases by, in outermost to innermost order, copying
2666 // the value of the skip bit from outer scopes that don't require a Context.
2667 DCHECK(needs_private_name_context_chain_recalc_)((void) 0);
2668 this->ForEach([](Scope* scope) {
2669 Scope* outer = scope->outer_scope();
2670 if (!outer) return Iteration::kDescend;
2671 if (!outer->NeedsContext()) {
2672 scope->private_name_lookup_skips_outer_class_ =
2673 outer->private_name_lookup_skips_outer_class();
2674 }
2675 if (!scope->is_function_scope() ||
2676 scope->AsDeclarationScope()->ShouldEagerCompile()) {
2677 return Iteration::kDescend;
2678 }
2679 return Iteration::kContinue;
2680 });
2681}
2682
2683void DeclarationScope::RecordNeedsPrivateNameContextChainRecalc() {
2684 DCHECK_EQ(GetClosureScope(), this)((void) 0);
2685 DeclarationScope* scope;
2686 for (scope = this; scope != nullptr;
2687 scope = scope->outer_scope() != nullptr
2688 ? scope->outer_scope()->GetClosureScope()
2689 : nullptr) {
2690 if (scope->needs_private_name_context_chain_recalc_) return;
2691 scope->needs_private_name_context_chain_recalc_ = true;
2692 }
2693}
2694
2695// static
2696template <typename IsolateT>
2697void DeclarationScope::AllocateScopeInfos(ParseInfo* info, IsolateT* isolate) {
2698 DeclarationScope* scope = info->literal()->scope();
2699
2700 // No one else should have allocated a scope info for this scope yet.
2701 DCHECK(scope->scope_info_.is_null())((void) 0);
2702
2703 MaybeHandle<ScopeInfo> outer_scope;
2704 if (scope->outer_scope_ != nullptr) {
2705 DCHECK((std::is_same<Isolate, v8::internal::Isolate>::value))((void) 0);
2706 outer_scope = scope->outer_scope_->scope_info_;
2707 }
2708
2709 if (scope->needs_private_name_context_chain_recalc()) {
2710 scope->RecalcPrivateNameContextChain();
2711 }
2712 scope->AllocateScopeInfosRecursively(isolate, outer_scope);
2713
2714 // The debugger expects all shared function infos to contain a scope info.
2715 // Since the top-most scope will end up in a shared function info, make sure
2716 // it has one, even if it doesn't need a scope info.
2717 // TODO(yangguo): Remove this requirement.
2718 if (scope->scope_info_.is_null()) {
2719 scope->scope_info_ =
2720 ScopeInfo::Create(isolate, scope->zone(), scope, outer_scope);
2721 }
2722
2723 // Ensuring that the outer script scope has a scope info avoids having
2724 // special case for native contexts vs other contexts.
2725 if (info->script_scope() && info->script_scope()->scope_info_.is_null()) {
2726 info->script_scope()->scope_info_ = isolate->factory()->empty_scope_info();
2727 }
2728}
2729
2730template V8_EXPORT_PRIVATE void DeclarationScope::AllocateScopeInfos(
2731 ParseInfo* info, Isolate* isolate);
2732template V8_EXPORT_PRIVATE void DeclarationScope::AllocateScopeInfos(
2733 ParseInfo* info, LocalIsolate* isolate);
2734
2735int Scope::ContextLocalCount() const {
2736 if (num_heap_slots() == 0) return 0;
2737 Variable* function =
2738 is_function_scope() ? AsDeclarationScope()->function_var() : nullptr;
2739 bool is_function_var_in_context =
2740 function != nullptr && function->IsContextSlot();
2741 return num_heap_slots() - ContextHeaderLength() -
2742 (is_function_var_in_context ? 1 : 0);
2743}
2744
2745VariableProxy* Scope::NewHomeObjectVariableProxy(AstNodeFactory* factory,
2746 const AstRawString* name,
2747 int start_pos) {
2748 // VariableProxies of the home object cannot be resolved like a normal
2749 // variable. Consider the case of a super.property usage in heritage position:
2750 //
2751 // class C extends super.foo { m() { super.bar(); } }
2752 //
2753 // The super.foo property access is logically nested under C's class scope,
2754 // which also has a home object due to its own method m's usage of
2755 // super.bar(). However, super.foo must resolve super in C's outer scope.
2756 //
2757 // Because of the above, home object VariableProxies are always made directly
2758 // on the Scope that needs the home object instead of the innermost scope.
2759 DCHECK(needs_home_object())((void) 0);
2760 if (!scope_info_.is_null()) {
2761 // This is a lazy compile, so the home object's context slot is already
2762 // known.
2763 Variable* home_object = variables_.Lookup(name);
2764 if (home_object == nullptr) {
2765 VariableLookupResult lookup_result;
2766 int index = scope_info_->ContextSlotIndex(name->string(), &lookup_result);
2767 DCHECK_GE(index, 0)((void) 0);
2768 bool was_added;
2769 home_object = variables_.Declare(zone(), this, name, lookup_result.mode,
2770 NORMAL_VARIABLE, lookup_result.init_flag,
2771 lookup_result.maybe_assigned_flag,
2772 IsStaticFlag::kNotStatic, &was_added);
2773 DCHECK(was_added)((void) 0);
2774 home_object->AllocateTo(VariableLocation::CONTEXT, index);
2775 }
2776 return factory->NewVariableProxy(home_object, start_pos);
2777 }
2778 // This is not a lazy compile. Add the unresolved home object VariableProxy to
2779 // the unresolved list of the home object scope, which is not necessarily the
2780 // innermost scope.
2781 VariableProxy* proxy =
2782 factory->NewVariableProxy(name, NORMAL_VARIABLE, start_pos);
2783 AddUnresolved(proxy);
2784 return proxy;
2785}
2786
2787bool IsComplementaryAccessorPair(VariableMode a, VariableMode b) {
2788 switch (a) {
2789 case VariableMode::kPrivateGetterOnly:
2790 return b == VariableMode::kPrivateSetterOnly;
2791 case VariableMode::kPrivateSetterOnly:
2792 return b == VariableMode::kPrivateGetterOnly;
2793 default:
2794 return false;
2795 }
2796}
2797
2798void ClassScope::FinalizeReparsedClassScope(
2799 Isolate* isolate, MaybeHandle<ScopeInfo> maybe_scope_info,
2800 AstValueFactory* ast_value_factory, bool needs_allocation_fixup) {
2801 // Set this bit so that DelcarationScope::Analyze recognizes
2802 // the reparsed instance member initializer scope.
2803#ifdef DEBUG
2804 is_reparsed_class_scope_ = true;
2805#endif
2806
2807 if (!needs_allocation_fixup) {
2808 return;
2809 }
2810
2811 // Restore variable allocation results for context-allocated variables in
2812 // the class scope from ScopeInfo, so that we don't need to run
2813 // resolution and allocation on these variables again when generating
2814 // code for the initializer function.
2815 DCHECK(!maybe_scope_info.is_null())((void) 0);
2816 Handle<ScopeInfo> scope_info = maybe_scope_info.ToHandleChecked();
2817 DCHECK_EQ(scope_info->scope_type(), CLASS_SCOPE)((void) 0);
2818 DCHECK_EQ(scope_info->StartPosition(), start_position_)((void) 0);
2819
2820 int context_header_length = scope_info->ContextHeaderLength();
2821 DisallowGarbageCollection no_gc;
2822 for (auto it : ScopeInfo::IterateLocalNames(scope_info)) {
2823 int slot_index = context_header_length + it->index();
2824 DCHECK_LT(slot_index, scope_info->ContextLength())((void) 0);
2825
2826 const AstRawString* string = ast_value_factory->GetString(
2827 it->name(), SharedStringAccessGuardIfNeeded(isolate));
2828 Variable* var = string->IsPrivateName() ? LookupLocalPrivateName(string)
2829 : LookupLocal(string);
2830 DCHECK_NOT_NULL(var)((void) 0);
2831 var->AllocateTo(VariableLocation::CONTEXT, slot_index);
2832 }
2833 scope_info_ = scope_info;
2834}
2835
2836Variable* ClassScope::DeclarePrivateName(const AstRawString* name,
2837 VariableMode mode,
2838 IsStaticFlag is_static_flag,
2839 bool* was_added) {
2840 Variable* result = EnsureRareData()->private_name_map.Declare(
2841 zone(), this, name, mode, NORMAL_VARIABLE,
2842 InitializationFlag::kNeedsInitialization, MaybeAssignedFlag::kNotAssigned,
2843 is_static_flag, was_added);
2844 if (*was_added) {
2845 locals_.Add(result);
2846 has_static_private_methods_ |=
2847 (result->is_static() &&
2848 IsPrivateMethodOrAccessorVariableMode(result->mode()));
2849 } else if (IsComplementaryAccessorPair(result->mode(), mode) &&
2850 result->is_static_flag() == is_static_flag) {
2851 *was_added = true;
2852 result->set_mode(VariableMode::kPrivateGetterAndSetter);
2853 }
2854 result->ForceContextAllocation();
2855 return result;
2856}
2857
2858Variable* ClassScope::LookupLocalPrivateName(const AstRawString* name) {
2859 RareData* rare_data = GetRareData();
2860 if (rare_data == nullptr) {
2861 return nullptr;
2862 }
2863 return rare_data->private_name_map.Lookup(name);
2864}
2865
2866UnresolvedList::Iterator ClassScope::GetUnresolvedPrivateNameTail() {
2867 RareData* rare_data = GetRareData();
2868 if (rare_data == nullptr) {
2869 return UnresolvedList::Iterator();
2870 }
2871 return rare_data->unresolved_private_names.end();
2872}
2873
2874void ClassScope::ResetUnresolvedPrivateNameTail(UnresolvedList::Iterator tail) {
2875 RareData* rare_data = GetRareData();
2876 if (rare_data == nullptr ||
2877 rare_data->unresolved_private_names.end() == tail) {
2878 return;
2879 }
2880
2881 bool tail_is_empty = tail == UnresolvedList::Iterator();
2882 if (tail_is_empty) {
2883 // If the saved tail is empty, the list used to be empty, so clear it.
2884 rare_data->unresolved_private_names.Clear();
2885 } else {
2886 rare_data->unresolved_private_names.Rewind(tail);
2887 }
2888}
2889
2890void ClassScope::MigrateUnresolvedPrivateNameTail(
2891 AstNodeFactory* ast_node_factory, UnresolvedList::Iterator tail) {
2892 RareData* rare_data = GetRareData();
2893 if (rare_data == nullptr ||
2894 rare_data->unresolved_private_names.end() == tail) {
2895 return;
2896 }
2897 UnresolvedList migrated_names;
2898
2899 // If the saved tail is empty, the list used to be empty, so we should
2900 // migrate everything after the head.
2901 bool tail_is_empty = tail == UnresolvedList::Iterator();
2902 UnresolvedList::Iterator it =
2903 tail_is_empty ? rare_data->unresolved_private_names.begin() : tail;
2904
2905 for (; it != rare_data->unresolved_private_names.end(); ++it) {
2906 VariableProxy* proxy = *it;
2907 VariableProxy* copy = ast_node_factory->CopyVariableProxy(proxy);
2908 migrated_names.Add(copy);
2909 }
2910
2911 // Replace with the migrated copies.
2912 if (tail_is_empty) {
2913 rare_data->unresolved_private_names.Clear();
2914 } else {
2915 rare_data->unresolved_private_names.Rewind(tail);
2916 }
2917 rare_data->unresolved_private_names.Append(std::move(migrated_names));
2918}
2919
2920Variable* ClassScope::LookupPrivateNameInScopeInfo(const AstRawString* name) {
2921 DCHECK(!scope_info_.is_null())((void) 0);
2922 DCHECK_NULL(LookupLocalPrivateName(name))((void) 0);
2923 DisallowGarbageCollection no_gc;
2924
2925 VariableLookupResult lookup_result;
2926 int index = scope_info_->ContextSlotIndex(name->string(), &lookup_result);
2927 if (index < 0) {
2928 return nullptr;
2929 }
2930
2931 DCHECK(IsConstVariableMode(lookup_result.mode))((void) 0);
2932 DCHECK_EQ(lookup_result.init_flag, InitializationFlag::kNeedsInitialization)((void) 0);
2933 DCHECK_EQ(lookup_result.maybe_assigned_flag, MaybeAssignedFlag::kNotAssigned)((void) 0);
2934
2935 // Add the found private name to the map to speed up subsequent
2936 // lookups for the same name.
2937 bool was_added;
2938 Variable* var = DeclarePrivateName(name, lookup_result.mode,
2939 lookup_result.is_static_flag, &was_added);
2940 DCHECK(was_added)((void) 0);
2941 var->AllocateTo(VariableLocation::CONTEXT, index);
2942 return var;
2943}
2944
2945Variable* ClassScope::LookupPrivateName(VariableProxy* proxy) {
2946 DCHECK(!proxy->is_resolved())((void) 0);
2947
2948 for (PrivateNameScopeIterator scope_iter(this); !scope_iter.Done();
2949 scope_iter.Next()) {
2950 ClassScope* scope = scope_iter.GetScope();
2951 // Try finding it in the private name map first, if it can't be found,
2952 // try the deseralized scope info.
2953 Variable* var = scope->LookupLocalPrivateName(proxy->raw_name());
2954 if (var == nullptr && !scope->scope_info_.is_null()) {
2955 var = scope->LookupPrivateNameInScopeInfo(proxy->raw_name());
2956 }
2957 if (var != nullptr) {
2958 return var;
2959 }
2960 }
2961 return nullptr;
2962}
2963
2964bool ClassScope::ResolvePrivateNames(ParseInfo* info) {
2965 RareData* rare_data = GetRareData();
2966 if (rare_data == nullptr || rare_data->unresolved_private_names.is_empty()) {
2967 return true;
2968 }
2969
2970 UnresolvedList& list = rare_data->unresolved_private_names;
2971 for (VariableProxy* proxy : list) {
2972 Variable* var = LookupPrivateName(proxy);
2973 if (var == nullptr) {
2974 // It's only possible to fail to resolve private names here if
2975 // this is at the top level or the private name is accessed through eval.
2976 DCHECK(info->flags().is_eval() || outer_scope_->is_script_scope())((void) 0);
2977 Scanner::Location loc = proxy->location();
2978 info->pending_error_handler()->ReportMessageAt(
2979 loc.beg_pos, loc.end_pos,
2980 MessageTemplate::kInvalidPrivateFieldResolution, proxy->raw_name());
2981 return false;
2982 } else {
2983 proxy->BindTo(var);
2984 }
2985 }
2986
2987 // By now all unresolved private names should be resolved so
2988 // clear the list.
2989 list.Clear();
2990 return true;
2991}
2992
2993VariableProxy* ClassScope::ResolvePrivateNamesPartially() {
2994 RareData* rare_data = GetRareData();
2995 if (rare_data == nullptr || rare_data->unresolved_private_names.is_empty()) {
2996 return nullptr;
2997 }
2998
2999 PrivateNameScopeIterator private_name_scope_iter(this);
3000 private_name_scope_iter.Next();
3001 UnresolvedList& unresolved = rare_data->unresolved_private_names;
3002 bool has_private_names = rare_data->private_name_map.capacity() > 0;
3003
3004 // If the class itself does not have private names, nor does it have
3005 // an outer private name scope, then we are certain any private name access
3006 // inside cannot be resolved.
3007 if (!has_private_names && private_name_scope_iter.Done() &&
3008 !unresolved.is_empty()) {
3009 return unresolved.first();
3010 }
3011
3012 for (VariableProxy* proxy = unresolved.first(); proxy != nullptr;) {
3013 DCHECK(proxy->IsPrivateName())((void) 0);
3014 VariableProxy* next = proxy->next_unresolved();
3015 unresolved.Remove(proxy);
3016 Variable* var = nullptr;
3017
3018 // If we can find private name in the current class scope, we can bind
3019 // them immediately because it's going to shadow any outer private names.
3020 if (has_private_names) {
3021 var = LookupLocalPrivateName(proxy->raw_name());
3022 if (var != nullptr) {
3023 var->set_is_used();
3024 proxy->BindTo(var);
3025 // If the variable being accessed is a static private method, we need to
3026 // save the class variable in the context to check that the receiver is
3027 // the class during runtime.
3028 has_explicit_static_private_methods_access_ |=
3029 (var->is_static() &&
3030 IsPrivateMethodOrAccessorVariableMode(var->mode()));
3031 }
3032 }
3033
3034 // If the current scope does not have declared private names,
3035 // try looking from the outer class scope later.
3036 if (var == nullptr) {
3037 // There's no outer private name scope so we are certain that the variable
3038 // cannot be resolved later.
3039 if (private_name_scope_iter.Done()) {
3040 return proxy;
3041 }
3042
3043 // The private name may be found later in the outer private name scope, so
3044 // push it to the outer sopce.
3045 private_name_scope_iter.AddUnresolvedPrivateName(proxy);
3046 }
3047
3048 proxy = next;
3049 }
3050
3051 DCHECK(unresolved.is_empty())((void) 0);
3052 return nullptr;
3053}
3054
3055Variable* ClassScope::DeclareBrandVariable(AstValueFactory* ast_value_factory,
3056 IsStaticFlag is_static_flag,
3057 int class_token_pos) {
3058 DCHECK_IMPLIES(GetRareData() != nullptr, GetRareData()->brand == nullptr)((void) 0);
3059 bool was_added;
3060 Variable* brand = Declare(zone(), ast_value_factory->dot_brand_string(),
3061 VariableMode::kConst, NORMAL_VARIABLE,
3062 InitializationFlag::kNeedsInitialization,
3063 MaybeAssignedFlag::kNotAssigned, &was_added);
3064 DCHECK(was_added)((void) 0);
3065 brand->set_is_static_flag(is_static_flag);
3066 brand->ForceContextAllocation();
3067 brand->set_is_used();
3068 EnsureRareData()->brand = brand;
3069 brand->set_initializer_position(class_token_pos);
3070 return brand;
3071}
3072
3073Variable* ClassScope::DeclareClassVariable(AstValueFactory* ast_value_factory,
3074 const AstRawString* name,
3075 int class_token_pos) {
3076 DCHECK_NULL(class_variable_)((void) 0);
3077 bool was_added;
3078 class_variable_ =
3079 Declare(zone(), name == nullptr ? ast_value_factory->dot_string() : name,
3080 VariableMode::kConst, NORMAL_VARIABLE,
3081 InitializationFlag::kNeedsInitialization,
3082 MaybeAssignedFlag::kMaybeAssigned, &was_added);
3083 DCHECK(was_added)((void) 0);
3084 class_variable_->set_initializer_position(class_token_pos);
3085 return class_variable_;
3086}
3087
3088PrivateNameScopeIterator::PrivateNameScopeIterator(Scope* start)
3089 : start_scope_(start), current_scope_(start) {
3090 if (!start->is_class_scope() || start->AsClassScope()->IsParsingHeritage()) {
3091 Next();
3092 }
3093}
3094
3095void PrivateNameScopeIterator::Next() {
3096 DCHECK(!Done())((void) 0);
3097 Scope* inner = current_scope_;
3098 Scope* scope = inner->outer_scope();
3099 while (scope != nullptr) {
3100 if (scope->is_class_scope()) {
3101 if (!inner->private_name_lookup_skips_outer_class()) {
3102 current_scope_ = scope;
3103 return;
3104 }
3105 skipped_any_scopes_ = true;
3106 }
3107 inner = scope;
3108 scope = scope->outer_scope();
3109 }
3110 current_scope_ = nullptr;
3111}
3112
3113void PrivateNameScopeIterator::AddUnresolvedPrivateName(VariableProxy* proxy) {
3114 // During a reparse, current_scope_->already_resolved_ may be true here,
3115 // because the class scope is deserialized while the function scope inside may
3116 // be new.
3117 DCHECK(!proxy->is_resolved())((void) 0);
3118 DCHECK(proxy->IsPrivateName())((void) 0);
3119 GetScope()->EnsureRareData()->unresolved_private_names.Add(proxy);
3120 // Any closure scope that contain uses of private names that skips over a
3121 // class scope due to heritage expressions need private name context chain
3122 // recalculation, since not all scopes require a Context or ScopeInfo. See
3123 // comment in DeclarationScope::RecalcPrivateNameContextChain.
3124 if (V8_UNLIKELY(skipped_any_scopes_)(__builtin_expect(!!(skipped_any_scopes_), 0))) {
3125 start_scope_->GetClosureScope()->RecordNeedsPrivateNameContextChainRecalc();
3126 }
3127}
3128
3129} // namespace internal
3130} // namespace v8