Line data Source code
1 : // Copyright 2015 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/debug/debug-scopes.h"
6 :
7 : #include <memory>
8 :
9 : #include "src/ast/ast.h"
10 : #include "src/ast/scopes.h"
11 : #include "src/debug/debug.h"
12 : #include "src/frames-inl.h"
13 : #include "src/globals.h"
14 : #include "src/isolate-inl.h"
15 : #include "src/objects/js-generator-inl.h"
16 : #include "src/objects/module.h"
17 : #include "src/ostreams.h"
18 : #include "src/parsing/parse-info.h"
19 : #include "src/parsing/parsing.h"
20 : #include "src/parsing/rewriter.h"
21 :
22 : namespace v8 {
23 : namespace internal {
24 :
25 159517 : ScopeIterator::ScopeIterator(Isolate* isolate, FrameInspector* frame_inspector,
26 : ScopeIterator::Option option)
27 : : isolate_(isolate),
28 : frame_inspector_(frame_inspector),
29 : function_(frame_inspector_->GetFunction()),
30 638068 : script_(frame_inspector_->GetScript()) {
31 319034 : if (!frame_inspector->GetContext()->IsContext()) {
32 : // Optimized frame, context or function cannot be materialized. Give up.
33 : return;
34 : }
35 159426 : context_ = Handle<Context>::cast(frame_inspector->GetContext());
36 :
37 : // We should not instantiate a ScopeIterator for wasm frames.
38 : DCHECK_NE(Script::TYPE_WASM, frame_inspector->GetScript()->type());
39 :
40 159426 : TryParseAndRetrieveScopes(option);
41 : }
42 :
43 160967 : ScopeIterator::~ScopeIterator() { delete info_; }
44 :
45 372790 : Handle<Object> ScopeIterator::GetFunctionDebugName() const {
46 372790 : if (!function_.is_null()) return JSFunction::GetDebugName(function_);
47 :
48 471574 : if (!context_->IsNativeContext()) {
49 : DisallowHeapAllocation no_gc;
50 18676 : ScopeInfo closure_info = context_->closure_context()->scope_info();
51 18676 : Handle<String> debug_name(closure_info->FunctionDebugName(), isolate_);
52 18676 : if (debug_name->length() > 0) return debug_name;
53 : }
54 454512 : return isolate_->factory()->undefined_value();
55 : }
56 :
57 60 : ScopeIterator::ScopeIterator(Isolate* isolate, Handle<JSFunction> function)
58 120 : : isolate_(isolate), context_(function->context(), isolate) {
59 60 : if (!function->shared()->IsSubjectToDebugging()) {
60 5 : context_ = Handle<Context>();
61 5 : return;
62 : }
63 110 : script_ = handle(Script::cast(function->shared()->script()), isolate);
64 55 : UnwrapEvaluationContext();
65 : }
66 :
67 1390 : ScopeIterator::ScopeIterator(Isolate* isolate,
68 : Handle<JSGeneratorObject> generator)
69 : : isolate_(isolate),
70 : generator_(generator),
71 : function_(generator->function(), isolate),
72 : context_(generator->context(), isolate),
73 5560 : script_(Script::cast(function_->shared()->script()), isolate) {
74 1390 : CHECK(function_->shared()->IsSubjectToDebugging());
75 1390 : TryParseAndRetrieveScopes(DEFAULT);
76 1390 : }
77 :
78 10903 : void ScopeIterator::Restart() {
79 : DCHECK_NOT_NULL(frame_inspector_);
80 10903 : function_ = frame_inspector_->GetFunction();
81 10903 : context_ = Handle<Context>::cast(frame_inspector_->GetContext());
82 10903 : current_scope_ = start_scope_;
83 : DCHECK_NOT_NULL(current_scope_);
84 10903 : UnwrapEvaluationContext();
85 10903 : }
86 :
87 160816 : void ScopeIterator::TryParseAndRetrieveScopes(ScopeIterator::Option option) {
88 : // Catch the case when the debugger stops in an internal function.
89 160816 : Handle<SharedFunctionInfo> shared_info(function_->shared(), isolate_);
90 482448 : Handle<ScopeInfo> scope_info(shared_info->scope_info(), isolate_);
91 482448 : if (shared_info->script()->IsUndefined(isolate_)) {
92 0 : current_scope_ = closure_scope_ = nullptr;
93 0 : context_ = handle(function_->context(), isolate_);
94 0 : function_ = Handle<JSFunction>();
95 0 : return;
96 : }
97 :
98 : // Class fields initializer functions don't have any scope
99 : // information. We short circuit the parsing of the class literal
100 : // and return an empty context here.
101 160816 : if (IsClassMembersInitializerFunction(shared_info->kind())) {
102 20 : current_scope_ = closure_scope_ = nullptr;
103 20 : context_ = Handle<Context>();
104 20 : function_ = Handle<JSFunction>();
105 20 : return;
106 : }
107 :
108 : DCHECK_NE(IGNORE_NESTED_SCOPES, option);
109 : bool ignore_nested_scopes = false;
110 160796 : if (shared_info->HasBreakInfo() && frame_inspector_ != nullptr) {
111 : // The source position at return is always the end of the function,
112 : // which is not consistent with the current scope chain. Therefore all
113 : // nested with, catch and block contexts are skipped, and we can only
114 : // inspect the function scope.
115 : // This can only happen if we set a break point inside right before the
116 : // return, which requires a debug info to be available.
117 90815 : Handle<DebugInfo> debug_info(shared_info->GetDebugInfo(), isolate_);
118 :
119 : // Find the break point where execution has stopped.
120 90815 : BreakLocation location = BreakLocation::FromFrame(debug_info, GetFrame());
121 :
122 : ignore_nested_scopes = location.IsReturn();
123 : }
124 :
125 : // Reparse the code and analyze the scopes.
126 : // Check whether we are in global, eval or function code.
127 160796 : if (scope_info->scope_type() == FUNCTION_SCOPE) {
128 : // Inner function.
129 101547 : info_ = new ParseInfo(isolate_, shared_info);
130 : } else {
131 : // Global or eval code.
132 177747 : Handle<Script> script(Script::cast(shared_info->script()), isolate_);
133 59249 : info_ = new ParseInfo(isolate_, script);
134 59249 : if (scope_info->scope_type() == EVAL_SCOPE) {
135 5574 : info_->set_eval();
136 5574 : if (!context_->IsNativeContext()) {
137 13024 : info_->set_outer_scope_info(handle(context_->scope_info(), isolate_));
138 : }
139 : // Language mode may be inherited from the eval caller.
140 : // Retrieve it from shared function info.
141 5574 : info_->set_language_mode(shared_info->language_mode());
142 53675 : } else if (scope_info->scope_type() == MODULE_SCOPE) {
143 : DCHECK(info_->is_module());
144 : } else {
145 : DCHECK_EQ(SCRIPT_SCOPE, scope_info->scope_type());
146 : }
147 : }
148 :
149 317320 : if (parsing::ParseAny(info_, shared_info, isolate_) &&
150 156524 : Rewriter::Rewrite(info_)) {
151 313048 : info_->ast_value_factory()->Internalize(isolate_);
152 156524 : closure_scope_ = info_->literal()->scope();
153 :
154 156524 : if (option == COLLECT_NON_LOCALS) {
155 : DCHECK(non_locals_.is_null());
156 12560 : non_locals_ = info_->literal()->scope()->CollectNonLocals(
157 25120 : isolate_, info_, StringSet::New(isolate_));
158 26446 : if (!closure_scope_->has_this_declaration() &&
159 1326 : closure_scope_->HasThisReference()) {
160 : non_locals_ = StringSet::Add(isolate_, non_locals_,
161 632 : isolate_->factory()->this_string());
162 : }
163 : }
164 :
165 156524 : CHECK(DeclarationScope::Analyze(info_));
166 156524 : if (ignore_nested_scopes) {
167 6202 : current_scope_ = closure_scope_;
168 6202 : start_scope_ = current_scope_;
169 6202 : if (closure_scope_->NeedsContext()) {
170 261 : context_ = handle(context_->closure_context(), isolate_);
171 : }
172 : } else {
173 150322 : RetrieveScopeChain(closure_scope_);
174 : }
175 156524 : UnwrapEvaluationContext();
176 : } else {
177 : // A failed reparse indicates that the preparser has diverged from the
178 : // parser or that the preparse data given to the initial parse has been
179 : // faulty. We fail in debug mode but in release mode we only provide the
180 : // information we get from the context chain but nothing about
181 : // completely stack allocated scopes or stack allocated locals.
182 : // Or it could be due to stack overflow.
183 : // Silently fail by presenting an empty context chain.
184 8544 : CHECK(isolate_->has_pending_exception());
185 : isolate_->clear_pending_exception();
186 4272 : context_ = Handle<Context>();
187 : }
188 : }
189 :
190 443758 : void ScopeIterator::UnwrapEvaluationContext() {
191 887516 : if (!context_->IsDebugEvaluateContext()) return;
192 0 : Context current = *context_;
193 0 : do {
194 : Object wrapped = current->get(Context::WRAPPED_CONTEXT_INDEX);
195 0 : if (wrapped->IsContext()) {
196 0 : current = Context::cast(wrapped);
197 : } else {
198 : DCHECK(!current->previous().is_null());
199 0 : current = current->previous();
200 : }
201 : } while (current->IsDebugEvaluateContext());
202 0 : context_ = handle(current, isolate_);
203 : }
204 :
205 945 : Handle<JSObject> ScopeIterator::MaterializeScopeDetails() {
206 : // Calculate the size of the result.
207 : Handle<FixedArray> details =
208 945 : isolate_->factory()->NewFixedArray(kScopeDetailsSize);
209 : // Fill in scope details.
210 945 : details->set(kScopeDetailsTypeIndex, Smi::FromInt(Type()));
211 945 : Handle<JSObject> scope_object = ScopeObject(Mode::ALL);
212 1890 : details->set(kScopeDetailsObjectIndex, *scope_object);
213 945 : if (Type() == ScopeTypeGlobal || Type() == ScopeTypeScript) {
214 315 : return isolate_->factory()->NewJSArrayWithElements(details);
215 630 : } else if (HasContext()) {
216 324 : Handle<Object> closure_name = GetFunctionDebugName();
217 324 : details->set(kScopeDetailsNameIndex, *closure_name);
218 324 : details->set(kScopeDetailsStartPositionIndex,
219 : Smi::FromInt(start_position()));
220 324 : details->set(kScopeDetailsEndPositionIndex, Smi::FromInt(end_position()));
221 324 : if (InInnerScope()) {
222 612 : details->set(kScopeDetailsFunctionIndex, *function_);
223 : }
224 : }
225 630 : return isolate_->factory()->NewJSArrayWithElements(details);
226 : }
227 :
228 372316 : bool ScopeIterator::HasPositionInfo() {
229 843634 : return InInnerScope() || !context_->IsNativeContext();
230 : }
231 :
232 155624 : int ScopeIterator::start_position() {
233 155624 : if (InInnerScope()) return current_scope_->start_position();
234 37322 : if (context_->IsNativeContext()) return 0;
235 18661 : return context_->closure_context()->scope_info()->StartPosition();
236 : }
237 :
238 155624 : int ScopeIterator::end_position() {
239 155624 : if (InInnerScope()) return current_scope_->end_position();
240 37322 : if (context_->IsNativeContext()) return 0;
241 18661 : return context_->closure_context()->scope_info()->EndPosition();
242 : }
243 :
244 310405 : bool ScopeIterator::DeclaresLocals(Mode mode) const {
245 310405 : ScopeType type = Type();
246 :
247 310405 : if (type == ScopeTypeWith) return mode == Mode::ALL;
248 307857 : if (type == ScopeTypeGlobal) return mode == Mode::ALL;
249 :
250 165439 : bool declares_local = false;
251 : auto visitor = [&](Handle<String> name, Handle<Object> value) {
252 144641 : declares_local = true;
253 : return true;
254 : };
255 330878 : VisitScope(visitor, mode);
256 165439 : return declares_local;
257 : }
258 :
259 12424 : bool ScopeIterator::HasContext() const {
260 118707 : return !InInnerScope() || current_scope_->NeedsContext();
261 : }
262 :
263 418982 : void ScopeIterator::Next() {
264 : DCHECK(!Done());
265 :
266 418982 : ScopeType scope_type = Type();
267 :
268 418982 : if (scope_type == ScopeTypeGlobal) {
269 : // The global scope is always the last in the chain.
270 : DCHECK(context_->IsNativeContext());
271 142706 : context_ = Handle<Context>();
272 : DCHECK(Done());
273 142706 : return;
274 : }
275 :
276 : bool inner = InInnerScope();
277 276276 : if (current_scope_ == closure_scope_) function_ = Handle<JSFunction>();
278 :
279 276276 : if (scope_type == ScopeTypeScript) {
280 : DCHECK_IMPLIES(InInnerScope(), current_scope_->is_script_scope());
281 142868 : seen_script_scope_ = true;
282 142868 : if (context_->IsScriptContext()) {
283 26790 : context_ = handle(context_->previous(), isolate_);
284 : }
285 133408 : } else if (!inner) {
286 : DCHECK(!context_->IsNativeContext());
287 40974 : context_ = handle(context_->previous(), isolate_);
288 : } else {
289 : DCHECK_NOT_NULL(current_scope_);
290 120954 : do {
291 120954 : if (current_scope_->NeedsContext()) {
292 : DCHECK(!context_->previous().is_null());
293 46485 : context_ = handle(context_->previous(), isolate_);
294 : }
295 : DCHECK_IMPLIES(InInnerScope(), current_scope_->outer_scope() != nullptr);
296 120954 : current_scope_ = current_scope_->outer_scope();
297 : // Repeat to skip hidden scopes.
298 : } while (current_scope_->is_hidden());
299 : }
300 :
301 276276 : UnwrapEvaluationContext();
302 : }
303 :
304 :
305 : // Return the type of the current scope.
306 2398433 : ScopeIterator::ScopeType ScopeIterator::Type() const {
307 : DCHECK(!Done());
308 2398433 : if (InInnerScope()) {
309 991399 : switch (current_scope_->scope_type()) {
310 : case FUNCTION_SCOPE:
311 : DCHECK_IMPLIES(current_scope_->NeedsContext(),
312 : context_->IsFunctionContext() ||
313 : context_->IsDebugEvaluateContext());
314 : return ScopeTypeLocal;
315 : case MODULE_SCOPE:
316 : DCHECK_IMPLIES(current_scope_->NeedsContext(),
317 : context_->IsModuleContext());
318 5562 : return ScopeTypeModule;
319 : case SCRIPT_SCOPE:
320 : DCHECK_IMPLIES(
321 : current_scope_->NeedsContext(),
322 : context_->IsScriptContext() || context_->IsNativeContext());
323 353438 : return ScopeTypeScript;
324 : case WITH_SCOPE:
325 : DCHECK_IMPLIES(current_scope_->NeedsContext(),
326 : context_->IsWithContext());
327 11265 : return ScopeTypeWith;
328 : case CATCH_SCOPE:
329 : DCHECK(context_->IsCatchContext());
330 6169 : return ScopeTypeCatch;
331 : case BLOCK_SCOPE:
332 : DCHECK_IMPLIES(current_scope_->NeedsContext(),
333 : context_->IsBlockContext());
334 19303 : return ScopeTypeBlock;
335 : case EVAL_SCOPE:
336 : DCHECK_IMPLIES(current_scope_->NeedsContext(),
337 : context_->IsEvalContext());
338 22737 : return ScopeTypeEval;
339 : }
340 0 : UNREACHABLE();
341 : }
342 1407034 : if (context_->IsNativeContext()) {
343 : DCHECK(context_->global_object()->IsJSGlobalObject());
344 : // If we are at the native context and have not yet seen script scope,
345 : // fake it.
346 1268434 : return seen_script_scope_ ? ScopeTypeGlobal : ScopeTypeScript;
347 : }
348 406280 : if (context_->IsFunctionContext() || context_->IsEvalContext() ||
349 200435 : context_->IsDebugEvaluateContext()) {
350 : return ScopeTypeClosure;
351 : }
352 61835 : if (context_->IsCatchContext()) {
353 : return ScopeTypeCatch;
354 : }
355 59296 : if (context_->IsBlockContext()) {
356 : return ScopeTypeBlock;
357 : }
358 56803 : if (context_->IsModuleContext()) {
359 : return ScopeTypeModule;
360 : }
361 51487 : if (context_->IsScriptContext()) {
362 : return ScopeTypeScript;
363 : }
364 : DCHECK(context_->IsWithContext());
365 2345 : return ScopeTypeWith;
366 : }
367 :
368 385503 : Handle<JSObject> ScopeIterator::ScopeObject(Mode mode) {
369 : DCHECK(!Done());
370 :
371 385503 : ScopeType type = Type();
372 385503 : if (type == ScopeTypeGlobal) {
373 : DCHECK_EQ(Mode::ALL, mode);
374 427698 : return handle(context_->global_proxy(), isolate_);
375 : }
376 242937 : if (type == ScopeTypeWith) {
377 : DCHECK_EQ(Mode::ALL, mode);
378 2518 : return WithContextExtension();
379 : }
380 :
381 240419 : Handle<JSObject> scope = isolate_->factory()->NewJSObjectWithNullProto();
382 : auto visitor = [=](Handle<String> name, Handle<Object> value) {
383 4616350 : JSObject::AddProperty(isolate_, scope, name, value, NONE);
384 : return false;
385 240419 : };
386 :
387 480838 : VisitScope(visitor, mode);
388 240419 : return scope;
389 : }
390 :
391 405858 : void ScopeIterator::VisitScope(const Visitor& visitor, Mode mode) const {
392 405858 : switch (Type()) {
393 : case ScopeTypeLocal:
394 : case ScopeTypeClosure:
395 : case ScopeTypeCatch:
396 : case ScopeTypeBlock:
397 : case ScopeTypeEval:
398 131349 : return VisitLocalScope(visitor, mode);
399 : case ScopeTypeModule:
400 2921 : if (InInnerScope()) {
401 1410 : return VisitLocalScope(visitor, mode);
402 : }
403 : DCHECK_EQ(Mode::ALL, mode);
404 1511 : return VisitModuleScope(visitor);
405 : case ScopeTypeScript:
406 : DCHECK_EQ(Mode::ALL, mode);
407 271588 : return VisitScriptScope(visitor);
408 : case ScopeTypeWith:
409 : case ScopeTypeGlobal:
410 0 : UNREACHABLE();
411 : }
412 : }
413 :
414 84138 : bool ScopeIterator::SetVariableValue(Handle<String> name,
415 : Handle<Object> value) {
416 : DCHECK(!Done());
417 84138 : name = isolate_->factory()->InternalizeString(name);
418 84138 : switch (Type()) {
419 : case ScopeTypeGlobal:
420 : case ScopeTypeWith:
421 : break;
422 :
423 : case ScopeTypeEval:
424 : case ScopeTypeBlock:
425 : case ScopeTypeCatch:
426 : case ScopeTypeModule:
427 777 : if (InInnerScope()) return SetLocalVariableValue(name, value);
428 25 : if (Type() == ScopeTypeModule && SetModuleVariableValue(name, value)) {
429 : return true;
430 : }
431 20 : return SetContextVariableValue(name, value);
432 :
433 : case ScopeTypeLocal:
434 : case ScopeTypeClosure:
435 83311 : if (InInnerScope()) {
436 : DCHECK_EQ(ScopeTypeLocal, Type());
437 83261 : if (SetLocalVariableValue(name, value)) return true;
438 : // There may not be an associated context since we're InInnerScope().
439 37183 : if (!current_scope_->NeedsContext()) return false;
440 : } else {
441 : DCHECK_EQ(ScopeTypeClosure, Type());
442 50 : if (SetContextVariableValue(name, value)) return true;
443 : }
444 : // The above functions only set variables statically declared in the
445 : // function. There may be eval-introduced variables. Check them in
446 : // SetContextExtensionValue.
447 930 : return SetContextExtensionValue(name, value);
448 :
449 : case ScopeTypeScript:
450 14 : return SetScriptVariableValue(name, value);
451 : }
452 : return false;
453 : }
454 :
455 12064 : Handle<StringSet> ScopeIterator::GetNonLocals() { return non_locals_; }
456 :
457 : #ifdef DEBUG
458 : // Debug print of the content of the current scope.
459 : void ScopeIterator::DebugPrint() {
460 : StdoutStream os;
461 : DCHECK(!Done());
462 : switch (Type()) {
463 : case ScopeIterator::ScopeTypeGlobal:
464 : os << "Global:\n";
465 : context_->Print(os);
466 : break;
467 :
468 : case ScopeIterator::ScopeTypeLocal: {
469 : os << "Local:\n";
470 : if (current_scope_->NeedsContext()) {
471 : context_->Print(os);
472 : if (context_->has_extension()) {
473 : Handle<HeapObject> extension(context_->extension(), isolate_);
474 : DCHECK(extension->IsJSContextExtensionObject());
475 : extension->Print(os);
476 : }
477 : }
478 : break;
479 : }
480 :
481 : case ScopeIterator::ScopeTypeWith:
482 : os << "With:\n";
483 : context_->extension()->Print(os);
484 : break;
485 :
486 : case ScopeIterator::ScopeTypeCatch:
487 : os << "Catch:\n";
488 : context_->extension()->Print(os);
489 : context_->get(Context::THROWN_OBJECT_INDEX)->Print(os);
490 : break;
491 :
492 : case ScopeIterator::ScopeTypeClosure:
493 : os << "Closure:\n";
494 : context_->Print(os);
495 : if (context_->has_extension()) {
496 : Handle<HeapObject> extension(context_->extension(), isolate_);
497 : DCHECK(extension->IsJSContextExtensionObject());
498 : extension->Print(os);
499 : }
500 : break;
501 :
502 : case ScopeIterator::ScopeTypeScript:
503 : os << "Script:\n";
504 : context_->global_object()
505 : ->native_context()
506 : ->script_context_table()
507 : ->Print(os);
508 : break;
509 :
510 : default:
511 : UNREACHABLE();
512 : }
513 : PrintF("\n");
514 : }
515 : #endif
516 :
517 150322 : int ScopeIterator::GetSourcePosition() {
518 150322 : if (frame_inspector_) {
519 148932 : return frame_inspector_->GetSourcePosition();
520 : } else {
521 : DCHECK(!generator_.is_null());
522 2780 : SharedFunctionInfo::EnsureSourcePositionsAvailable(
523 1390 : isolate_, handle(generator_->function()->shared(), isolate_));
524 1390 : return generator_->source_position();
525 : }
526 : }
527 :
528 150322 : void ScopeIterator::RetrieveScopeChain(DeclarationScope* scope) {
529 : DCHECK_NOT_NULL(scope);
530 :
531 150322 : const int position = GetSourcePosition();
532 :
533 : Scope* parent = nullptr;
534 : Scope* current = scope;
535 308488 : while (parent != current) {
536 : parent = current;
537 699482 : for (Scope* inner_scope = current->inner_scope(); inner_scope != nullptr;
538 : inner_scope = inner_scope->sibling()) {
539 : int beg_pos = inner_scope->start_position();
540 : int end_pos = inner_scope->end_position();
541 : DCHECK((beg_pos >= 0 && end_pos >= 0) || inner_scope->is_hidden());
542 278530 : if (beg_pos <= position && position < end_pos) {
543 : // Don't walk into inner functions.
544 7872 : if (!inner_scope->is_function_scope()) {
545 : current = inner_scope;
546 : }
547 : break;
548 : }
549 : }
550 : }
551 :
552 150322 : start_scope_ = current;
553 150322 : current_scope_ = current;
554 150322 : }
555 :
556 271588 : void ScopeIterator::VisitScriptScope(const Visitor& visitor) const {
557 814764 : Handle<JSGlobalObject> global(context_->global_object(), isolate_);
558 : Handle<ScriptContextTable> script_contexts(
559 814764 : global->native_context()->script_context_table(), isolate_);
560 :
561 : // Skip the first script since that just declares 'this'.
562 548764 : for (int context_index = 1; context_index < script_contexts->used();
563 : context_index++) {
564 : Handle<Context> context = ScriptContextTable::GetContext(
565 267596 : isolate_, script_contexts, context_index);
566 802788 : Handle<ScopeInfo> scope_info(context->scope_info(), isolate_);
567 396604 : if (VisitContextLocals(visitor, scope_info, context)) return;
568 : }
569 : }
570 :
571 1511 : void ScopeIterator::VisitModuleScope(const Visitor& visitor) const {
572 : DCHECK(context_->IsModuleContext());
573 :
574 4533 : Handle<ScopeInfo> scope_info(context_->scope_info(), isolate_);
575 2269 : if (VisitContextLocals(visitor, scope_info, context_)) return;
576 :
577 753 : int count_index = scope_info->ModuleVariableCountIndex();
578 : int module_variable_count = Smi::cast(scope_info->get(count_index))->value();
579 :
580 2259 : Handle<Module> module(context_->module(), isolate_);
581 :
582 3983 : for (int i = 0; i < module_variable_count; ++i) {
583 : int index;
584 : Handle<String> name;
585 : {
586 1615 : String raw_name;
587 1615 : scope_info->ModuleVariable(i, &raw_name, &index);
588 1625 : if (ScopeInfo::VariableIsSynthetic(raw_name)) continue;
589 1605 : name = handle(raw_name, isolate_);
590 : }
591 1605 : Handle<Object> value = Module::LoadVariable(isolate_, module, index);
592 :
593 : // Reflect variables under TDZ as undeclared in scope object.
594 3210 : if (value->IsTheHole(isolate_)) continue;
595 65 : if (visitor(name, value)) return;
596 : }
597 : }
598 :
599 292192 : bool ScopeIterator::VisitContextLocals(const Visitor& visitor,
600 : Handle<ScopeInfo> scope_info,
601 : Handle<Context> context) const {
602 : // Fill all context locals to the context extension.
603 1383356 : for (int i = 0; i < scope_info->ContextLocalCount(); ++i) {
604 2058105 : Handle<String> name(scope_info->ContextLocalName(i), isolate_);
605 686035 : if (ScopeInfo::VariableIsSynthetic(*name)) continue;
606 : int context_index = Context::MIN_CONTEXT_SLOTS + i;
607 668696 : Handle<Object> value(context->get(context_index), isolate_);
608 : // Reflect variables under TDZ as undefined in scope object.
609 1337392 : if (value->IsTheHole(isolate_)) continue;
610 666438 : if (visitor(name, value)) return true;
611 : }
612 : return false;
613 : }
614 :
615 109674 : bool ScopeIterator::VisitLocals(const Visitor& visitor, Mode mode) const {
616 134587 : if (mode == Mode::STACK && current_scope_->is_declaration_scope() &&
617 12205 : current_scope_->AsDeclarationScope()->has_this_declaration()) {
618 11462 : Handle<Object> receiver = frame_inspector_ == nullptr
619 0 : ? handle(generator_->receiver(), isolate_)
620 11462 : : frame_inspector_->GetReceiver();
621 34386 : if (receiver->IsOptimizedOut(isolate_) || receiver->IsTheHole(isolate_)) {
622 : receiver = isolate_->factory()->undefined_value();
623 : }
624 11462 : if (visitor(isolate_->factory()->this_string(), receiver)) return true;
625 : }
626 :
627 4492079 : for (Variable* var : *current_scope_->locals()) {
628 : DCHECK(!var->is_this());
629 4277137 : if (ScopeInfo::VariableIsSynthetic(*var->name())) continue;
630 :
631 : int index = var->index();
632 : Handle<Object> value;
633 4160346 : switch (var->location()) {
634 : case VariableLocation::LOOKUP:
635 0 : UNREACHABLE();
636 : break;
637 :
638 : case VariableLocation::UNALLOCATED:
639 : continue;
640 :
641 : case VariableLocation::PARAMETER: {
642 25502 : if (frame_inspector_ == nullptr) {
643 : // Get the variable from the suspended generator.
644 : DCHECK(!generator_.is_null());
645 : FixedArray parameters_and_registers =
646 : generator_->parameters_and_registers();
647 : DCHECK_LT(index, parameters_and_registers->length());
648 127 : value = handle(parameters_and_registers->get(index), isolate_);
649 : } else {
650 25375 : value = frame_inspector_->GetParameter(index);
651 :
652 50750 : if (value->IsOptimizedOut(isolate_)) {
653 : value = isolate_->factory()->undefined_value();
654 : }
655 : }
656 : break;
657 : }
658 :
659 : case VariableLocation::LOCAL:
660 3996891 : if (frame_inspector_ == nullptr) {
661 : // Get the variable from the suspended generator.
662 : DCHECK(!generator_.is_null());
663 : FixedArray parameters_and_registers =
664 : generator_->parameters_and_registers();
665 : int parameter_count =
666 352 : function_->shared()->scope_info()->ParameterCount();
667 352 : index += parameter_count;
668 : DCHECK_LT(index, parameters_and_registers->length());
669 352 : value = handle(parameters_and_registers->get(index), isolate_);
670 704 : if (value->IsTheHole(isolate_)) {
671 : value = isolate_->factory()->undefined_value();
672 : }
673 : } else {
674 3996539 : value = frame_inspector_->GetExpression(index);
675 7993078 : if (value->IsOptimizedOut(isolate_)) {
676 : // We'll rematerialize this later.
677 2979 : if (current_scope_->is_declaration_scope() &&
678 961 : current_scope_->AsDeclarationScope()->arguments() == var) {
679 : continue;
680 : }
681 987 : value = isolate_->factory()->undefined_value();
682 3995530 : } else if (value->IsTheHole(isolate_)) {
683 : // Reflect variables under TDZ as undeclared in scope object.
684 : continue;
685 : }
686 : }
687 : break;
688 :
689 : case VariableLocation::CONTEXT:
690 49951 : if (mode == Mode::STACK) continue;
691 : DCHECK(var->IsContextSlot());
692 49083 : value = handle(context_->get(index), isolate_);
693 : // Reflect variables under TDZ as undeclared in scope object.
694 98166 : if (value->IsTheHole(isolate_)) continue;
695 : break;
696 :
697 : case VariableLocation::MODULE: {
698 2084 : if (mode == Mode::STACK) continue;
699 : // if (var->IsExport()) continue;
700 2169 : Handle<Module> module(context_->module(), isolate_);
701 723 : value = Module::LoadVariable(isolate_, module, var->index());
702 : // Reflect variables under TDZ as undeclared in scope object.
703 1446 : if (value->IsTheHole(isolate_)) continue;
704 240 : break;
705 : }
706 : }
707 :
708 4071168 : if (visitor(var->name(), value)) return true;
709 : }
710 : return false;
711 : }
712 :
713 : // Retrieve the with-context extension object. If the extension object is
714 : // a proxy, return an empty object.
715 2518 : Handle<JSObject> ScopeIterator::WithContextExtension() {
716 : DCHECK(context_->IsWithContext());
717 5036 : if (context_->extension_receiver()->IsJSProxy()) {
718 0 : return isolate_->factory()->NewJSObjectWithNullProto();
719 : }
720 7554 : return handle(JSObject::cast(context_->extension_receiver()), isolate_);
721 : }
722 :
723 : // Create a plain JSObject which materializes the block scope for the specified
724 : // block context.
725 132759 : void ScopeIterator::VisitLocalScope(const Visitor& visitor, Mode mode) const {
726 132759 : if (InInnerScope()) {
727 109674 : if (VisitLocals(visitor, mode)) return;
728 105496 : if (mode == Mode::STACK && Type() == ScopeTypeLocal) {
729 : // Hide |this| in arrow functions that may be embedded in other functions
730 : // but don't force |this| to be context-allocated. Otherwise we'd find the
731 : // wrong |this| value.
732 23869 : if (!closure_scope_->has_this_declaration() &&
733 619 : !closure_scope_->HasThisReference()) {
734 380 : if (visitor(isolate_->factory()->this_string(),
735 380 : isolate_->factory()->undefined_value()))
736 : return;
737 : }
738 : // Add |arguments| to the function scope even if it wasn't used.
739 : // Currently we don't yet support materializing the arguments object of
740 : // suspended generators. We'd need to read the arguments out from the
741 : // suspended generator rather than from an activation as
742 : // FunctionGetArguments does.
743 34875 : if (frame_inspector_ != nullptr && !closure_scope_->is_arrow_scope() &&
744 83 : (closure_scope_->arguments() == nullptr ||
745 83 : frame_inspector_->GetExpression(closure_scope_->arguments()->index())
746 83 : ->IsOptimizedOut(isolate_))) {
747 : JavaScriptFrame* frame = GetFrame();
748 : Handle<JSObject> arguments = Accessors::FunctionGetArguments(
749 10925 : frame, frame_inspector_->inlined_frame_index());
750 21850 : if (visitor(isolate_->factory()->arguments_string(), arguments)) return;
751 : }
752 : }
753 : } else {
754 : DCHECK_EQ(Mode::ALL, mode);
755 69255 : Handle<ScopeInfo> scope_info(context_->scope_info(), isolate_);
756 23085 : if (VisitContextLocals(visitor, scope_info, context_)) return;
757 : }
758 :
759 223547 : if (mode == Mode::ALL && HasContext()) {
760 : DCHECK(!context_->IsScriptContext());
761 : DCHECK(!context_->IsNativeContext());
762 : DCHECK(!context_->IsWithContext());
763 23365 : if (!context_->scope_info()->CallsSloppyEval()) return;
764 15728 : if (context_->extension_object().is_null()) return;
765 1089 : Handle<JSObject> extension(context_->extension_object(), isolate_);
766 : Handle<FixedArray> keys =
767 726 : KeyAccumulator::GetKeys(extension, KeyCollectionMode::kOwnOnly,
768 363 : ENUMERABLE_STRINGS)
769 : .ToHandleChecked();
770 :
771 1449 : for (int i = 0; i < keys->length(); i++) {
772 : // Names of variables introduced by eval are strings.
773 : DCHECK(keys->get(i)->IsString());
774 553 : Handle<String> key(String::cast(keys->get(i)), isolate_);
775 553 : Handle<Object> value = JSReceiver::GetDataProperty(extension, key);
776 563 : if (visitor(key, value)) return;
777 : }
778 : }
779 : }
780 :
781 84013 : bool ScopeIterator::SetLocalVariableValue(Handle<String> variable_name,
782 : Handle<Object> new_value) {
783 : // TODO(verwaest): Walk parameters backwards, not forwards.
784 : // TODO(verwaest): Use VariableMap rather than locals() list for lookup.
785 2455045 : for (Variable* var : *current_scope_->locals()) {
786 2360553 : if (String::Equals(isolate_, var->name(), variable_name)) {
787 : int index = var->index();
788 73534 : switch (var->location()) {
789 : case VariableLocation::LOOKUP:
790 : case VariableLocation::UNALLOCATED:
791 : // Drop assignments to unallocated locals.
792 : DCHECK(var->is_this() ||
793 : *variable_name == ReadOnlyRoots(isolate_).arguments_string());
794 : return false;
795 :
796 : case VariableLocation::PARAMETER: {
797 12455 : if (var->is_this()) return false;
798 12455 : if (frame_inspector_ == nullptr) {
799 : // Set the variable in the suspended generator.
800 : DCHECK(!generator_.is_null());
801 : Handle<FixedArray> parameters_and_registers(
802 0 : generator_->parameters_and_registers(), isolate_);
803 : DCHECK_LT(index, parameters_and_registers->length());
804 0 : parameters_and_registers->set(index, *new_value);
805 : } else {
806 : JavaScriptFrame* frame = GetFrame();
807 24910 : if (frame->is_optimized()) return false;
808 :
809 2138 : frame->SetParameterValue(index, *new_value);
810 : }
811 : return true;
812 : }
813 :
814 : case VariableLocation::LOCAL:
815 51189 : if (frame_inspector_ == nullptr) {
816 : // Set the variable in the suspended generator.
817 : DCHECK(!generator_.is_null());
818 : int parameter_count =
819 27 : function_->shared()->scope_info()->ParameterCount();
820 27 : index += parameter_count;
821 : Handle<FixedArray> parameters_and_registers(
822 27 : generator_->parameters_and_registers(), isolate_);
823 : DCHECK_LT(index, parameters_and_registers->length());
824 27 : parameters_and_registers->set(index, *new_value);
825 : } else {
826 : // Set the variable on the stack.
827 : JavaScriptFrame* frame = GetFrame();
828 102324 : if (frame->is_optimized()) return false;
829 :
830 44337 : frame->SetExpression(index, *new_value);
831 : }
832 : return true;
833 :
834 : case VariableLocation::CONTEXT:
835 : DCHECK(var->IsContextSlot());
836 : context_->set(index, *new_value);
837 : return true;
838 :
839 : case VariableLocation::MODULE:
840 10 : if (!var->IsExport()) return false;
841 15 : Handle<Module> module(context_->module(), isolate_);
842 5 : Module::StoreVariable(module, var->index(), new_value);
843 5 : return true;
844 : }
845 0 : UNREACHABLE();
846 : }
847 : }
848 :
849 : return false;
850 : }
851 :
852 930 : bool ScopeIterator::SetContextExtensionValue(Handle<String> variable_name,
853 : Handle<Object> new_value) {
854 1860 : if (!context_->has_extension()) return false;
855 :
856 : DCHECK(context_->extension_object()->IsJSContextExtensionObject());
857 126 : Handle<JSObject> ext(context_->extension_object(), isolate_);
858 42 : LookupIterator it(isolate_, ext, variable_name, LookupIterator::OWN);
859 42 : Maybe<bool> maybe = JSReceiver::HasOwnProperty(ext, variable_name);
860 : DCHECK(maybe.IsJust());
861 42 : if (!maybe.FromJust()) return false;
862 :
863 20 : CHECK(Object::SetDataProperty(&it, new_value).ToChecked());
864 : return true;
865 : }
866 :
867 70 : bool ScopeIterator::SetContextVariableValue(Handle<String> variable_name,
868 : Handle<Object> new_value) {
869 : DisallowHeapAllocation no_gc;
870 : VariableMode mode;
871 : InitializationFlag flag;
872 : MaybeAssignedFlag maybe_assigned_flag;
873 : int slot_index =
874 140 : ScopeInfo::ContextSlotIndex(context_->scope_info(), *variable_name, &mode,
875 70 : &flag, &maybe_assigned_flag);
876 70 : if (slot_index < 0) return false;
877 :
878 : context_->set(slot_index, *new_value);
879 : return true;
880 : }
881 :
882 15 : bool ScopeIterator::SetModuleVariableValue(Handle<String> variable_name,
883 : Handle<Object> new_value) {
884 : DisallowHeapAllocation no_gc;
885 : int cell_index;
886 : VariableMode mode;
887 : InitializationFlag init_flag;
888 : MaybeAssignedFlag maybe_assigned_flag;
889 30 : cell_index = context_->scope_info()->ModuleIndex(
890 15 : *variable_name, &mode, &init_flag, &maybe_assigned_flag);
891 :
892 : // Setting imports is currently not supported.
893 15 : if (ModuleDescriptor::GetCellIndexKind(cell_index) !=
894 : ModuleDescriptor::kExport) {
895 : return false;
896 : }
897 :
898 15 : Handle<Module> module(context_->module(), isolate_);
899 5 : Module::StoreVariable(module, cell_index, new_value);
900 5 : return true;
901 : }
902 :
903 14 : bool ScopeIterator::SetScriptVariableValue(Handle<String> variable_name,
904 : Handle<Object> new_value) {
905 : Handle<ScriptContextTable> script_contexts(
906 42 : context_->global_object()->native_context()->script_context_table(),
907 28 : isolate_);
908 : ScriptContextTable::LookupResult lookup_result;
909 14 : if (ScriptContextTable::Lookup(isolate_, *script_contexts, *variable_name,
910 : &lookup_result)) {
911 : Handle<Context> script_context = ScriptContextTable::GetContext(
912 14 : isolate_, script_contexts, lookup_result.context_index);
913 14 : script_context->set(lookup_result.slot_index, *new_value);
914 : return true;
915 : }
916 :
917 : return false;
918 : }
919 :
920 : } // namespace internal
921 120216 : } // namespace v8
|