v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
debug-scopes.cc
Go to the documentation of this file.
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
6
7#include <memory>
8
9#include "src/ast/ast.h"
10#include "src/ast/scopes.h"
11#include "src/common/globals.h"
12#include "src/debug/debug.h"
18#include "src/parsing/parsing.h"
19#include "src/utils/ostreams.h"
20
21namespace v8 {
22namespace internal {
23
25 ReparseStrategy strategy)
26 : isolate_(isolate),
27 frame_inspector_(frame_inspector),
28 function_(frame_inspector_->GetFunction()),
29 script_(frame_inspector_->GetScript()),
30 locals_(StringSet::New(isolate)) {
31 if (!IsContext(*frame_inspector->GetContext())) {
32 // Optimized frame, context or function cannot be materialized. Give up.
33 return;
34 }
35 context_ = Cast<Context>(frame_inspector->GetContext());
36
37#if V8_ENABLE_WEBASSEMBLY
38 // We should not instantiate a ScopeIterator for wasm frames.
39 DCHECK_NE(Script::Type::kWasm, frame_inspector->GetScript()->type());
40#endif // V8_ENABLE_WEBASSEMBLY
41
43}
44
46
48 if (!function_.is_null()) return JSFunction::GetDebugName(function_);
49
50 if (!IsNativeContext(*context_)) {
52 Tagged<ScopeInfo> closure_info = context_->closure_context()->scope_info();
53 DirectHandle<String> debug_name(closure_info->FunctionDebugName(),
54 isolate_);
55 if (debug_name->length() > 0) return debug_name;
56 }
57 return isolate_->factory()->undefined_value();
58}
59
62 : isolate_(isolate),
63 context_(function->context(), isolate),
64 locals_(StringSet::New(isolate)) {
65 if (!function->shared()->IsSubjectToDebugging()) {
66 context_ = Handle<Context>();
67 return;
68 }
69 script_ = handle(Cast<Script>(function->shared()->script()), isolate);
71}
72
75 : isolate_(isolate),
76 generator_(generator),
77 function_(generator->function(), isolate),
78 context_(generator->context(), isolate),
79 script_(Cast<Script>(function_->shared()->script()), isolate),
80 locals_(StringSet::New(isolate)) {
81 CHECK(function_->shared()->IsSubjectToDebugging());
83}
84
95
96namespace {
97
98// Takes the scope of a parsed script, a function and a break location
99// inside the function. The result is the innermost lexical scope around
100// the break point, which serves as the starting point of the ScopeIterator.
101// And the scope of the function that was passed in (called closure scope).
102//
103// The start scope is guaranteed to be either the closure scope itself,
104// or a child of the closure scope.
105class ScopeChainRetriever {
106 public:
107 ScopeChainRetriever(DeclarationScope* scope,
109 : scope_(scope),
110 break_scope_start_(function->shared()->StartPosition()),
111 break_scope_end_(function->shared()->EndPosition()),
112 break_scope_type_(function->shared()->scope_info()->scope_type()),
114 DCHECK_NOT_NULL(scope);
115 RetrieveScopes();
116 }
117
118 DeclarationScope* ClosureScope() { return closure_scope_; }
119 Scope* StartScope() { return start_scope_; }
120
121 private:
122 DeclarationScope* scope_;
126 const int position_;
127
128 DeclarationScope* closure_scope_ = nullptr;
129 Scope* start_scope_ = nullptr;
130
131 void RetrieveScopes() {
132 // 1. Find the closure scope with a DFS.
133 RetrieveClosureScope(scope_);
135
136 // 2. Starting from the closure scope search inwards. Given that V8's scope
137 // tree doesn't guarantee that siblings don't overlap, we look at all
138 // scopes and pick the one with the tightest bounds around `position_`.
140 RetrieveStartScope(closure_scope_);
142 }
143
144 bool RetrieveClosureScope(Scope* scope) {
145 // The closure scope is the scope that matches exactly the function we
146 // paused in.
147 // Note that comparing the position alone is not enough and we also need to
148 // match the scope type. E.g. class member initializer have the exact same
149 // scope positions as their class scope.
150 if (break_scope_type_ == scope->scope_type() &&
151 break_scope_start_ == scope->start_position() &&
152 break_scope_end_ == scope->end_position()) {
153 closure_scope_ = scope->AsDeclarationScope();
154 return true;
155 }
156
157 for (Scope* inner_scope = scope->inner_scope(); inner_scope != nullptr;
158 inner_scope = inner_scope->sibling()) {
159 if (RetrieveClosureScope(inner_scope)) return true;
160 }
161 return false;
162 }
163
164 void RetrieveStartScope(Scope* scope) {
165 const int start = scope->start_position();
166 const int end = scope->end_position();
167
168 // Update start_scope_ if scope contains `position_` and scope is a tighter
169 // fit than the currently set start_scope_.
170 // Generators have the same source position so we also check for equality.
171 if (ContainsPosition(scope) && start >= start_scope_->start_position() &&
172 end <= start_scope_->end_position()) {
173 start_scope_ = scope;
174 }
175
176 for (Scope* inner_scope = scope->inner_scope(); inner_scope != nullptr;
177 inner_scope = inner_scope->sibling()) {
178 RetrieveStartScope(inner_scope);
179 }
180 }
181
182 bool ContainsPosition(Scope* scope) {
183 const int start = scope->start_position();
184 const int end = scope->end_position();
185 // In case the closure_scope_ hasn't been found yet, we are less strict
186 // about recursing downwards. This might be the case for nested arrow
187 // functions that have the same end position.
188 const bool position_fits_end =
190 // While we're evaluating a class, the calling function will have a class
191 // context on the stack with a range that starts at Token::kClass, and the
192 // source position will also point to Token::kClass. To identify the
193 // matching scope we include start in the accepted range for class scopes.
194 //
195 // Similarly "with" scopes can already have bytecodes where the source
196 // position points to the closing parenthesis with the "with" context
197 // already pushed.
198 const bool position_fits_start =
199 scope->is_class_scope() || scope->is_with_scope() ? start <= position_
200 : start < position_;
201 return position_fits_start && position_fits_end;
202 }
203};
204
205// Walks a ScopeInfo outwards until it finds a EVAL scope.
206MaybeDirectHandle<ScopeInfo> FindEvalScope(Isolate* isolate,
207 Tagged<ScopeInfo> start_scope) {
208 Tagged<ScopeInfo> scope = start_scope;
209 while (scope->scope_type() != ScopeType::EVAL_SCOPE &&
210 scope->HasOuterScopeInfo()) {
211 scope = scope->OuterScopeInfo();
212 }
213
214 return scope->scope_type() == ScopeType::EVAL_SCOPE
215 ? MaybeHandle<ScopeInfo>(scope, isolate)
217}
218
219} // namespace
220
222 // Catch the case when the debugger stops in an internal function.
224 DirectHandle<ScopeInfo> scope_info(shared_info->scope_info(), isolate_);
225 if (IsUndefined(shared_info->script(), isolate_)) {
226 current_scope_ = closure_scope_ = nullptr;
227 context_ = handle(function_->context(), isolate_);
229 return;
230 }
231
232 bool ignore_nested_scopes = false;
233 if (shared_info->HasBreakInfo(isolate_) && frame_inspector_ != nullptr) {
234 // The source position at return is always the end of the function,
235 // which is not consistent with the current scope chain. Therefore all
236 // nested with, catch and block contexts are skipped, and we can only
237 // inspect the function scope.
238 // This can only happen if we set a break point inside right before the
239 // return, which requires a debug info to be available.
240 Handle<DebugInfo> debug_info(shared_info->GetDebugInfo(isolate_), isolate_);
241
242 // Find the break point where execution has stopped.
243 BreakLocation location = BreakLocation::FromFrame(debug_info, GetFrame());
244
245 ignore_nested_scopes = location.IsReturn();
246 }
247
248 if (strategy == ReparseStrategy::kScriptIfNeeded) {
249 Tagged<Object> maybe_block_list =
251 calculate_blocklists_ = IsTheHole(maybe_block_list);
254 }
255
256 // Reparse the code and analyze the scopes.
257 // Depending on the chosen strategy, the whole script or just
258 // the closure is re-parsed for function scopes.
259 DirectHandle<Script> script(Cast<Script>(shared_info->script()), isolate_);
260
261 // Pick between flags for a single function compilation, or an eager
262 // compilation of the whole script.
264 (scope_info->scope_type() == FUNCTION_SCOPE &&
268 .set_is_eager(true);
269 flags.set_is_reparse(true);
270
271 MaybeDirectHandle<ScopeInfo> maybe_outer_scope;
272 if (flags.is_toplevel() &&
273 script->compilation_type() == Script::CompilationType::kEval) {
274 // Re-parsing a full eval script requires us to correctly set the outer
275 // language mode and potentially an outer scope info.
276 //
277 // We walk the runtime scope chain and look for an EVAL scope. If we don't
278 // find one, we assume sloppy mode and no outer scope info.
279
280 DCHECK(flags.is_eval());
281
282 DirectHandle<ScopeInfo> eval_scope;
283 if (FindEvalScope(isolate_, *scope_info).ToHandle(&eval_scope)) {
284 flags.set_outer_language_mode(eval_scope->language_mode());
285 if (eval_scope->HasOuterScopeInfo()) {
286 maybe_outer_scope =
287 direct_handle(eval_scope->OuterScopeInfo(), isolate_);
288 }
289 } else {
290 DCHECK_EQ(flags.outer_language_mode(), LanguageMode::kSloppy);
291 DCHECK(maybe_outer_scope.is_null());
292 }
293 } else if (scope_info->scope_type() == EVAL_SCOPE || script->is_wrapped()) {
294 flags.set_is_eval(true);
295 if (!IsNativeContext(*context_)) {
296 maybe_outer_scope = direct_handle(context_->scope_info(), isolate_);
297 }
298 // Language mode may be inherited from the eval caller.
299 // Retrieve it from shared function info.
300 flags.set_outer_language_mode(shared_info->language_mode());
301 } else if (scope_info->scope_type() == MODULE_SCOPE) {
302 DCHECK(script->origin_options().IsModule());
303 DCHECK(flags.is_module());
304 } else {
305 DCHECK(scope_info->is_script_scope() ||
306 scope_info->scope_type() == FUNCTION_SCOPE);
307 }
308
309 UnoptimizedCompileState compile_state;
310
312 std::make_unique<ReusableUnoptimizedCompileState>(isolate_);
313 info_ = std::make_unique<ParseInfo>(isolate_, flags, &compile_state,
315
316 const bool parse_result =
317 flags.is_toplevel()
318 ? parsing::ParseProgram(info_.get(), script, maybe_outer_scope,
320 : parsing::ParseFunction(info_.get(), shared_info, isolate_,
322
323 if (parse_result) {
324 DeclarationScope* literal_scope = info_->literal()->scope();
325
326 ScopeChainRetriever scope_chain_retriever(literal_scope, function_,
328 start_scope_ = scope_chain_retriever.StartScope();
330
331 // In case of a FUNCTION_SCOPE, the ScopeIterator expects
332 // {closure_scope_} to be set to the scope of the function.
333 closure_scope_ = scope_info->scope_type() == FUNCTION_SCOPE
334 ? scope_chain_retriever.ClosureScope()
335 : literal_scope;
336
337 if (ignore_nested_scopes) {
340 // ignore_nested_scopes is only used for the return-position breakpoint,
341 // so we can safely assume that the closure context for the current
342 // function exists if it needs one.
344 context_ = handle(context_->closure_context(), isolate_);
345 }
346 }
347
350 } else {
351 // A failed reparse indicates that the preparser has diverged from the
352 // parser, that the preparse data given to the initial parse was faulty, or
353 // a stack overflow.
354 // TODO(leszeks): This error is pretty unexpected, so we could report the
355 // error in debug mode. Better to not fail in release though, in case it's
356 // just a stack overflow.
357
358 // Silently fail by presenting an empty context chain.
360 }
361}
362
364 if (!context_->IsDebugEvaluateContext()) return;
365 Tagged<Context> current = *context_;
366 do {
367 Tagged<Object> wrapped = current->get(Context::WRAPPED_CONTEXT_INDEX);
368 if (IsContext(wrapped)) {
369 current = Cast<Context>(wrapped);
370 } else {
371 DCHECK(!current->previous().is_null());
372 current = current->previous();
373 }
374 } while (current->IsDebugEvaluateContext());
375 context_ = handle(current, isolate_);
376}
377
379 // Calculate the size of the result.
382 // Fill in scope details.
383 details->set(kScopeDetailsTypeIndex, Smi::FromInt(Type()));
385 details->set(kScopeDetailsObjectIndex, *scope_object);
386 if (Type() == ScopeTypeGlobal || Type() == ScopeTypeScript) {
387 return isolate_->factory()->NewJSArrayWithElements(details);
388 } else if (HasContext()) {
390 details->set(kScopeDetailsNameIndex, *closure_name);
394 if (InInnerScope()) {
396 }
397 }
398 return isolate_->factory()->NewJSArrayWithElements(details);
399}
400
402 return InInnerScope() || !IsNativeContext(*context_);
403}
404
407 if (IsNativeContext(*context_)) return 0;
408 return context_->closure_context()->scope_info()->StartPosition();
409}
410
413 if (IsNativeContext(*context_)) return 0;
414 return context_->closure_context()->scope_info()->EndPosition();
415}
416
418 ScopeType type = Type();
419
420 if (type == ScopeTypeWith) return mode == Mode::ALL;
421 if (type == ScopeTypeGlobal) return mode == Mode::ALL;
422
423 bool declares_local = false;
425 ScopeType scope_type) {
426 declares_local = true;
427 return true;
428 };
429 VisitScope(visitor, mode);
430 return declares_local;
431}
432
434 return !InInnerScope() || NeedsContext();
435}
436
438 const bool needs_context = current_scope_->NeedsContext();
439
440 // We try very hard to ensure that a function's context is already
441 // available when we pause right at the beginning of that function.
442 // This can be tricky when we pause via stack check or via
443 // `BreakOnNextFunctionCall`, which happens normally in the middle of frame
444 // construction and we have to "step into" the function first.
445 //
446 // We check this by ensuring that the current context is not the closure
447 // context should the function need one. In that case the function has already
448 // pushed the context and we are good.
449 CHECK_IMPLIES(needs_context && current_scope_ == closure_scope_ &&
451 function_->context() != *context_);
452
453 return needs_context;
454}
455
463
465 DCHECK(!IsNativeContext(*context_));
466 DCHECK(!context_->previous().is_null());
467 context_ = handle(context_->previous(), isolate_);
468
469 // The locals blocklist is always associated with a context. So when we
470 // move one context up, we also reset the locals_ blocklist.
472}
473
476
477 do {
478 if (NeedsContext()) {
479 // current_scope_ needs a context so moving one scope up requires us to
480 // also move up one context.
482 }
483
485 } while (current_scope_->is_hidden());
486}
487
490
491 // While advancing one context, we need to advance at least one
492 // scope, but until we hit the next scope that actually requires
493 // a context. All the locals collected along the way build the
494 // blocklist for debug-evaluate for this context.
495 while (AdvanceOneScope() && !NeedsContext()) {
496 }
497}
498
500 DCHECK(!Done());
501
502 ScopeType scope_type = Type();
503
504 if (scope_type == ScopeTypeGlobal) {
505 // The global scope is always the last in the chain.
506 DCHECK(IsNativeContext(*context_));
508 DCHECK(Done());
509 return;
510 }
511
512 bool leaving_closure = current_scope_ == closure_scope_;
513
514 if (scope_type == ScopeTypeScript) {
515 DCHECK_IMPLIES(InInnerScope() && !leaving_closure,
517 seen_script_scope_ = true;
518 if (context_->IsScriptContext()) {
519 context_ = handle(context_->previous(), isolate_);
520 }
521 } else if (!InInnerScope()) {
523 } else {
525 AdvanceScope();
526
527 if (leaving_closure) {
529 // If the current_scope_ doesn't need a context, we advance the scopes
530 // and collect the blocklist along the way until we find the scope
531 // that should match `context_`.
532 // But only do this if we have complete scope information.
533 while (!NeedsContext() && AdvanceOneScope()) {
534 }
535 }
536 }
537
540
541 if (leaving_closure) function_ = Handle<JSFunction>();
542}
543
544// Return the type of the current scope.
546 DCHECK(!Done());
547 if (InInnerScope()) {
548 switch (current_scope_->scope_type()) {
549 case FUNCTION_SCOPE:
550 DCHECK_IMPLIES(NeedsContext(), context_->IsFunctionContext() ||
551 context_->IsDebugEvaluateContext());
552 return ScopeTypeLocal;
553 case MODULE_SCOPE:
554 DCHECK_IMPLIES(NeedsContext(), context_->IsModuleContext());
555 return ScopeTypeModule;
556 case SCRIPT_SCOPE:
557 case REPL_MODE_SCOPE:
558 DCHECK_IMPLIES(NeedsContext(), context_->IsScriptContext() ||
559 IsNativeContext(*context_));
560 return ScopeTypeScript;
561 case WITH_SCOPE:
562 DCHECK_IMPLIES(NeedsContext(), context_->IsWithContext());
563 return ScopeTypeWith;
564 case CATCH_SCOPE:
565 DCHECK(context_->IsCatchContext());
566 return ScopeTypeCatch;
567 case BLOCK_SCOPE:
568 case CLASS_SCOPE:
569 DCHECK_IMPLIES(NeedsContext(), context_->IsBlockContext());
570 return ScopeTypeBlock;
571 case EVAL_SCOPE:
572 DCHECK_IMPLIES(NeedsContext(), context_->IsEvalContext());
573 return ScopeTypeEval;
575 DCHECK_IMPLIES(NeedsContext(), IsNativeContext(*context_));
576 // TODO(v8:11989): New ScopeType for ShadowRealms?
577 return ScopeTypeScript;
578 }
579 UNREACHABLE();
580 }
581 if (IsNativeContext(*context_)) {
582 DCHECK(IsJSGlobalObject(context_->global_object()));
583 // If we are at the native context and have not yet seen script scope,
584 // fake it.
586 }
587 if (context_->IsFunctionContext() || context_->IsEvalContext() ||
588 context_->IsDebugEvaluateContext()) {
589 return ScopeTypeClosure;
590 }
591 if (context_->IsCatchContext()) {
592 return ScopeTypeCatch;
593 }
594 if (context_->IsBlockContext()) {
595 return ScopeTypeBlock;
596 }
597 if (context_->IsModuleContext()) {
598 return ScopeTypeModule;
599 }
600 if (context_->IsScriptContext()) {
601 return ScopeTypeScript;
602 }
603 DCHECK(context_->IsWithContext());
604 return ScopeTypeWith;
605}
606
608 DCHECK(!Done());
609
610 ScopeType type = Type();
611 if (type == ScopeTypeGlobal) {
612 DCHECK_EQ(Mode::ALL, mode);
613 return handle(context_->global_proxy(), isolate_);
614 }
615 if (type == ScopeTypeWith) {
616 DCHECK_EQ(Mode::ALL, mode);
617 return WithContextExtension();
618 }
619
621 auto visitor = [=, this](DirectHandle<String> name,
623 if (IsOptimizedOut(*value, isolate_)) {
625 scope, name, isolate_->factory()->value_unavailable_accessor(), NONE)
626 .Check();
627 } else if (IsTheHole(*value, isolate_)) {
628 const bool is_overriden_repl_let =
629 scope_type == ScopeTypeScript &&
630 JSReceiver::HasOwnProperty(isolate_, scope, name).FromMaybe(true);
631 if (!is_overriden_repl_let) {
632 // We also use the hole to represent overridden let-declarations via
633 // REPL mode in a script context. Don't install the unavailable accessor
634 // in that case.
635 JSObject::SetAccessor(scope, name,
636 isolate_->factory()->value_unavailable_accessor(),
637 NONE)
638 .Check();
639 }
640 } else {
641 // Overwrite properties. Sometimes names in the same scope can collide,
642 // e.g. with extension objects introduced via local eval.
643 Object::SetPropertyOrElement(isolate_, scope, name, value,
645 .Check();
646 }
647 return false;
648 };
649
650 VisitScope(visitor, mode);
651 return scope;
652}
653
654void ScopeIterator::VisitScope(const Visitor& visitor, Mode mode) const {
655 switch (Type()) {
656 case ScopeTypeLocal:
657 case ScopeTypeClosure:
658 case ScopeTypeCatch:
659 case ScopeTypeBlock:
660 case ScopeTypeEval:
661 return VisitLocalScope(visitor, mode, Type());
662 case ScopeTypeModule:
663 if (InInnerScope()) {
664 return VisitLocalScope(visitor, mode, Type());
665 }
666 DCHECK_EQ(Mode::ALL, mode);
667 return VisitModuleScope(visitor);
668 case ScopeTypeScript:
669 DCHECK_EQ(Mode::ALL, mode);
670 return VisitScriptScope(visitor);
671 case ScopeTypeWith:
672 case ScopeTypeGlobal:
673 UNREACHABLE();
674 }
675}
676
678 DirectHandle<Object> value) {
679 DCHECK(!Done());
680 name = isolate_->factory()->InternalizeString(name);
681 switch (Type()) {
682 case ScopeTypeGlobal:
683 case ScopeTypeWith:
684 break;
685
686 case ScopeTypeEval:
687 case ScopeTypeBlock:
688 case ScopeTypeCatch:
689 case ScopeTypeModule:
690 if (InInnerScope()) return SetLocalVariableValue(name, value);
691 if (Type() == ScopeTypeModule && SetModuleVariableValue(name, value)) {
692 return true;
693 }
694 return SetContextVariableValue(name, value);
695
696 case ScopeTypeLocal:
697 case ScopeTypeClosure:
698 if (InInnerScope()) {
700 if (SetLocalVariableValue(name, value)) return true;
701 // There may not be an associated context since we're InInnerScope().
702 if (!NeedsContext()) return false;
703 } else {
705 if (SetContextVariableValue(name, value)) return true;
706 }
707 // The above functions only set variables statically declared in the
708 // function. There may be eval-introduced variables. Check them in
709 // SetContextExtensionValue.
710 return SetContextExtensionValue(name, value);
711
712 case ScopeTypeScript:
713 return SetScriptVariableValue(name, value);
714 }
715 return false;
716}
717
719 // closure_scope_ can be nullptr if parsing failed. See the TODO in
720 // TryParseAndRetrieveScopes.
723}
724
726 DCHECK(IsStringSet(*locals_));
727 for (Variable* var : *current_scope_->locals()) {
728 if (var->location() == VariableLocation::PARAMETER ||
729 var->location() == VariableLocation::LOCAL) {
730 locals_ = StringSet::Add(isolate_, locals_, var->name());
731 }
732 }
733}
734
735#ifdef DEBUG
736// Debug print of the content of the current scope.
737void ScopeIterator::DebugPrint() {
738 StdoutStream os;
739 DCHECK(!Done());
740 switch (Type()) {
742 os << "Global:\n";
743 Print(*context_, os);
744 break;
745
747 os << "Local:\n";
748 if (NeedsContext()) {
749 Print(*context_, os);
750 if (context_->has_extension()) {
752 DCHECK(IsJSContextExtensionObject(*extension));
753 Print(*extension, os);
754 }
755 }
756 break;
757 }
758
760 os << "With:\n";
761 Print(context_->extension(), os);
762 break;
763
765 os << "Catch:\n";
766 Print(context_->extension(), os);
768 break;
769
771 os << "Closure:\n";
772 Print(*context_, os);
773 if (context_->has_extension()) {
774 DirectHandle<HeapObject> extension(context_->extension(), isolate_);
775 DCHECK(IsJSContextExtensionObject(*extension));
776 Print(*extension, os);
777 }
778 break;
779
781 os << "Script:\n";
782 Print(context_->native_context()->script_context_table(), os);
783 break;
784
785 default:
786 UNREACHABLE();
787 }
788 PrintF("\n");
789}
790#endif
791
793 if (frame_inspector_) {
795 } else {
796 DCHECK(!generator_.is_null());
798 isolate_, direct_handle(generator_->function()->shared(), isolate_));
799 return generator_->source_position();
800 }
801}
802
803void ScopeIterator::VisitScriptScope(const Visitor& visitor) const {
804 DirectHandle<ScriptContextTable> script_contexts(
805 context_->native_context()->script_context_table(), isolate_);
806
807 // Skip the first script since that just declares 'this'.
808 for (int i = 1; i < script_contexts->length(kAcquireLoad); i++) {
809 DirectHandle<Context> context(script_contexts->get(i), isolate_);
810 DirectHandle<ScopeInfo> scope_info(context->scope_info(), isolate_);
811 if (VisitContextLocals(visitor, scope_info, context, ScopeTypeScript)) {
812 return;
813 }
814 }
815}
816
817void ScopeIterator::VisitModuleScope(const Visitor& visitor) const {
818 DCHECK(context_->IsModuleContext());
819
820 DirectHandle<ScopeInfo> scope_info(context_->scope_info(), isolate_);
821 if (VisitContextLocals(visitor, scope_info, context_, ScopeTypeModule)) {
822 return;
823 }
824
825 int module_variable_count = scope_info->ModuleVariableCount();
826
828
829 for (int i = 0; i < module_variable_count; ++i) {
830 int index;
832 {
833 Tagged<String> raw_name;
834 scope_info->ModuleVariable(i, &raw_name, &index);
835 if (ScopeInfo::VariableIsSynthetic(raw_name)) continue;
836 name = handle(raw_name, isolate_);
837 }
838 Handle<Object> value =
840
841 if (visitor(name, value, ScopeTypeModule)) return;
842 }
843}
844
846 DirectHandle<ScopeInfo> scope_info,
847 DirectHandle<Context> context,
848 ScopeType scope_type) const {
849 // Fill all context locals to the context extension.
850 for (auto it : ScopeInfo::IterateLocalNames(scope_info)) {
851 Handle<String> name(it->name(), isolate_);
852 if (ScopeInfo::VariableIsSynthetic(*name)) continue;
853 int context_index = scope_info->ContextHeaderLength() + it->index();
854 Handle<Object> value(context->get(context_index), isolate_);
855 if (v8_flags.script_context_mutable_heap_number &&
856 context->IsScriptContext()) {
858 context, it->index(), value, isolate_),
859 isolate_);
860 }
861 if (visitor(name, value, scope_type)) return true;
862 }
863 return false;
864}
865
866bool ScopeIterator::VisitLocals(const Visitor& visitor, Mode mode,
867 ScopeType scope_type) const {
870 // TODO(bmeurer): We should refactor the general variable lookup
871 // around "this", since the current way is rather hacky when the
872 // receiver is context-allocated.
873 auto this_var = current_scope_->AsDeclarationScope()->receiver();
876 ? handle(context_->get(this_var->index()), isolate_)
877 : frame_inspector_ == nullptr ? handle(generator_->receiver(), isolate_)
879 if (visitor(isolate_->factory()->this_string(), receiver, scope_type))
880 return true;
881 }
882
884 Variable* function_var =
886 if (function_var != nullptr) {
887 Handle<JSFunction> function = frame_inspector_ == nullptr
888 ? function_
890 Handle<String> name = function_var->name();
891 if (visitor(name, function, scope_type)) return true;
892 }
893 }
894
895 for (Variable* var : *current_scope_->locals()) {
896 if (ScopeInfo::VariableIsSynthetic(*var->name())) {
897 // We want to materialize "new.target" for debug-evaluate.
898 if (mode != Mode::STACK ||
899 !var->name()->Equals(*isolate_->factory()->dot_new_target_string())) {
900 continue;
901 }
902 }
903
904 int index = var->index();
906 switch (var->location()) {
908 UNREACHABLE();
909
911 // REPL declared variables are ignored for now.
913 continue;
914
916 if (frame_inspector_ == nullptr) {
917 // Get the variable from the suspended generator.
918 DCHECK(!generator_.is_null());
919 Tagged<FixedArray> parameters_and_registers =
920 generator_->parameters_and_registers();
921 DCHECK_LT(index, parameters_and_registers->length());
922 value = handle(parameters_and_registers->get(index), isolate_);
923 } else if (var->IsReceiver()) {
924 value = frame_inspector_->GetReceiver();
925 } else {
926 value = frame_inspector_->GetParameter(index);
927 }
928 break;
929 }
930
932 if (frame_inspector_ == nullptr) {
933 // Get the variable from the suspended generator.
934 DCHECK(!generator_.is_null());
935 Tagged<FixedArray> parameters_and_registers =
936 generator_->parameters_and_registers();
937 int parameter_count =
938 function_->shared()->scope_info()->ParameterCount();
939 index += parameter_count;
940 DCHECK_LT(index, parameters_and_registers->length());
941 value = handle(parameters_and_registers->get(index), isolate_);
942 } else {
943 value = frame_inspector_->GetExpression(index);
944 if (IsOptimizedOut(*value, isolate_)) {
945 // We'll rematerialize this later.
948 continue;
949 }
950 } else if (IsLexicalVariableMode(var->mode()) &&
951 IsUndefined(*value, isolate_) &&
953 GetSourcePosition() <= var->initializer_position()) {
954 // Variables that are `undefined` could also mean an elided hole
955 // write. We explicitly check the static scope information if we
956 // are currently stopped before the variable is actually initialized
957 // which means we are in the middle of that var's TDZ.
958 value = isolate_->factory()->the_hole_value();
959 }
960 }
961 break;
962
964 if (mode == Mode::STACK) continue;
965 DCHECK(var->IsContextSlot());
966
967 DCHECK_EQ(context_->scope_info()->ContextSlotIndex(var->name()), index);
968 value = handle(context_->get(index), isolate_);
969
970 if (v8_flags.script_context_mutable_heap_number &&
971 context_->IsScriptContext()) {
973 context_, index, value, isolate_),
974 isolate_);
975 }
976 break;
977
979 if (mode == Mode::STACK) continue;
980 // if (var->IsExport()) continue;
982 value = SourceTextModule::LoadVariable(isolate_, module, var->index());
983 break;
984 }
985 }
986
987 if (visitor(var->name(), value, scope_type)) return true;
988 }
989 return false;
990}
991
992// Retrieve the with-context extension object. If the extension object is
993// a proxy, return an empty object.
995 DCHECK(context_->IsWithContext());
996 if (!IsJSObject(context_->extension_receiver())) {
997 DCHECK(IsJSProxy(context_->extension_receiver()) ||
998 IsWasmObject(context_->extension_receiver()));
1000 }
1001 return handle(Cast<JSObject>(context_->extension_receiver()), isolate_);
1002}
1003
1004// Create a plain JSObject which materializes the block scope for the specified
1005// block context.
1007 ScopeType scope_type) const {
1008 if (InInnerScope()) {
1009 if (VisitLocals(visitor, mode, scope_type)) return;
1010 if (mode == Mode::STACK && Type() == ScopeTypeLocal) {
1011 // Hide |this| in arrow functions that may be embedded in other functions
1012 // but don't force |this| to be context-allocated. Otherwise we'd find the
1013 // wrong |this| value.
1016 if (visitor(isolate_->factory()->this_string(),
1017 isolate_->factory()->undefined_value(), scope_type))
1018 return;
1019 }
1020 // Add |arguments| to the function scope even if it wasn't used.
1021 // Currently we don't yet support materializing the arguments object of
1022 // suspended generators. We'd need to read the arguments out from the
1023 // suspended generator rather than from an activation as
1024 // FunctionGetArguments does.
1025 if (frame_inspector_ != nullptr && !closure_scope_->is_arrow_scope() &&
1026 (closure_scope_->arguments() == nullptr ||
1027 IsOptimizedOut(*frame_inspector_->GetExpression(
1029 isolate_))) {
1030 JavaScriptFrame* frame = GetFrame();
1033 if (visitor(isolate_->factory()->arguments_string(), arguments,
1034 scope_type))
1035 return;
1036 }
1037 }
1038 } else {
1039 DCHECK_EQ(Mode::ALL, mode);
1040 DirectHandle<ScopeInfo> scope_info(context_->scope_info(), isolate_);
1041 if (VisitContextLocals(visitor, scope_info, context_, scope_type)) return;
1042 }
1043
1044 if (mode == Mode::ALL && HasContext()) {
1045 DCHECK(!context_->IsScriptContext());
1046 DCHECK(!IsNativeContext(*context_));
1047 DCHECK(!context_->IsWithContext());
1048 if (!context_->scope_info()->SloppyEvalCanExtendVars()) return;
1049 if (context_->extension_object().is_null()) return;
1050 DirectHandle<JSObject> extension(context_->extension_object(), isolate_);
1054 .ToHandleChecked();
1055
1056 for (int i = 0; i < keys->length(); i++) {
1057 // Names of variables introduced by eval are strings.
1058 DCHECK(IsString(keys->get(i)));
1060 Handle<Object> value =
1062 if (visitor(key, value, scope_type)) return;
1063 }
1064 }
1065}
1066
1068 DirectHandle<Object> new_value) {
1069 // TODO(verwaest): Walk parameters backwards, not forwards.
1070 // TODO(verwaest): Use VariableMap rather than locals() list for lookup.
1071 for (Variable* var : *current_scope_->locals()) {
1072 if (String::Equals(isolate_, var->name(), variable_name)) {
1073 int index = var->index();
1074 switch (var->location()) {
1077 // Drop assignments to unallocated locals.
1078 DCHECK(var->is_this() ||
1079 *variable_name == ReadOnlyRoots(isolate_).arguments_string());
1080 return false;
1081
1083 // Assignments to REPL declared variables are ignored for now.
1084 return false;
1085
1087 if (var->is_this()) return false;
1088 if (frame_inspector_ == nullptr) {
1089 // Set the variable in the suspended generator.
1090 DCHECK(!generator_.is_null());
1091 DirectHandle<FixedArray> parameters_and_registers(
1092 generator_->parameters_and_registers(), isolate_);
1093 DCHECK_LT(index, parameters_and_registers->length());
1094 parameters_and_registers->set(index, *new_value);
1095 } else {
1096 JavaScriptFrame* frame = GetFrame();
1097 if (!frame->is_unoptimized()) return false;
1098
1099 frame->SetParameterValue(index, *new_value);
1100 }
1101 return true;
1102 }
1103
1105 if (frame_inspector_ == nullptr) {
1106 // Set the variable in the suspended generator.
1107 DCHECK(!generator_.is_null());
1108 int parameter_count =
1109 function_->shared()->scope_info()->ParameterCount();
1110 index += parameter_count;
1111 DirectHandle<FixedArray> parameters_and_registers(
1112 generator_->parameters_and_registers(), isolate_);
1113 DCHECK_LT(index, parameters_and_registers->length());
1114 parameters_and_registers->set(index, *new_value);
1115 } else {
1116 // Set the variable on the stack.
1117 JavaScriptFrame* frame = GetFrame();
1118 if (!frame->is_unoptimized()) return false;
1119
1120 frame->SetExpression(index, *new_value);
1121 }
1122 return true;
1123
1125 DCHECK(var->IsContextSlot());
1126
1127 // We know of at least one open bug where the context and scope chain
1128 // don't match (https://crbug.com/753338).
1129 // Skip the write if the context's ScopeInfo doesn't know anything
1130 // about this variable.
1131 if (context_->scope_info()->ContextSlotIndex(variable_name) !=
1132 index) {
1133 return false;
1134 }
1135 if ((v8_flags.script_context_mutable_heap_number ||
1136 v8_flags.const_tracking_let) &&
1137 context_->IsScriptContext()) {
1139 context_, index, new_value, isolate_);
1140 } else {
1141 context_->set(index, *new_value);
1142 }
1143
1144 return true;
1145
1147 if (!var->IsExport()) return false;
1149 SourceTextModule::StoreVariable(module, var->index(), new_value);
1150 return true;
1151 }
1152 UNREACHABLE();
1153 }
1154 }
1155
1156 return false;
1157}
1158
1160 DirectHandle<Object> new_value) {
1161 if (!context_->has_extension()) return false;
1162
1163 DCHECK(IsJSContextExtensionObject(context_->extension_object()));
1164 DirectHandle<JSObject> ext(context_->extension_object(), isolate_);
1165 LookupIterator it(isolate_, ext, variable_name, LookupIterator::OWN);
1167 DCHECK(maybe.IsJust());
1168 if (!maybe.FromJust()) return false;
1169
1170 CHECK(Object::SetDataProperty(&it, new_value).ToChecked());
1171 return true;
1172}
1173
1175 DirectHandle<Object> new_value) {
1176 int slot_index = context_->scope_info()->ContextSlotIndex(variable_name);
1177 if (slot_index < 0) return false;
1178 context_->set(slot_index, *new_value);
1179 return true;
1180}
1181
1183 DirectHandle<Object> new_value) {
1185 int cell_index;
1187 InitializationFlag init_flag;
1188 MaybeAssignedFlag maybe_assigned_flag;
1189 cell_index = context_->scope_info()->ModuleIndex(
1190 *variable_name, &mode, &init_flag, &maybe_assigned_flag);
1191
1192 // Setting imports is currently not supported.
1195 return false;
1196 }
1197
1199 SourceTextModule::StoreVariable(module, cell_index, new_value);
1200 return true;
1201}
1202
1204 DirectHandle<Object> new_value) {
1205 DirectHandle<ScriptContextTable> script_contexts(
1206 context_->native_context()->script_context_table(), isolate_);
1207 VariableLookupResult lookup_result;
1208 if (script_contexts->Lookup(variable_name, &lookup_result)) {
1209 DirectHandle<Context> script_context(
1210 script_contexts->get(lookup_result.context_index), isolate_);
1211 if (v8_flags.script_context_mutable_heap_number ||
1212 v8_flags.const_tracking_let) {
1214 script_context, lookup_result.slot_index, new_value, isolate_);
1215 } else {
1216 script_context->set(lookup_result.slot_index, *new_value);
1217 }
1218 return true;
1219 }
1220
1221 return false;
1222}
1223
1224namespace {
1225
1226// Given the scope and context of a paused function, this class calculates
1227// all the necessary block lists on the scope chain and stores them in the
1228// global LocalsBlockListCache ephemeron table.
1229//
1230// Doc: bit.ly/chrome-devtools-debug-evaluate-design.
1231//
1232// The algorithm works in a single walk of the scope chain from the
1233// paused function scope outwards to the script scope.
1234//
1235// When we step from scope "a" to its outer scope "b", we do:
1236//
1237// 1. Add all stack-allocated variables from "b" to the blocklists.
1238// 2. Does "b" need a context? If yes:
1239// - Store all current blocklists in the global table
1240// - Start a new blocklist for scope "b"
1241// 3. Is "b" a function scope without a context? If yes:
1242// - Start a new blocklist for scope "b"
1243//
1244class LocalBlocklistsCollector {
1245 public:
1246 LocalBlocklistsCollector(Isolate* isolate, Handle<Script> script,
1247 Handle<Context> context,
1248 DeclarationScope* closure_scope);
1249 void CollectAndStore();
1250
1251 private:
1252 void InitializeWithClosureScope();
1253 void AdvanceToNextNonHiddenScope();
1254 void CollectCurrentLocalsIntoBlocklists();
1255 DirectHandle<ScopeInfo> FindScopeInfoForScope(Scope* scope) const;
1256 void StoreFunctionBlocklists(DirectHandle<ScopeInfo> outer_scope_info);
1257
1258 Isolate* isolate_;
1261 Scope* scope_;
1262 DeclarationScope* closure_scope_;
1263
1265 std::map<Scope*, IndirectHandle<StringSet>> function_blocklists_;
1266};
1267
1268LocalBlocklistsCollector::LocalBlocklistsCollector(
1269 Isolate* isolate, Handle<Script> script, Handle<Context> context,
1270 DeclarationScope* closure_scope)
1271 : isolate_(isolate),
1272 script_(script),
1273 context_(context),
1274 scope_(closure_scope),
1275 closure_scope_(closure_scope) {}
1276
1277void LocalBlocklistsCollector::InitializeWithClosureScope() {
1278 CHECK(scope_->is_declaration_scope());
1279 function_blocklists_.emplace(scope_, StringSet::New(isolate_));
1280 if (scope_->NeedsContext()) context_blocklist_ = StringSet::New(isolate_);
1281}
1282
1283void LocalBlocklistsCollector::AdvanceToNextNonHiddenScope() {
1284 DCHECK(scope_ && scope_->outer_scope());
1285 do {
1286 scope_ = scope_->outer_scope();
1287 CHECK(scope_);
1288 } while (scope_->is_hidden());
1289}
1290
1291void LocalBlocklistsCollector::CollectCurrentLocalsIntoBlocklists() {
1292 for (Variable* var : *scope_->locals()) {
1293 if (var->location() == VariableLocation::PARAMETER ||
1294 var->location() == VariableLocation::LOCAL) {
1295 if (!context_blocklist_.is_null()) {
1297 StringSet::Add(isolate_, context_blocklist_, var->name());
1298 }
1299 for (auto& pair : function_blocklists_) {
1300 pair.second = StringSet::Add(isolate_, pair.second, var->name());
1301 }
1302 }
1303 }
1304}
1305
1306DirectHandle<ScopeInfo> LocalBlocklistsCollector::FindScopeInfoForScope(
1307 Scope* scope) const {
1309 SharedFunctionInfo::ScriptIterator iterator(isolate_, *script_);
1310 for (Tagged<SharedFunctionInfo> info = iterator.Next(); !info.is_null();
1311 info = iterator.Next()) {
1312 Tagged<ScopeInfo> scope_info = info->scope_info();
1313 if (info->is_compiled() && !scope_info.is_null() &&
1314 scope->start_position() == info->StartPosition() &&
1315 scope->end_position() == info->EndPosition() &&
1316 scope->scope_type() == scope_info->scope_type()) {
1317 return direct_handle(scope_info, isolate_);
1318 }
1319 }
1320 return DirectHandle<ScopeInfo>();
1321}
1322
1323void LocalBlocklistsCollector::StoreFunctionBlocklists(
1324 DirectHandle<ScopeInfo> outer_scope_info) {
1325 for (const auto& pair : function_blocklists_) {
1326 DirectHandle<ScopeInfo> scope_info = FindScopeInfoForScope(pair.first);
1327 // If we don't find a ScopeInfo it's not tragic. It means we'll do
1328 // a full-reparse in case we pause in that function in the future.
1329 // The only ScopeInfo that MUST be found is for the closure_scope_.
1330 CHECK_IMPLIES(pair.first == closure_scope_, !scope_info.is_null());
1331 if (scope_info.is_null()) continue;
1332 isolate_->LocalsBlockListCacheSet(scope_info, outer_scope_info,
1333 pair.second);
1334 }
1335}
1336
1337void LocalBlocklistsCollector::CollectAndStore() {
1338 InitializeWithClosureScope();
1339
1340 while (scope_->outer_scope() && !IsNativeContext(*context_)) {
1341 AdvanceToNextNonHiddenScope();
1342 // 1. Add all stack-allocated variables of `scope_` to the various lists.
1343 CollectCurrentLocalsIntoBlocklists();
1344
1345 // 2. If the current scope requires a context then all the blocklists "stop"
1346 // here and we store them. Next, advance the current context so
1347 // `context_` and `scope_` match again.
1348 if (scope_->NeedsContext()) {
1349 if (!context_blocklist_.is_null()) {
1350 // Only store the block list and advance the context if the
1351 // context_blocklist is set. This handles the case when we start on
1352 // a closure scope that doesn't require a context. In that case
1353 // `context_` is already the right context for `scope_` so we don't
1354 // need to advance `context_`.
1355 isolate_->LocalsBlockListCacheSet(
1356 direct_handle(context_->scope_info(), isolate_),
1357 direct_handle(context_->previous()->scope_info(), isolate_),
1359 context_ = handle(context_->previous(), isolate_);
1360 }
1361
1362 StoreFunctionBlocklists(direct_handle(context_->scope_info(), isolate_));
1363
1364 context_blocklist_ = StringSet::New(isolate_);
1365 function_blocklists_.clear();
1366 } else if (scope_->is_function_scope()) {
1367 // 3. If `scope` is a function scope with an SFI, start recording
1368 // locals for its ScopeInfo.
1369 CHECK(!scope_->NeedsContext());
1370 function_blocklists_.emplace(scope_, StringSet::New(isolate_));
1371 }
1372 }
1373
1374 // In case we don't have any outer scopes we still need to record the empty
1375 // block list for the paused function to prevent future re-parses.
1376 StoreFunctionBlocklists(direct_handle(context_->scope_info(), isolate_));
1377}
1378
1379} // namespace
1380
1381void ScopeIterator::MaybeCollectAndStoreLocalBlocklists() const {
1382 if (!calculate_blocklists_ || current_scope_ != closure_scope_ ||
1383 Type() == ScopeTypeScript) {
1384 return;
1385 }
1386
1387 DCHECK(IsTheHole(isolate_->LocalsBlockListCacheGet(
1388 direct_handle(function_->shared()->scope_info(), isolate_))));
1389 LocalBlocklistsCollector collector(isolate_, script_, context_,
1391 collector.CollectAndStore();
1392}
1393
1394} // namespace internal
1395} // namespace v8
Isolate * isolate_
int16_t parameter_count
Definition builtins.cc:67
V8_INLINE bool IsJust() const
Definition v8-maybe.h:36
V8_INLINE T FromJust() const &
Definition v8-maybe.h:64
static Handle< JSObject > FunctionGetArguments(JavaScriptFrame *frame, int inlined_jsframe_index)
Definition accessors.cc:520
bool IsReturn() const
Definition debug.h:81
static BreakLocation FromFrame(Handle< DebugInfo > debug_info, JavaScriptFrame *frame)
Definition debug.cc:188
void SetExpression(int index, Tagged< Object > value)
Definition frames-inl.h:246
static DirectHandle< Object > LoadScriptContextElement(DirectHandle< Context > script_context, int index, DirectHandle< Object > new_value, Isolate *isolate)
Definition contexts.cc:578
static void StoreScriptContextAndUpdateSlotProperty(DirectHandle< Context > script_context, int index, DirectHandle< Object > new_value, Isolate *isolate)
Definition contexts.cc:586
Variable * function_var() const
Definition scopes.h:1046
Variable * arguments() const
Definition scopes.h:1109
bool has_this_declaration() const
Definition scopes.h:1039
Handle< FixedArray > NewFixedArray(int length, AllocationType allocation=AllocationType::kYoung)
Handle< JSObject > NewSlowJSObjectWithNullProto()
Definition factory.cc:2998
Handle< JSArray > NewJSArrayWithElements(DirectHandle< FixedArrayBase > elements, ElementsKind elements_kind, int length, AllocationType allocation=AllocationType::kYoung)
Definition factory.cc:3228
Handle< String > InternalizeString(base::Vector< const char > str, bool convert_encoding=false)
Definition factory.h:216
Handle< Object > GetParameter(int index)
Handle< JSFunction > GetFunction() const
Handle< Object > GetExpression(int index)
Handle< Script > GetScript()
Handle< Object > GetReceiver()
Handle< Object > GetContext()
V8_INLINE Address * location() const
Definition handles.h:80
v8::internal::Factory * factory()
Definition isolate.h:1527
Tagged< Object > LocalsBlockListCacheGet(DirectHandle< ScopeInfo > scope_info)
Definition isolate.cc:7593
static DirectHandle< String > GetDebugName(DirectHandle< JSFunction > function)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< Object > SetAccessor(DirectHandle< JSObject > object, DirectHandle< Name > name, DirectHandle< AccessorInfo > info, PropertyAttributes attributes)
V8_EXPORT_PRIVATE static V8_WARN_UNUSED_RESULT Maybe< bool > HasOwnProperty(Isolate *isolate, DirectHandle< JSReceiver > object, DirectHandle< Name > name)
static Handle< Object > GetDataProperty(Isolate *isolate, DirectHandle< JSReceiver > object, DirectHandle< Name > name)
V8_EXPORT_PRIVATE static V8_WARN_UNUSED_RESULT Maybe< bool > HasProperty(LookupIterator *it)
Definition js-objects.cc:98
void SetParameterValue(int index, Tagged< Object > value) const
Definition frames.cc:2410
bool is_unoptimized() const
Definition frames.h:801
static MaybeHandle< FixedArray > GetKeys(Isolate *isolate, DirectHandle< JSReceiver > object, KeyCollectionMode mode, PropertyFilter filter, GetKeysConversion keys_conversion=GetKeysConversion::kKeepNumbers, bool is_for_in=false, bool skip_indices=false)
Definition keys.cc:97
V8_INLINE bool is_null() const
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< Object > SetPropertyOrElement(Isolate *isolate, DirectHandle< JSAny > object, DirectHandle< Name > name, DirectHandle< Object > value, Maybe< ShouldThrow > should_throw=Nothing< ShouldThrow >(), StoreOrigin store_origin=StoreOrigin::kMaybeKeyed)
static V8_WARN_UNUSED_RESULT Maybe< bool > SetDataProperty(LookupIterator *it, DirectHandle< Object > value)
Definition objects.cc:2604
static LocalNamesRange< DirectHandle< ScopeInfo > > IterateLocalNames(DirectHandle< ScopeInfo > scope_info)
static bool VariableIsSynthetic(Tagged< String > name)
bool DeclaresLocals(Mode mode) const
bool SetModuleVariableValue(DirectHandle< String > variable_name, DirectHandle< Object > new_value)
Handle< JSObject > ScopeObject(Mode mode)
static const int kScopeDetailsNameIndex
bool SetLocalVariableValue(DirectHandle< String > variable_name, DirectHandle< Object > new_value)
FrameInspector *const frame_inspector_
DirectHandle< JSObject > MaterializeScopeDetails()
bool SetVariableValue(Handle< String > variable_name, DirectHandle< Object > new_value)
void VisitLocalScope(const Visitor &visitor, Mode mode, ScopeType scope_type) const
DirectHandle< Object > GetFunctionDebugName() const
std::unique_ptr< ReusableUnoptimizedCompileState > reusable_compile_state_
JavaScriptFrame * GetFrame() const
void TryParseAndRetrieveScopes(ReparseStrategy strategy)
static const int kScopeDetailsTypeIndex
bool SetScriptVariableValue(DirectHandle< String > variable_name, DirectHandle< Object > new_value)
static const int kScopeDetailsStartPositionIndex
Handle< StringSet > locals_
void VisitModuleScope(const Visitor &visitor) const
Handle< JSObject > WithContextExtension()
void MaybeCollectAndStoreLocalBlocklists() const
bool SetContextVariableValue(DirectHandle< String > variable_name, DirectHandle< Object > new_value)
bool VisitContextLocals(const Visitor &visitor, DirectHandle< ScopeInfo > scope_info, DirectHandle< Context > context, ScopeType scope_type) const
void VisitScriptScope(const Visitor &visitor) const
Handle< Context > context_
bool ClosureScopeHasThisReference() const
bool VisitLocals(const Visitor &visitor, Mode mode, ScopeType scope_type) const
std::function< bool(Handle< String > name, Handle< Object > value, ScopeType scope_type)> Visitor
static const int kScopeDetailsSize
ScopeIterator(Isolate *isolate, FrameInspector *frame_inspector, ReparseStrategy strategy)
bool SetContextExtensionValue(DirectHandle< String > variable_name, DirectHandle< Object > new_value)
std::unique_ptr< ParseInfo > info_
void VisitScope(const Visitor &visitor, Mode mode) const
DeclarationScope * closure_scope_
static const int kScopeDetailsFunctionIndex
Handle< JSFunction > function_
Handle< JSGeneratorObject > generator_
static const int kScopeDetailsObjectIndex
static const int kScopeDetailsEndPositionIndex
bool HasThisReference() const
Definition scopes.cc:1385
Scope * outer_scope() const
Definition scopes.h:488
DeclarationScope * AsDeclarationScope()
base::ThreadedList< Variable > * locals()
Definition scopes.h:231
bool is_script_scope() const
Definition scopes.h:364
bool is_function_scope() const
Definition scopes.h:362
ScopeType scope_type() const
Definition scopes.h:474
bool is_hidden() const
Definition scopes.h:346
bool NeedsContext() const
Definition scopes.h:430
int end_position() const
Definition scopes.h:342
int start_position() const
Definition scopes.h:338
bool is_declaration_scope() const
Definition scopes.h:372
static void EnsureSourcePositionsAvailable(Isolate *isolate, DirectHandle< SharedFunctionInfo > shared_info)
static constexpr Tagged< Smi > FromInt(int value)
Definition smi.h:38
static CellIndexKind GetCellIndexKind(int cell_index)
Definition modules.cc:279
static void StoreVariable(DirectHandle< SourceTextModule > module, int cell_index, DirectHandle< Object > value)
static Handle< Object > LoadVariable(Isolate *isolate, DirectHandle< SourceTextModule > module, int cell_index)
static V8_EXPORT_PRIVATE Handle< StringSet > New(Isolate *isolate)
Definition objects.cc:5615
static V8_EXPORT_PRIVATE Handle< StringSet > Add(Isolate *isolate, Handle< StringSet > stringset, DirectHandle< String > name)
Definition objects.cc:5619
bool Equals(Tagged< String > other) const
Definition string-inl.h:535
static UnoptimizedCompileFlags ForFunctionCompile(Isolate *isolate, Tagged< SharedFunctionInfo > shared)
Definition parse-info.cc:46
static UnoptimizedCompileFlags ForScriptCompile(Isolate *isolate, Tagged< Script > script)
Definition parse-info.cc:69
Handle< String > name() const
Definition variables.h:64
const JSFunctionRef function_
int start
int end
const ScopeType break_scope_type_
std::map< Scope *, IndirectHandle< StringSet > > function_blocklists_
const int position_
Scope * start_scope_
Handle< StringSet > context_blocklist_
DeclarationScope * scope_
Isolate * isolate_
Handle< Context > context_
DeclarationScope * closure_scope_
const int break_scope_start_
const int break_scope_end_
Handle< Script > script_
std::string extension
TNode< Context > context
TNode< Object > receiver
std::unique_ptr< icu::DateTimePatternGenerator > generator_
int position
Definition liveedit.cc:290
bool ParseFunction(ParseInfo *info, DirectHandle< SharedFunctionInfo > shared_info, Isolate *isolate, ReportStatisticsMode mode)
Definition parsing.cc:67
bool ParseProgram(ParseInfo *info, DirectHandle< Script > script, MaybeDirectHandle< ScopeInfo > maybe_outer_scope_info, Isolate *isolate, ReportStatisticsMode mode)
Definition parsing.cc:39
V8_INLINE IndirectHandle< T > handle(Tagged< T > object, Isolate *isolate)
Definition handles-inl.h:72
constexpr NullMaybeHandleType kNullMaybeHandle
PerThreadAssertScopeDebugOnly< false, SAFEPOINTS_ASSERT, HEAP_ALLOCATION_ASSERT > DisallowGarbageCollection
constexpr int kNoSourcePosition
Definition globals.h:850
bool IsLexicalVariableMode(VariableMode mode)
Definition globals.h:2155
void PrintF(const char *format,...)
Definition utils.cc:39
@ SHADOW_REALM_SCOPE
Definition globals.h:1903
Tagged(T object) -> Tagged< T >
V8_INLINE IndirectHandle< T > indirect_handle(DirectHandle< T > handle)
Definition handles.h:757
V8_INLINE DirectHandle< T > direct_handle(Tagged< T > object, Isolate *isolate)
too high values may cause the compiler to set high thresholds for inlining to as much as possible avoid inlined allocation of objects that cannot escape trace load stores from virtual maglev objects use TurboFan fast string builder analyze liveness of environment slots and zap dead values trace TurboFan load elimination emit data about basic block usage in builtins to this enable builtin reordering when run mksnapshot flag for emit warnings when applying builtin profile data verify register allocation in TurboFan randomly schedule instructions to stress dependency tracking enable store store elimination in TurboFan rewrite far to near simulate GC compiler thread race related to allow float parameters to be passed in simulator mode JS Wasm Run additional turbo_optimize_inlined_js_wasm_wrappers enable experimental feedback collection in generic lowering enable Turboshaft s WasmLoadElimination enable Turboshaft s low level load elimination for JS enable Turboshaft s escape analysis for string concatenation use enable Turbolev features that we want to ship in the not too far future trace individual Turboshaft reduction steps trace intermediate Turboshaft reduction steps invocation count threshold for early optimization Enables optimizations which favor memory size over execution speed Enables sampling allocation profiler with X as a sample interval min size of a semi the new space consists of two semi spaces max size of the Collect garbage after Collect garbage after keeps maps alive for< n > old space garbage collections print one detailed trace line in name
Definition flags.cc:2086
too high values may cause the compiler to set high thresholds for inlining to as much as possible avoid inlined allocation of objects that cannot escape trace load stores from virtual maglev objects use TurboFan fast string builder analyze liveness of environment slots and zap dead values trace TurboFan load elimination emit data about basic block usage in builtins to this enable builtin reordering when run mksnapshot flag for emit warnings when applying builtin profile data verify register allocation in TurboFan randomly schedule instructions to stress dependency tracking enable store store elimination in TurboFan rewrite far to near simulate GC compiler thread race related to allow float parameters to be passed in simulator mode JS Wasm Run additional turbo_optimize_inlined_js_wasm_wrappers enable experimental feedback collection in generic lowering enable Turboshaft s WasmLoadElimination enable Turboshaft s low level load elimination for JS enable Turboshaft s escape analysis for string concatenation use enable Turbolev features that we want to ship in the not too far future trace individual Turboshaft reduction steps trace intermediate Turboshaft reduction steps invocation count threshold for early optimization Enables optimizations which favor memory size over execution speed Enables sampling allocation profiler with X as a sample interval min size of a semi the new space consists of two semi spaces max size of the Collect garbage after Collect garbage after keeps maps alive for< n > old space garbage collections print one detailed trace line in allocation gc speed threshold for starting incremental marking via a task in percent of available threshold for starting incremental marking immediately in percent of available Use a single schedule for determining a marking schedule between JS and C objects schedules the minor GC task with kUserVisible priority max worker number of concurrent for NumberOfWorkerThreads start background threads that allocate memory concurrent_array_buffer_sweeping use parallel threads to clear weak refs in the atomic pause trace progress of the incremental marking trace object counts and memory usage report a tick only when allocated zone memory changes by this amount TracingFlags::gc_stats TracingFlags::gc_stats track native contexts that are expected to be garbage collected verify heap pointers before and after GC memory reducer runs GC with ReduceMemoryFootprint flag Maximum number of memory reducer GCs scheduled Old gen GC speed is computed directly from gc tracer counters Perform compaction on full GCs based on V8 s default heuristics Perform compaction on every full GC Perform code space compaction when finalizing a full GC with stack Stress GC compaction to flush out bugs with moving objects flush of baseline code when it has not been executed recently Use time base code flushing instead of age Use a progress bar to scan large objects in increments when incremental marking is active force incremental marking for small heaps and run it more often force marking at random points between and force scavenge at random points between and reclaim otherwise unreachable unmodified wrapper objects when possible less compaction in non memory reducing mode use high priority threads for concurrent Marking Test mode only flag It allows an unit test to select evacuation candidates use incremental marking for CppHeap cppheap_concurrent_marking c value for membalancer A special constant to balance between memory and space tradeoff The smaller the more memory it uses enable use of SSE4 instructions if available enable use of AVX VNNI instructions if available enable use of POPCNT instruction if available force all emitted branches to be in long mode(MIPS/PPC only)") DEFINE_BOOL(partial_constant_pool
void Print(Tagged< Object > obj)
Definition objects.h:774
V8_EXPORT_PRIVATE FlagValues v8_flags
V8_INLINE bool IsWasmObject(T obj, Isolate *=nullptr)
Definition objects.h:725
return value
Definition map-inl.h:893
kInterpreterTrampolineOffset script
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
Definition casting.h:150
Local< T > Handle
static constexpr AcquireLoadTag kAcquireLoad
Definition globals.h:2908
Maybe< T > Just(const T &t)
Definition v8-maybe.h:117
std::vector< ValueType > locals_
#define CHECK_IMPLIES(lhs, rhs)
#define CHECK(condition)
Definition logging.h:124
#define DCHECK_NOT_NULL(val)
Definition logging.h:492
#define DCHECK_IMPLIES(v1, v2)
Definition logging.h:493
#define DCHECK_NE(v1, v2)
Definition logging.h:486
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_LT(v1, v2)
Definition logging.h:489
#define DCHECK_EQ(v1, v2)
Definition logging.h:485