File: | out/../deps/v8/src/ast/scopes.cc |
Warning: | line 3098, column 18 Called C++ object pointer is null |
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) continue; | |||
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 == VariableMode::kVar && !is_declaration_scope()) { | |||
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 |