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') |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 | |||||||
27 | namespace v8 { | ||||||
28 | namespace 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 | |||||||
39 | static_assert(sizeof(VariableMap) == (sizeof(void*) + 2 * sizeof(uint32_t) + | ||||||
40 | sizeof(ZoneAllocationPolicy)), | ||||||
41 | "Empty base optimization didn't kick in for VariableMap"); | ||||||
42 | |||||||
43 | VariableMap::VariableMap(Zone* zone) | ||||||
44 | : ZoneHashMap(8, ZoneAllocationPolicy(zone)) {} | ||||||
45 | |||||||
46 | VariableMap::VariableMap(const VariableMap& other, Zone* zone) | ||||||
47 | : ZoneHashMap(other, ZoneAllocationPolicy(zone)) {} | ||||||
48 | |||||||
49 | Variable* 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 | |||||||
73 | void VariableMap::Remove(Variable* var) { | ||||||
74 | const AstRawString* name = var->raw_name(); | ||||||
75 | ZoneHashMap::Remove(const_cast<AstRawString*>(name), name->Hash()); | ||||||
76 | } | ||||||
77 | |||||||
78 | void 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 | |||||||
87 | Variable* 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 | |||||||
100 | Scope::Scope(Zone* zone) | ||||||
101 | : outer_scope_(nullptr), variables_(zone), scope_type_(SCRIPT_SCOPE) { | ||||||
102 | SetDefaults(); | ||||||
103 | } | ||||||
104 | |||||||
105 | Scope::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 | |||||||
116 | Variable* 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 | |||||||
128 | Variable* 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 | |||||||
142 | DeclarationScope::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 | |||||||
157 | DeclarationScope::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 | |||||||
167 | ModuleScope::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 | |||||||
178 | ModuleScope::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 | |||||||
186 | ClassScope::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 | |||||||
193 | template <typename IsolateT> | ||||||
194 | ClassScope::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 | } | ||||||
231 | template ClassScope::ClassScope(Isolate* isolate, Zone* zone, | ||||||
232 | AstValueFactory* ast_value_factory, | ||||||
233 | Handle<ScopeInfo> scope_info); | ||||||
234 | template ClassScope::ClassScope(LocalIsolate* isolate, Zone* zone, | ||||||
235 | AstValueFactory* ast_value_factory, | ||||||
236 | Handle<ScopeInfo> scope_info); | ||||||
237 | |||||||
238 | Scope::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 | |||||||
271 | DeclarationScope::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 | |||||||
289 | Scope::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 | |||||||
310 | void 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 | |||||||
344 | void 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 | |||||||
384 | bool Scope::HasSimpleParameters() { | ||||||
385 | DeclarationScope* scope = GetClosureScope(); | ||||||
386 | return !scope->is_function_scope() || scope->has_simple_parameters(); | ||||||
387 | } | ||||||
388 | |||||||
389 | void DeclarationScope::set_should_eager_compile() { | ||||||
390 | should_eager_compile_ = !was_lazily_parsed_; | ||||||
391 | } | ||||||
392 | |||||||
393 | #if V8_ENABLE_WEBASSEMBLY1 | ||||||
394 | void DeclarationScope::set_is_asm_module() { is_asm_module_ = true; } | ||||||
395 | |||||||
396 | bool Scope::IsAsmModule() const { | ||||||
397 | return is_function_scope() && AsDeclarationScope()->is_asm_module(); | ||||||
398 | } | ||||||
399 | |||||||
400 | bool 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 | |||||||
416 | template <typename IsolateT> | ||||||
417 | Scope* 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 | |||||||
520 | template <typename IsolateT> | ||||||
521 | void 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 | |||||||
529 | template EXPORT_TEMPLATE_DEFINE( | ||||||
530 | V8_EXPORT_PRIVATE) void Scope::SetScriptScopeInfo(Isolate* isolate, | ||||||
531 | DeclarationScope* | ||||||
532 | script_scope); | ||||||
533 | template EXPORT_TEMPLATE_DEFINE( | ||||||
534 | V8_EXPORT_PRIVATE) void Scope::SetScriptScopeInfo(LocalIsolate* isolate, | ||||||
535 | DeclarationScope* | ||||||
536 | script_scope); | ||||||
537 | |||||||
538 | template 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); | ||||||
543 | template 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 | ||||||
550 | bool 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 | |||||||
558 | DeclarationScope* Scope::AsDeclarationScope() { | ||||||
559 | DCHECK(is_declaration_scope())((void) 0); | ||||||
560 | return static_cast<DeclarationScope*>(this); | ||||||
561 | } | ||||||
562 | |||||||
563 | const DeclarationScope* Scope::AsDeclarationScope() const { | ||||||
564 | DCHECK(is_declaration_scope())((void) 0); | ||||||
565 | return static_cast<const DeclarationScope*>(this); | ||||||
566 | } | ||||||
567 | |||||||
568 | ModuleScope* Scope::AsModuleScope() { | ||||||
569 | DCHECK(is_module_scope())((void) 0); | ||||||
570 | return static_cast<ModuleScope*>(this); | ||||||
571 | } | ||||||
572 | |||||||
573 | const ModuleScope* Scope::AsModuleScope() const { | ||||||
574 | DCHECK(is_module_scope())((void) 0); | ||||||
575 | return static_cast<const ModuleScope*>(this); | ||||||
576 | } | ||||||
577 | |||||||
578 | ClassScope* Scope::AsClassScope() { | ||||||
579 | DCHECK(is_class_scope())((void) 0); | ||||||
580 | return static_cast<ClassScope*>(this); | ||||||
581 | } | ||||||
582 | |||||||
583 | const ClassScope* Scope::AsClassScope() const { | ||||||
584 | DCHECK(is_class_scope())((void) 0); | ||||||
585 | return static_cast<const ClassScope*>(this); | ||||||
586 | } | ||||||
587 | |||||||
588 | void DeclarationScope::DeclareSloppyBlockFunction( | ||||||
589 | SloppyBlockFunctionStatement* sloppy_block_function) { | ||||||
590 | sloppy_block_functions_.Add(sloppy_block_function); | ||||||
591 | } | ||||||
592 | |||||||
593 | void 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; | ||||||
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_; | ||||||
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 { | ||||||
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); | ||||||
644 | |||||||
645 | if (!should_hoist
| ||||||
646 | |||||||
647 | if (factory
| ||||||
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( | ||||||
656 | declaration, name, pos, VariableMode::kVar, NORMAL_VARIABLE, | ||||||
657 | Variable::DefaultInitializationFlag(VariableMode::kVar), &was_added, | ||||||
658 | nullptr, &ok); | ||||||
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 | |||||||
679 | bool 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())) { | ||||||
| |||||||
694 | AstNodeFactory factory(info->ast_value_factory(), info->zone()); | ||||||
695 | scope->HoistSloppyBlockFunctions(&factory); | ||||||
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 | |||||||
732 | void 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 | |||||||
746 | void 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 | |||||||
778 | void 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 | |||||||
799 | Variable* 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 | |||||||
818 | Variable* 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 | |||||||
829 | Scope* 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 | |||||||
883 | void 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 | |||||||
890 | void 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 | |||||||
947 | void 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 | |||||||
956 | Variable* 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 | |||||||
1016 | Variable* 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 | |||||||
1050 | void 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 | |||||||
1059 | Variable* 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 | |||||||
1092 | Variable* 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
| ||||||
1105 | return GetDeclarationScope()->DeclareVariable( | ||||||
1106 | declaration, name, pos, mode, kind, init, was_added, | ||||||
1107 | sloppy_mode_block_scope_function_redefinition, ok); | ||||||
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; | ||||||
1119 | if (V8_LIKELY(*was_added)(__builtin_expect(!!(*was_added), 1))) { | ||||||
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; | ||||||
| |||||||
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 | |||||||
1178 | Variable* 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 | |||||||
1214 | Variable* 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 | |||||||
1226 | void Scope::AddUnresolved(VariableProxy* proxy) { | ||||||
1227 | DCHECK(!already_resolved_)((void) 0); | ||||||
1228 | DCHECK(!proxy->is_resolved())((void) 0); | ||||||
1229 | unresolved_list_.Add(proxy); | ||||||
1230 | } | ||||||
1231 | |||||||
1232 | Variable* 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 | |||||||
1243 | bool Scope::RemoveUnresolved(VariableProxy* var) { | ||||||
1244 | return unresolved_list_.Remove(var); | ||||||
1245 | } | ||||||
1246 | |||||||
1247 | void Scope::DeleteUnresolved(VariableProxy* var) { | ||||||
1248 | DCHECK(unresolved_list_.Contains(var))((void) 0); | ||||||
1249 | var->mark_removed_from_unresolved(); | ||||||
1250 | } | ||||||
1251 | |||||||
1252 | Variable* Scope::NewTemporary(const AstRawString* name) { | ||||||
1253 | return NewTemporary(name, kMaybeAssigned); | ||||||
1254 | } | ||||||
1255 | |||||||
1256 | Variable* 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 | |||||||
1266 | Declaration* 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 | |||||||
1330 | const 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 | |||||||
1342 | void 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 | |||||||
1357 | bool 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 | |||||||
1380 | bool 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 | |||||||
1395 | bool 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 | |||||||
1419 | bool 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 | |||||||
1426 | int 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 | |||||||
1435 | int 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 | |||||||
1451 | DeclarationScope* Scope::GetDeclarationScope() { | ||||||
1452 | Scope* scope = this; | ||||||
1453 | while (!scope->is_declaration_scope()) { | ||||||
1454 | scope = scope->outer_scope(); | ||||||
1455 | } | ||||||
1456 | return scope->AsDeclarationScope(); | ||||||
1457 | } | ||||||
1458 | |||||||
1459 | DeclarationScope* 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 | |||||||
1467 | const 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 | |||||||
1475 | DeclarationScope* 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 | |||||||
1483 | bool 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 | |||||||
1492 | bool Scope::ShouldBanArguments() { | ||||||
1493 | return GetReceiverScope()->should_ban_arguments(); | ||||||
1494 | } | ||||||
1495 | |||||||
1496 | DeclarationScope* 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 | |||||||
1506 | DeclarationScope* 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 | |||||||
1518 | Scope* 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 | |||||||
1541 | DeclarationScope* Scope::GetScriptScope() { | ||||||
1542 | Scope* scope = this; | ||||||
1543 | while (!scope->is_script_scope()) { | ||||||
1544 | scope = scope->outer_scope(); | ||||||
1545 | } | ||||||
1546 | return scope->AsDeclarationScope(); | ||||||
1547 | } | ||||||
1548 | |||||||
1549 | Scope* Scope::GetOuterScopeWithContext() { | ||||||
1550 | Scope* scope = outer_scope_; | ||||||
1551 | while (scope && !scope->NeedsContext()) { | ||||||
1552 | scope = scope->outer_scope(); | ||||||
1553 | } | ||||||
1554 | return scope; | ||||||
1555 | } | ||||||
1556 | |||||||
1557 | namespace { | ||||||
1558 | bool WasLazilyParsed(Scope* scope) { | ||||||
1559 | return scope->is_declaration_scope() && | ||||||
1560 | scope->AsDeclarationScope()->was_lazily_parsed(); | ||||||
1561 | } | ||||||
1562 | |||||||
1563 | } // namespace | ||||||
1564 | |||||||
1565 | template <typename FunctionType> | ||||||
1566 | void 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 | |||||||
1585 | bool Scope::IsConstructorScope() const { | ||||||
1586 | return is_declaration_scope() && | ||||||
1587 | IsClassConstructor(AsDeclarationScope()->function_kind()); | ||||||
1588 | } | ||||||
1589 | |||||||
1590 | bool 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 | |||||||
1599 | void 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 | |||||||
1635 | void 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 | |||||||
1671 | Handle<StringSet> DeclarationScope::CollectNonLocals( | ||||||
1672 | Isolate* isolate, Handle<StringSet> non_locals) { | ||||||
1673 | Scope::CollectNonLocals(this, isolate, &non_locals); | ||||||
1674 | return non_locals; | ||||||
1675 | } | ||||||
1676 | |||||||
1677 | void 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 | |||||||
1718 | bool 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 | |||||||
1730 | void 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 | |||||||
1739 | void DeclarationScope::SavePreparseDataForDeclarationScope(Parser* parser) { | ||||||
1740 | if (preparse_data_builder_ == nullptr) return; | ||||||
1741 | preparse_data_builder_->SaveScopeAllocationData(this, parser); | ||||||
1742 | } | ||||||
1743 | |||||||
1744 | void 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 | |||||||
1779 | void 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 | ||||||
1791 | namespace { | ||||||
1792 | |||||||
1793 | const 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 | |||||||
1813 | void Indent(int n, const char* str) { PrintF("%*s%s", n, "", str); } | ||||||
1814 | |||||||
1815 | void PrintName(const AstRawString* name) { | ||||||
1816 | PrintF("%.*s", name->length(), name->raw_data()); | ||||||
1817 | } | ||||||
1818 | |||||||
1819 | void 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 | |||||||
1844 | void 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 | |||||||
1872 | void 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 | |||||||
1892 | void 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 | |||||||
1906 | void 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 | |||||||
2035 | void 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 | |||||||
2046 | void 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 | |||||||
2059 | Variable* 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 | ||||||
2072 | template <Scope::ScopeLookupMode mode> | ||||||
2073 | Variable* 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 | |||||||
2181 | template Variable* Scope::Lookup<Scope::kParsedScope>( | ||||||
2182 | VariableProxy* proxy, Scope* scope, Scope* outer_scope_end, | ||||||
2183 | Scope* cache_scope, bool force_context_allocation); | ||||||
2184 | template Variable* Scope::Lookup<Scope::kDeserializedScope>( | ||||||
2185 | VariableProxy* proxy, Scope* scope, Scope* outer_scope_end, | ||||||
2186 | Scope* cache_scope, bool force_context_allocation); | ||||||
2187 | |||||||
2188 | Variable* 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 | |||||||
2228 | Variable* 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 | |||||||
2281 | void 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 | |||||||
2288 | namespace { | ||||||
2289 | |||||||
2290 | void SetNeedsHoleCheck(Variable* var, VariableProxy* proxy) { | ||||||
2291 | proxy->set_needs_hole_check(); | ||||||
2292 | var->ForceHoleInitialization(); | ||||||
2293 | } | ||||||
2294 | |||||||
2295 | void 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 | |||||||
2348 | void Scope::ResolveTo(VariableProxy* proxy, Variable* var) { | ||||||
2349 | DCHECK_NOT_NULL(var)((void) 0); | ||||||
2350 | UpdateNeedsHoleCheck(var, proxy, this); | ||||||
2351 | proxy->BindTo(var); | ||||||
2352 | } | ||||||
2353 | |||||||
2354 | void 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 | |||||||
2370 | bool 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 | |||||||
2397 | bool 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 | |||||||
2413 | bool 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 | |||||||
2432 | void 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 | |||||||
2441 | void Scope::AllocateHeapSlot(Variable* var) { | ||||||
2442 | var->AllocateTo(VariableLocation::CONTEXT, num_heap_slots_++); | ||||||
2443 | } | ||||||
2444 | |||||||
2445 | void 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 | |||||||
2483 | void 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 | |||||||
2497 | void 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 | |||||||
2504 | void 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 | |||||||
2517 | void 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 | |||||||
2542 | void 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 | |||||||
2564 | void 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 | |||||||
2578 | void 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 | |||||||
2625 | template <typename IsolateT> | ||||||
2626 | void 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 | |||||||
2647 | template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) void Scope:: | ||||||
2648 | AllocateScopeInfosRecursively<Isolate>(Isolate* isolate, | ||||||
2649 | MaybeHandle<ScopeInfo> outer_scope); | ||||||
2650 | template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) void Scope:: | ||||||
2651 | AllocateScopeInfosRecursively<LocalIsolate>( | ||||||
2652 | LocalIsolate* isolate, MaybeHandle<ScopeInfo> outer_scope); | ||||||
2653 | |||||||
2654 | void 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 | |||||||
2683 | void 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 | ||||||
2696 | template <typename IsolateT> | ||||||
2697 | void 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 | |||||||
2730 | template V8_EXPORT_PRIVATE void DeclarationScope::AllocateScopeInfos( | ||||||
2731 | ParseInfo* info, Isolate* isolate); | ||||||
2732 | template V8_EXPORT_PRIVATE void DeclarationScope::AllocateScopeInfos( | ||||||
2733 | ParseInfo* info, LocalIsolate* isolate); | ||||||
2734 | |||||||
2735 | int 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 | |||||||
2745 | VariableProxy* 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 | |||||||
2787 | bool 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 | |||||||
2798 | void 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 | |||||||
2836 | Variable* 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 | |||||||
2858 | Variable* 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 | |||||||
2866 | UnresolvedList::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 | |||||||
2874 | void 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 | |||||||
2890 | void 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 | |||||||
2920 | Variable* 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 | |||||||
2945 | Variable* 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 | |||||||
2964 | bool 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 | |||||||
2993 | VariableProxy* 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 | |||||||
3055 | Variable* 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 | |||||||
3073 | Variable* 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 | |||||||
3088 | PrivateNameScopeIterator::PrivateNameScopeIterator(Scope* start) | ||||||
3089 | : start_scope_(start), current_scope_(start) { | ||||||
3090 | if (!start->is_class_scope() || start->AsClassScope()->IsParsingHeritage()) { | ||||||
3091 | Next(); | ||||||
3092 | } | ||||||
3093 | } | ||||||
3094 | |||||||
3095 | void 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 | |||||||
3113 | void 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 |