v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
v8-debugger.cc
Go to the documentation of this file.
1// Copyright 2016 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 <algorithm>
8
10#include "include/v8-context.h"
11#include "include/v8-function.h"
13#include "include/v8-profiler.h"
14#include "include/v8-util.h"
16#include "src/inspector/protocol/Protocol.h"
27
28namespace v8_inspector {
29
30namespace {
31
32static const size_t kMaxAsyncTaskStacks = 8 * 1024;
33static const size_t kMaxExternalParents = 1 * 1024;
34static const int kNoBreakpointId = 0;
35
36template <typename Map>
37void cleanupExpiredWeakPointers(Map& map) {
38 for (auto it = map.begin(); it != map.end();) {
39 if (it->second.expired()) {
40 it = map.erase(it);
41 } else {
42 ++it;
43 }
44 }
45}
46
47// Allow usages of v8::Object::GetPrototype() for now.
48// TODO(https://crbug.com/333672197): remove.
50
51class MatchPrototypePredicate : public v8::QueryObjectPredicate {
52 public:
53 MatchPrototypePredicate(V8InspectorImpl* inspector,
55 v8::Local<v8::Object> prototype)
56 : m_inspector(inspector), m_context(context), m_prototype(prototype) {}
57
58 bool Filter(v8::Local<v8::Object> object) override {
59 if (object->IsModuleNamespaceObject()) return false;
60 v8::Local<v8::Context> objectContext;
61 if (!v8::debug::GetCreationContext(object).ToLocal(&objectContext)) {
62 return false;
63 }
64 if (objectContext != m_context) return false;
65 if (!m_inspector->client()->isInspectableHeapObject(object)) return false;
66 // Get prototype chain for current object until first visited prototype.
67 for (v8::Local<v8::Value> prototype = object->GetPrototype();
68 prototype->IsObject();
69 prototype = prototype.As<v8::Object>()->GetPrototype()) {
70 if (m_prototype == prototype) return true;
71 }
72 return false;
73 }
74
75 private:
76 V8InspectorImpl* m_inspector;
79};
80
81// Allow usages of v8::Object::GetPrototype() for now.
82// TODO(https://crbug.com/333672197): remove.
84
85} // namespace
86
88 : m_isolate(isolate),
89 m_inspector(inspector),
90 m_enableCount(0),
91 m_ignoreScriptParsedEventsCounter(0),
92 m_continueToLocationBreakpointId(kNoBreakpointId),
93 m_maxAsyncCallStacks(kMaxAsyncTaskStacks),
94 m_maxAsyncCallStackDepth(0),
95 m_maxCallStackSizeToCapture(
96 V8StackTraceImpl::kDefaultMaxCallStackSizeToCapture),
97 m_pauseOnExceptionsState(v8::debug::NoBreakOnException) {}
98
111
113 if (m_enableCount++) return;
119#if V8_ENABLE_WEBASSEMBLY
120 v8::debug::EnterDebuggingForIsolate(m_isolate);
121#endif // V8_ENABLE_WEBASSEMBLY
122}
123
125 if (isPaused()) {
126 bool scheduledOOMBreak = m_scheduledOOMBreak;
127 bool hasAgentAcceptsPause = false;
128
131 } else {
133 m_pausedContextGroupId, [&scheduledOOMBreak, &hasAgentAcceptsPause](
134 V8InspectorSessionImpl* session) {
135 if (session->debuggerAgent()->acceptsPause(scheduledOOMBreak)) {
136 hasAgentAcceptsPause = true;
137 }
138 });
139 if (!hasAgentAcceptsPause)
141 }
142 }
143 if (--m_enableCount) return;
145 m_taskWithScheduledBreak = nullptr;
149 m_pauseOnAsyncCall = false;
150#if V8_ENABLE_WEBASSEMBLY
151 v8::debug::LeaveDebuggingForIsolate(m_isolate);
152#endif // V8_ENABLE_WEBASSEMBLY
157}
158
159bool V8Debugger::isPausedInContextGroup(int contextGroupId) const {
160 return isPaused() && m_pausedContextGroupId == contextGroupId;
161}
162
163bool V8Debugger::enabled() const { return m_enableCount > 0; }
164
165std::vector<std::unique_ptr<V8DebuggerScript>> V8Debugger::getCompiledScripts(
166 int contextGroupId, V8DebuggerAgentImpl* agent) {
167 std::vector<std::unique_ptr<V8DebuggerScript>> result;
169 std::vector<v8::Global<v8::debug::Script>> scripts;
171 for (size_t i = 0; i < scripts.size(); ++i) {
172 v8::Local<v8::debug::Script> script = scripts[i].Get(m_isolate);
173 if (!script->WasCompiled()) continue;
174 if (!script->IsEmbedded()) {
175 int contextId;
176 if (!script->ContextId().To(&contextId)) continue;
177 if (m_inspector->contextGroupId(contextId) != contextGroupId) continue;
178 }
179 result.push_back(V8DebuggerScript::Create(m_isolate, script, false, agent,
180 m_inspector->client()));
181 }
182 return result;
183}
184
193
197
202
204 v8::debug::ExceptionBreakState pauseOnExceptionsState) {
205 DCHECK(enabled());
206 if (m_pauseOnExceptionsState == pauseOnExceptionsState) return;
207 v8::debug::ChangeBreakOnException(m_isolate, pauseOnExceptionsState);
208 m_pauseOnExceptionsState = pauseOnExceptionsState;
209}
210
211void V8Debugger::setPauseOnNextCall(bool pause, int targetContextGroupId) {
212 if (isPaused()) return;
213 DCHECK(targetContextGroupId);
214 if (!pause && m_targetContextGroupId &&
215 m_targetContextGroupId != targetContextGroupId) {
216 return;
217 }
218 if (pause) {
219 bool didHaveBreak = hasScheduledBreakOnNextFunctionCall();
221 if (!didHaveBreak) {
222 m_targetContextGroupId = targetContextGroupId;
224 }
225 } else {
229 }
230 }
231}
232
236
240
241void V8Debugger::breakProgram(int targetContextGroupId) {
243 // Don't allow nested breaks.
244 if (isPaused()) return;
245 DCHECK(targetContextGroupId);
246 m_targetContextGroupId = targetContextGroupId;
248}
249
250void V8Debugger::interruptAndBreak(int targetContextGroupId) {
251 // Don't allow nested breaks.
252 if (isPaused()) return;
253 DCHECK(targetContextGroupId);
254 m_targetContextGroupId = targetContextGroupId;
256 [](v8::Isolate* isolate, void*) {
258 isolate,
260 },
261 nullptr);
262}
263
267
269 bool allAgentsFinishedInstrumentation = true;
272 [&allAgentsFinishedInstrumentation](V8InspectorSessionImpl* session) {
273 if (!session->debuggerAgent()->instrumentationFinished()) {
274 allAgentsFinishedInstrumentation = false;
275 }
276 });
277 if (allAgentsFinishedInstrumentation) {
279 }
280}
281
282void V8Debugger::continueProgram(int targetContextGroupId,
283 bool terminateOnResume) {
284 if (m_pausedContextGroupId != targetContextGroupId) return;
285 if (isPaused()) {
288 } else if (terminateOnResume) {
290
291 v8::HandleScope handles(m_isolate);
292 v8::Local<v8::Context> context =
294 targetContextGroupId);
296
298 } else {
300 }
301 }
302}
303
304void V8Debugger::breakProgramOnAssert(int targetContextGroupId) {
305 if (!enabled()) return;
307 // Don't allow nested breaks.
308 if (isPaused()) return;
309 if (!canBreakProgram()) return;
310 DCHECK(targetContextGroupId);
311 m_targetContextGroupId = targetContextGroupId;
314}
315
316void V8Debugger::stepIntoStatement(int targetContextGroupId,
317 bool breakOnAsyncCall) {
318 DCHECK(isPaused());
319 DCHECK(targetContextGroupId);
320 m_targetContextGroupId = targetContextGroupId;
321 m_pauseOnAsyncCall = breakOnAsyncCall;
323 continueProgram(targetContextGroupId);
324}
325
326void V8Debugger::stepOverStatement(int targetContextGroupId) {
327 DCHECK(isPaused());
328 DCHECK(targetContextGroupId);
329 m_targetContextGroupId = targetContextGroupId;
331 continueProgram(targetContextGroupId);
332}
333
334void V8Debugger::stepOutOfFunction(int targetContextGroupId) {
335 DCHECK(isPaused());
336 DCHECK(targetContextGroupId);
337 m_targetContextGroupId = targetContextGroupId;
339 continueProgram(targetContextGroupId);
340}
341
344 std::unique_ptr<TerminateExecutionCallback> callback) {
346 if (callback) {
347 callback->sendFailure(Response::ServerError(
348 "There is current termination request in progress"));
349 }
350 return;
351 }
355}
356
374
400
407
409 v8::Isolate* isolate, void* data) {
410 DCHECK(data);
411 // Ensure that after every microtask completed callback we remove the
412 // callback regardless of how `terminateExecutionCompletedCallback` behaves.
413 static_cast<v8::MicrotaskQueue*>(data)->RemoveMicrotasksCompletedCallback(
416}
417
419 int targetContextGroupId, V8DebuggerScript* script,
420 std::unique_ptr<protocol::Debugger::Location> location,
421 const String16& targetCallFrames) {
422 DCHECK(isPaused());
423 DCHECK(targetContextGroupId);
424 m_targetContextGroupId = targetContextGroupId;
425 v8::debug::Location v8Location(location->getLineNumber(),
426 location->getColumnNumber(0));
427 if (script->setBreakpoint(String16(), &v8Location,
429 m_continueToLocationTargetCallFrames = targetCallFrames;
431 protocol::Debugger::ContinueToLocation::TargetCallFramesEnum::Any) {
435 }
436 continueProgram(targetContextGroupId);
437 // TODO(kozyatinskiy): Return actual line and column number.
438 return Response::Success();
439 } else {
440 return Response::ServerError("Cannot continue to specified location");
441 }
442}
443
444bool V8Debugger::restartFrame(int targetContextGroupId, int callFrameOrdinal) {
445 DCHECK(isPaused());
446 DCHECK(targetContextGroupId);
447 m_targetContextGroupId = targetContextGroupId;
448
449 if (v8::debug::PrepareRestartFrame(m_isolate, callFrameOrdinal)) {
450 continueProgram(targetContextGroupId);
451 return true;
452 }
453 return false;
454}
455
458 protocol::Debugger::ContinueToLocation::TargetCallFramesEnum::Any) {
459 return true;
460 }
461 std::unique_ptr<V8StackTraceImpl> currentStack = V8StackTraceImpl::capture(
464 protocol::Debugger::ContinueToLocation::TargetCallFramesEnum::Current) {
465 return m_continueToLocationStack->isEqualIgnoringTopFrame(
466 currentStack.get());
467 }
468 return true;
469}
470
478
480 v8::Local<v8::Context> pausedContext, v8::Local<v8::Value> exception,
481 const std::vector<v8::debug::BreakpointId>& breakpointIds,
482 v8::debug::BreakReasons breakReasons,
483 v8::debug::ExceptionType exceptionType, bool isUncaught) {
484 // Don't allow nested breaks.
485 if (isPaused()) return;
486
487 int contextGroupId = m_inspector->contextGroupId(pausedContext);
488 if (m_targetContextGroupId && contextGroupId != m_targetContextGroupId) {
490 return;
491 }
492
501
504 m_pauseOnAsyncCall = false;
505 m_taskWithScheduledBreak = nullptr;
508
509 bool scheduledOOMBreak = m_scheduledOOMBreak;
510 DCHECK(scheduledOOMBreak ==
512 bool hasAgents = false;
513
515 contextGroupId,
516 [&scheduledOOMBreak, &hasAgents](V8InspectorSessionImpl* session) {
517 if (session->debuggerAgent()->acceptsPause(scheduledOOMBreak))
518 hasAgents = true;
519 });
520 if (!hasAgents) return;
521
522 if (breakpointIds.size() == 1 &&
523 breakpointIds[0] == m_continueToLocationBreakpointId) {
524 v8::Context::Scope contextScope(pausedContext);
525 if (!shouldContinueToCurrentLocation()) return;
526 }
528
529 DCHECK(contextGroupId);
530 m_pausedContextGroupId = contextGroupId;
531
533 contextGroupId,
534 [&pausedContext, &exception, &breakpointIds, &exceptionType, &isUncaught,
535 &scheduledOOMBreak, &breakReasons](V8InspectorSessionImpl* session) {
536 if (session->debuggerAgent()->acceptsPause(scheduledOOMBreak)) {
537 session->debuggerAgent()->didPause(
538 InspectedContext::contextId(pausedContext), exception,
539 breakpointIds, exceptionType, isUncaught, breakReasons);
540 }
541 });
542 {
543 v8::Context::Scope scope(pausedContext);
544
546 contextGroupId, [](V8InspectorSessionImpl* session) {
547 if (session->heapProfilerAgent()) {
549 }
550 });
551
552 m_inspector->client()->runMessageLoopOnPause(contextGroupId);
554 }
555 m_inspector->forEachSession(contextGroupId,
556 [](V8InspectorSessionImpl* session) {
557 if (session->debuggerAgent()->enabled()) {
558 session->debuggerAgent()->clearBreakDetails();
559 session->debuggerAgent()->didContinue();
560 }
561 });
562
564 m_scheduledOOMBreak = false;
565}
566
567namespace {
568
569size_t HeapLimitForDebugging(size_t initial_heap_limit) {
570 const size_t kDebugHeapSizeFactor = 4;
571 size_t max_limit = std::numeric_limits<size_t>::max() / 4;
572 return std::min(max_limit, initial_heap_limit * kDebugHeapSizeFactor);
573}
574
575} // anonymous namespace
576
577size_t V8Debugger::nearHeapLimitCallback(void* data, size_t current_heap_limit,
578 size_t initial_heap_limit) {
579 V8Debugger* thisPtr = static_cast<V8Debugger*>(data);
580 thisPtr->m_originalHeapLimit = current_heap_limit;
581 thisPtr->m_scheduledOOMBreak = true;
582 v8::Local<v8::Context> context =
584 thisPtr->m_targetContextGroupId =
585 context.IsEmpty() ? 0 : thisPtr->m_inspector->contextGroupId(context);
586 thisPtr->m_isolate->RequestInterrupt(
587 [](v8::Isolate* isolate, void*) {
588 // There's a redundancy between setting `m_scheduledOOMBreak` and
589 // passing the reason along in `BreakRightNow`. The
590 // `m_scheduledOOMBreak` is used elsewhere, so we cannot remove it. And
591 // for being explicit, we still pass the break reason along.
594 },
595 nullptr);
596 return HeapLimitForDebugging(initial_heap_limit);
597}
598
600 bool is_live_edited, bool has_compile_error) {
601 if (m_ignoreScriptParsedEventsCounter != 0) return;
602
603 int contextId;
604 if (!script->ContextId().To(&contextId)) return;
605
606 v8::Isolate* isolate = m_isolate;
608
610 m_inspector->contextGroupId(contextId),
611 [isolate, &script, has_compile_error, is_live_edited,
612 client](V8InspectorSessionImpl* session) {
613 auto agent = session->debuggerAgent();
614 if (!agent->enabled()) return;
615 agent->didParseSource(
616 V8DebuggerScript::Create(isolate, script, is_live_edited, agent,
617 client),
618 !has_compile_error);
619 });
620}
621
623 v8::Local<v8::Context> pausedContext,
624 v8::debug::BreakpointId instrumentationId) {
625 // Don't allow nested breaks.
627
628 int contextGroupId = m_inspector->contextGroupId(pausedContext);
629 bool hasAgents = false;
631 contextGroupId, [&hasAgents](V8InspectorSessionImpl* session) {
632 if (session->debuggerAgent()->acceptsPause(false /* isOOMBreak */))
633 hasAgents = true;
634 });
636
637 m_pausedContextGroupId = contextGroupId;
640 contextGroupId, [instrumentationId](V8InspectorSessionImpl* session) {
641 if (session->debuggerAgent()->acceptsPause(false /* isOOMBreak */)) {
643 instrumentationId);
644 }
645 });
646 {
647 v8::Context::Scope scope(pausedContext);
649 }
650 bool requestedPauseAfterInstrumentation =
652
656
657 hasAgents = false;
659 contextGroupId, [&hasAgents](V8InspectorSessionImpl* session) {
660 if (session->debuggerAgent()->enabled())
661 session->debuggerAgent()->didContinue();
662 if (session->debuggerAgent()->acceptsPause(false /* isOOMBreak */))
663 hasAgents = true;
664 });
665 if (!hasAgents) {
667 } else if (requestedPauseAfterInstrumentation) {
669 } else {
671 }
672}
673
675 v8::Local<v8::Context> pausedContext,
676 const std::vector<v8::debug::BreakpointId>& break_points_hit,
677 v8::debug::BreakReasons reasons) {
678 handleProgramBreak(pausedContext, v8::Local<v8::Value>(), break_points_hit,
679 reasons);
680}
681
683 v8::Local<v8::Value> exception,
684 v8::Local<v8::Value> promise, bool isUncaught,
685 v8::debug::ExceptionType exceptionType) {
686 std::vector<v8::debug::BreakpointId> break_points_hit;
688 pausedContext, exception, break_points_hit,
690 exceptionType, isUncaught);
691}
692
695 const v8::debug::Location& end) {
696 int contextId;
697 if (!script->ContextId().To(&contextId)) return false;
698 bool hasAgents = false;
699 bool allBlackboxed = true;
700 String16 scriptId = String16::fromInteger(script->Id());
702 m_inspector->contextGroupId(contextId),
703 [&hasAgents, &allBlackboxed, &scriptId, &start,
704 &end](V8InspectorSessionImpl* session) {
705 V8DebuggerAgentImpl* agent = session->debuggerAgent();
706 if (!agent->enabled()) return;
707 hasAgents = true;
708 allBlackboxed &= agent->isFunctionBlackboxed(scriptId, start, end);
709 });
710 return hasAgents && allBlackboxed;
711}
712
714 int column) {
715 int contextId;
716 if (!script->ContextId().To(&contextId)) return false;
717
718 bool hasAgents = false;
719 bool allShouldBeSkipped = true;
720 String16 scriptId = String16::fromInteger(script->Id());
722 m_inspector->contextGroupId(contextId),
723 [&hasAgents, &allShouldBeSkipped, &scriptId, line,
724 column](V8InspectorSessionImpl* session) {
725 V8DebuggerAgentImpl* agent = session->debuggerAgent();
726 if (!agent->enabled()) return;
727 hasAgents = true;
728 const bool skip = agent->shouldBeSkipped(scriptId, line, column);
729 allShouldBeSkipped &= skip;
730 });
731 return hasAgents && allShouldBeSkipped;
732}
733
735 v8::Local<v8::Context> context, v8::debug::BreakpointId breakpoint_id,
736 bool exception_thrown, v8::Local<v8::Value> exception) {
737 if (!exception_thrown || exception.IsEmpty()) return;
738
739 v8::Local<v8::Message> message =
741 v8::ScriptOrigin origin = message->GetScriptOrigin();
742 String16 url;
743 if (origin.ResourceName()->IsString()) {
744 url = toProtocolString(isolate(), origin.ResourceName().As<v8::String>());
745 }
746 // The message text is prepended to the exception text itself so we don't
747 // need to get it from the v8::Message.
748 StringView messageText;
749 StringView detailedMessage;
751 context, messageText, exception, detailedMessage, toStringView(url),
752 message->GetLineNumber(context).FromMaybe(0),
753 message->GetStartColumn() + 1, createStackTrace(message->GetStackTrace()),
754 origin.ScriptId());
755}
756
758 int id, bool isBlackboxed) {
759 // Async task events from Promises are given misaligned pointers to prevent
760 // from overlapping with other Blink task identifiers.
761 void* task = reinterpret_cast<void*>(id * 2 + 1);
762 switch (type) {
764 asyncTaskScheduledForStack(toStringView("Promise.then"), task, false);
765 if (!isBlackboxed) asyncTaskCandidateForStepping(task);
766 break;
768 asyncTaskScheduledForStack(toStringView("Promise.catch"), task, false);
769 if (!isBlackboxed) asyncTaskCandidateForStepping(task);
770 break;
772 asyncTaskScheduledForStack(toStringView("Promise.finally"), task, false);
773 if (!isBlackboxed) asyncTaskCandidateForStepping(task);
774 break;
778 break;
782 break;
784 asyncTaskScheduledForStack(toStringView("await"), task, false, true);
785 break;
788 break;
789 }
790}
791
792std::shared_ptr<AsyncStackTrace> V8Debugger::currentAsyncParent() {
793 return m_currentAsyncParent.empty() ? nullptr : m_currentAsyncParent.back();
794}
795
800
804 std::unique_ptr<v8::debug::ScopeIterator> iterator;
805 switch (kind) {
806 case FUNCTION:
808 m_isolate, value.As<v8::Function>());
809 break;
810 case GENERATOR:
813 if (!generatorObject->IsSuspended()) return v8::MaybeLocal<v8::Value>();
814
816 m_isolate, value.As<v8::Object>());
817 break;
818 }
819 if (!iterator) return v8::MaybeLocal<v8::Value>();
821 if (!result->SetPrototypeV2(context, v8::Null(m_isolate)).FromMaybe(false)) {
823 }
824
825 for (; !iterator->Done(); iterator->Advance()) {
830 m_isolate, iterator->GetFunctionDebugName());
831 String16 description;
832 if (nameSuffix.length()) nameSuffix = " (" + nameSuffix + ")";
833 switch (iterator->GetType()) {
835 description = "Global" + nameSuffix;
836 break;
838 description = "Local" + nameSuffix;
839 break;
841 description = "With Block" + nameSuffix;
842 break;
844 description = "Closure" + nameSuffix;
845 break;
847 description = "Catch" + nameSuffix;
848 break;
850 description = "Block" + nameSuffix;
851 break;
853 description = "Script" + nameSuffix;
854 break;
856 description = "Eval" + nameSuffix;
857 break;
859 description = "Module" + nameSuffix;
860 break;
862 description = "Wasm Expression Stack" + nameSuffix;
863 break;
864 }
865 v8::Local<v8::Object> object = iterator->GetObject();
866 createDataProperty(context, scope,
867 toV8StringInternalized(m_isolate, "description"),
868 toV8String(m_isolate, description));
869 createDataProperty(context, scope,
870 toV8StringInternalized(m_isolate, "object"), object);
871 createDataProperty(context, result, result->Length(), scope);
872 }
875 return result;
876}
877
882
887
889 v8::Local<v8::Context> context, v8::Local<v8::Value> collection) {
890 v8::Isolate* isolate = context->GetIsolate();
892 bool isKeyValue = false;
893 if (!collection->IsObject() || !collection.As<v8::Object>()
894 ->PreviewEntries(&isKeyValue)
895 .ToLocal(&entries)) {
897 }
898
899 v8::Local<v8::Array> wrappedEntries = v8::Array::New(isolate);
900 CHECK(!isKeyValue || wrappedEntries->Length() % 2 == 0);
901 if (!wrappedEntries->SetPrototypeV2(context, v8::Null(isolate))
902 .FromMaybe(false))
904 for (uint32_t i = 0; i < entries->Length(); i += isKeyValue ? 2 : 1) {
906 if (!entries->Get(context, i).ToLocal(&item)) continue;
908 if (isKeyValue && !entries->Get(context, i + 1).ToLocal(&value)) continue;
909 v8::Local<v8::Object> wrapper = v8::Object::New(isolate);
910 if (!wrapper->SetPrototypeV2(context, v8::Null(isolate)).FromMaybe(false))
911 continue;
913 context, wrapper,
914 toV8StringInternalized(isolate, isKeyValue ? "key" : "value"), item);
915 if (isKeyValue) {
916 createDataProperty(context, wrapper,
917 toV8StringInternalized(isolate, "value"), value);
918 }
919 if (!addInternalObject(context, wrapper, V8InternalValueType::kEntry))
920 continue;
921 createDataProperty(context, wrappedEntries, wrappedEntries->Length(),
922 wrapper);
923 }
924 return wrappedEntries;
925}
926
929 if (!receiver->IsObject()) {
931 }
932 v8::Isolate* isolate = context->GetIsolate();
933 v8::LocalVector<v8::Value> names(isolate);
934 v8::LocalVector<v8::Value> values(isolate);
935 int filter =
937 if (!v8::debug::GetPrivateMembers(context, receiver.As<v8::Object>(), filter,
938 &names, &values) ||
939 names.empty()) {
941 }
942
944 if (!result->SetPrototypeV2(context, v8::Null(isolate)).FromMaybe(false))
946 for (uint32_t i = 0; i < names.size(); i++) {
947 v8::Local<v8::Value> name = names[i];
948 v8::Local<v8::Value> value = values[i];
949 DCHECK(value->IsFunction());
950 v8::Local<v8::Object> wrapper = v8::Object::New(isolate);
951 if (!wrapper->SetPrototypeV2(context, v8::Null(isolate)).FromMaybe(false))
952 continue;
953 createDataProperty(context, wrapper,
954 toV8StringInternalized(isolate, "name"), name);
955 createDataProperty(context, wrapper,
956 toV8StringInternalized(isolate, "value"), value);
957 if (!addInternalObject(context, wrapper,
959 continue;
960 createDataProperty(context, result, result->Length(), wrapper);
961 }
962
963 if (!addInternalObject(context, result,
966 return result;
967}
968
971 v8::Local<v8::Array> properties;
972 if (!v8::debug::GetInternalProperties(m_isolate, value).ToLocal(&properties))
975 if (collectionsEntries(context, value).ToLocal(&entries)) {
976 createDataProperty(context, properties, properties->Length(),
977 toV8StringInternalized(m_isolate, "[[Entries]]"));
978 createDataProperty(context, properties, properties->Length(), entries);
979 }
980
981 if (value->IsGeneratorObject()) {
983 if (generatorScopes(context, value).ToLocal(&scopes)) {
984 createDataProperty(context, properties, properties->Length(),
985 toV8StringInternalized(m_isolate, "[[Scopes]]"));
986 createDataProperty(context, properties, properties->Length(), scopes);
987 }
988 }
989 if (value->IsFunction()) {
990 v8::Local<v8::Function> function = value.As<v8::Function>();
992 if (functionScopes(context, function).ToLocal(&scopes)) {
993 createDataProperty(context, properties, properties->Length(),
994 toV8StringInternalized(m_isolate, "[[Scopes]]"));
995 createDataProperty(context, properties, properties->Length(), scopes);
996 }
997 }
998 v8::Local<v8::Array> private_methods;
999 if (privateMethods(context, value).ToLocal(&private_methods)) {
1000 createDataProperty(context, properties, properties->Length(),
1001 toV8StringInternalized(m_isolate, "[[PrivateMethods]]"));
1002 createDataProperty(context, properties, properties->Length(),
1003 private_methods);
1004 }
1005 return properties;
1006}
1007
1009 v8::Local<v8::Object> prototype) {
1010 v8::Isolate* isolate = context->GetIsolate();
1011 std::vector<v8::Global<v8::Object>> v8_objects;
1012 MatchPrototypePredicate predicate(m_inspector, context, prototype);
1013 isolate->GetHeapProfiler()->QueryObjects(context, &predicate, &v8_objects);
1014
1015 v8::MicrotasksScope microtasksScope(context,
1018 m_inspector->isolate(), static_cast<int>(v8_objects.size()));
1019 for (size_t i = 0; i < v8_objects.size(); ++i) {
1020 createDataProperty(context, resultArray, static_cast<int>(i),
1021 v8_objects[i].Get(isolate));
1022 }
1023 return resultArray;
1024}
1025
1026std::unique_ptr<V8StackTraceImpl> V8Debugger::createStackTrace(
1027 v8::Local<v8::StackTrace> v8StackTrace) {
1030}
1031
1033 if (depth <= 0)
1034 m_maxAsyncCallStackDepthMap.erase(agent);
1035 else
1036 m_maxAsyncCallStackDepthMap[agent] = depth;
1037
1038 int maxAsyncCallStackDepth = 0;
1039 for (const auto& pair : m_maxAsyncCallStackDepthMap) {
1040 if (pair.second > maxAsyncCallStackDepth)
1041 maxAsyncCallStackDepth = pair.second;
1042 }
1043
1044 if (m_maxAsyncCallStackDepth == maxAsyncCallStackDepth) return;
1045 // TODO(dgozman): ideally, this should be per context group.
1046 m_maxAsyncCallStackDepth = maxAsyncCallStackDepth;
1049 if (!maxAsyncCallStackDepth) allAsyncTasksCanceled();
1051 maxAsyncCallStackDepth ? this : nullptr);
1052}
1053
1055 int size) {
1056 if (size < 0) {
1057 m_maxCallStackSizeToCaptureMap.erase(agent);
1058 } else {
1060 }
1061
1062 // The following logic is a bit complicated to decipher because we
1063 // want to retain backwards compatible semantics:
1064 //
1065 // (a) When no `Runtime` domain is enabled, we stick to the default
1066 // maximum call stack size, but don't let V8 collect stack traces
1067 // for uncaught exceptions.
1068 // (b) When `Runtime` is enabled for at least one front-end, we compute
1069 // the maximum of the requested maximum call stack sizes of all the
1070 // front-ends whose `Runtime` domains are enabled (which might be 0),
1071 // and ask V8 to collect stack traces for uncaught exceptions.
1072 //
1073 // The latter allows performance test automation infrastructure to drive
1074 // browser via `Runtime` domain while still minimizing the performance
1075 // overhead of having the inspector attached - see the relevant design
1076 // document https://bit.ly/v8-cheaper-inspector-stack-traces for more
1077 if (m_maxCallStackSizeToCaptureMap.empty()) {
1081 } else {
1083 for (auto const& pair : m_maxCallStackSizeToCaptureMap) {
1084 if (m_maxCallStackSizeToCapture < pair.second)
1085 m_maxCallStackSizeToCapture = pair.second;
1086 }
1089 }
1090}
1091
1092void V8Debugger::asyncParentFor(int stackTraceId,
1093 std::shared_ptr<AsyncStackTrace>* asyncParent,
1094 V8StackTraceId* externalParent) const {
1095 auto it = m_asyncParents.find(stackTraceId);
1096 if (it != m_asyncParents.end()) {
1097 *asyncParent = it->second.lock();
1098 if (*asyncParent && (*asyncParent)->isEmpty()) {
1099 *asyncParent = (*asyncParent)->parent().lock();
1100 }
1101 } else {
1102 auto externalIt = std::find_if(
1103 m_externalParents.begin(), m_externalParents.end(),
1104 [stackTraceId](const auto& p) { return p.first == stackTraceId; });
1105 if (externalIt != m_externalParents.end()) {
1106 *externalParent = externalIt->second;
1107 }
1108 }
1109 DCHECK_IMPLIES(!externalParent->IsInvalid(), !*asyncParent);
1110 DCHECK_IMPLIES(*asyncParent, externalParent->IsInvalid());
1111}
1112
1113std::shared_ptr<AsyncStackTrace> V8Debugger::stackTraceFor(
1114 int contextGroupId, const V8StackTraceId& id) {
1115 if (debuggerIdFor(contextGroupId).pair() != id.debugger_id) return nullptr;
1116 auto it = m_storedStackTraces.find(id.id);
1117 if (it == m_storedStackTraces.end()) return nullptr;
1118 return it->second.lock();
1119}
1120
1122 const StringView& description) {
1124
1126 int contextGroupId = currentContextGroupId();
1127 if (!contextGroupId) return V8StackTraceId();
1128
1129 std::shared_ptr<AsyncStackTrace> asyncStack =
1130 AsyncStackTrace::capture(this, toString16(description));
1131 if (!asyncStack) return V8StackTraceId();
1132
1133 uintptr_t id = AsyncStackTrace::store(this, asyncStack);
1134
1135 m_allAsyncStacks.push_back(std::move(asyncStack));
1137
1138 bool shouldPause =
1139 m_pauseOnAsyncCall && contextGroupId == m_targetContextGroupId;
1140 if (shouldPause) {
1141 m_pauseOnAsyncCall = false;
1142 v8::debug::ClearStepping(m_isolate); // Cancel step into.
1143 }
1144 return V8StackTraceId(id, debuggerIdFor(contextGroupId).pair(), shouldPause);
1145}
1146
1148 std::shared_ptr<AsyncStackTrace> asyncStack) {
1149 uintptr_t id = ++m_lastStackTraceId;
1150 m_storedStackTraces[id] = asyncStack;
1151 return id;
1152}
1153
1155 if (!m_maxAsyncCallStackDepth || parent.IsInvalid()) return;
1156 m_currentExternalParent.push_back(parent);
1157 m_currentAsyncParent.emplace_back();
1158 m_currentTasks.push_back(reinterpret_cast<void*>(parent.id));
1159
1160 if (!parent.should_pause) return;
1161 bool didHaveBreak = hasScheduledBreakOnNextFunctionCall();
1163 if (didHaveBreak) return;
1166}
1167
1169 if (!m_maxAsyncCallStackDepth || m_currentExternalParent.empty()) return;
1170 m_currentExternalParent.pop_back();
1171 m_currentAsyncParent.pop_back();
1172 DCHECK(m_currentTasks.back() == reinterpret_cast<void*>(parent.id));
1173 m_currentTasks.pop_back();
1174
1175 if (!parent.should_pause) return;
1179}
1180
1181void V8Debugger::asyncTaskScheduled(const StringView& taskName, void* task,
1182 bool recurring) {
1183 asyncTaskScheduledForStack(taskName, task, recurring);
1185}
1186
1191
1196
1201
1202#ifdef V8_USE_PERFETTO
1203namespace {
1204void AddTraceDataWithSample(v8::Isolate* isolate,
1205 perfetto::TracedValue context) {
1206 uint64_t trace_id = v8::tracing::TraceId();
1207 auto dict = std::move(context).WriteDictionary();
1208 v8::CpuProfiler::CpuProfiler::CollectSample(isolate, trace_id);
1209 dict.Add("sampleTraceId", trace_id);
1210}
1211} // namespace
1212#endif // V8_USE_PERFETTO
1213
1215 void* task, bool recurring,
1216 bool skipTopFrame) {
1217#ifdef V8_USE_PERFETTO
1218 TRACE_EVENT(TRACE_DISABLED_BY_DEFAULT("v8.inspector"),
1219 "v8::Debugger::AsyncTaskScheduled", "taskName",
1220 TRACE_STR_COPY(toString16(taskName).utf8().c_str()),
1221 perfetto::Flow::ProcessScoped(reinterpret_cast<uintptr_t>(task)),
1222 "data", [isolate = m_isolate](perfetto::TracedValue context) {
1223 AddTraceDataWithSample(isolate, std::move(context));
1224 });
1225#endif // V8_USE_PERFETTO
1226 if (!m_maxAsyncCallStackDepth) return;
1228 std::shared_ptr<AsyncStackTrace> asyncStack =
1229 AsyncStackTrace::capture(this, toString16(taskName), skipTopFrame);
1230 if (asyncStack) {
1231 m_asyncTaskStacks[task] = asyncStack;
1232 if (recurring) m_recurringTasks.insert(task);
1233 m_allAsyncStacks.push_back(std::move(asyncStack));
1235 }
1236}
1237
1239#ifdef V8_USE_PERFETTO
1240 TRACE_EVENT(TRACE_DISABLED_BY_DEFAULT("v8.inspector"),
1241 "v8::Debugger::AsyncTaskCanceled",
1242 perfetto::Flow::ProcessScoped(reinterpret_cast<uintptr_t>(task)),
1243 "data", [isolate = m_isolate](perfetto::TracedValue context) {
1244 AddTraceDataWithSample(isolate, std::move(context));
1245 });
1246#endif // V8_USE_PERFETTO
1247 if (!m_maxAsyncCallStackDepth) return;
1248 m_asyncTaskStacks.erase(task);
1249 m_recurringTasks.erase(task);
1250}
1251
1253#ifdef V8_USE_PERFETTO
1254 TRACE_EVENT_BEGIN(
1255 TRACE_DISABLED_BY_DEFAULT("v8.inspector"), "v8::Debugger::AsyncTaskRun",
1256 perfetto::Flow::ProcessScoped(reinterpret_cast<uintptr_t>(task)), "data",
1257 [isolate = m_isolate](perfetto::TracedValue context) {
1258 AddTraceDataWithSample(isolate, std::move(context));
1259 });
1260#endif // V8_USE_PERFETTO
1261
1262 if (!m_maxAsyncCallStackDepth) return;
1263 // Needs to support following order of events:
1264 // - asyncTaskScheduled
1265 // <-- attached here -->
1266 // - asyncTaskStarted
1267 // - asyncTaskCanceled <-- canceled before finished
1268 // <-- async stack requested here -->
1269 // - asyncTaskFinished
1270 m_currentTasks.push_back(task);
1271 AsyncTaskToStackTrace::iterator stackIt = m_asyncTaskStacks.find(task);
1272 if (stackIt != m_asyncTaskStacks.end() && !stackIt->second.expired()) {
1273 std::shared_ptr<AsyncStackTrace> stack(stackIt->second);
1274 m_currentAsyncParent.push_back(stack);
1275 } else {
1276 m_currentAsyncParent.emplace_back();
1277 }
1278 m_currentExternalParent.emplace_back();
1279}
1280
1282#ifdef V8_USE_PERFETTO
1284 "v8::Debugger::AsyncTaskRun");
1285#endif // V8_USE_PERFETTO
1286 if (!m_maxAsyncCallStackDepth) return;
1287 // We could start instrumenting half way and the stack is empty.
1288 if (m_currentTasks.empty()) return;
1289 DCHECK(m_currentTasks.back() == task);
1290 m_currentTasks.pop_back();
1291
1292 m_currentAsyncParent.pop_back();
1293 m_currentExternalParent.pop_back();
1294
1295 if (m_recurringTasks.find(task) == m_recurringTasks.end()) {
1297 }
1298}
1299
1301 if (!m_pauseOnAsyncCall) return;
1302 int contextGroupId = currentContextGroupId();
1303 if (contextGroupId != m_targetContextGroupId) return;
1305 m_pauseOnAsyncCall = false;
1306 v8::debug::ClearStepping(m_isolate); // Cancel step into.
1307}
1308
1310 // TODO(kozyatinskiy): we should search task in async chain to support
1311 // blackboxing.
1312 if (task != m_taskWithScheduledBreak) return;
1313 bool didHaveBreak = hasScheduledBreakOnNextFunctionCall();
1315 if (didHaveBreak) return;
1318}
1319
1327
1331
1333 auto async_stack = currentAsyncParent();
1334 if (async_stack) {
1335 m_asyncParents.emplace(id, async_stack);
1336 }
1337 auto externalParent = currentExternalParent();
1338 if (!externalParent.IsInvalid()) {
1339 m_externalParents.push_back(std::make_pair(id, externalParent));
1340 }
1341}
1342
1344 m_asyncTaskStacks.clear();
1345 m_recurringTasks.clear();
1346 m_currentAsyncParent.clear();
1348 m_currentTasks.clear();
1349 m_currentAsyncParent.clear();
1350 m_externalParents.clear();
1351
1352 m_allAsyncStacks.clear();
1353}
1354
1358
1363
1364std::unique_ptr<V8StackTraceImpl> V8Debugger::captureStackTrace(
1365 bool fullStack) {
1366 int contextGroupId = currentContextGroupId();
1367 if (!contextGroupId) return nullptr;
1368
1369 int stackSize = 1;
1370 if (fullStack) {
1372 } else {
1374 contextGroupId, [this, &stackSize](V8InspectorSessionImpl* session) {
1375 if (session->runtimeAgent()->enabled())
1376 stackSize = maxCallStackSizeToCapture();
1377 });
1378 }
1379 return V8StackTraceImpl::capture(this, stackSize);
1380}
1381
1387
1389 if (m_allAsyncStacks.size() <= m_maxAsyncCallStacks) return;
1390 size_t halfOfLimitRoundedUp =
1392 while (m_allAsyncStacks.size() > halfOfLimitRoundedUp) {
1393 m_allAsyncStacks.pop_front();
1394 }
1395 cleanupExpiredWeakPointers(m_asyncTaskStacks);
1396 cleanupExpiredWeakPointers(m_cachedStackFrames);
1397 cleanupExpiredWeakPointers(m_asyncParents);
1398 cleanupExpiredWeakPointers(m_storedStackTraces);
1399 for (auto it = m_recurringTasks.begin(); it != m_recurringTasks.end();) {
1400 if (m_asyncTaskStacks.find(*it) == m_asyncTaskStacks.end()) {
1401 it = m_recurringTasks.erase(it);
1402 } else {
1403 ++it;
1404 }
1405 }
1406 if (m_externalParents.size() > kMaxExternalParents) {
1407 size_t halfOfExternalParents = (m_externalParents.size() + 1) / 2;
1408 while (m_externalParents.size() > halfOfExternalParents) {
1409 m_externalParents.pop_front();
1410 }
1411 }
1412}
1413
1414std::shared_ptr<StackFrame> V8Debugger::symbolize(
1415 v8::Local<v8::StackFrame> v8Frame) {
1416 int scriptId = v8Frame->GetScriptId();
1417 auto location = v8Frame->GetLocation();
1418 int lineNumber = location.GetLineNumber();
1419 int columnNumber = location.GetColumnNumber();
1420 CachedStackFrameKey key{scriptId, lineNumber, columnNumber};
1421 auto functionName = toProtocolString(isolate(), v8Frame->GetFunctionName());
1422 auto it = m_cachedStackFrames.find(key);
1423 std::shared_ptr<StackFrame> stackFrame;
1424 if (it != m_cachedStackFrames.end() && (stackFrame = it->second.lock())) {
1425 if (stackFrame->functionName() == functionName) {
1426 DCHECK_EQ(
1427 stackFrame->sourceURL(),
1428 toProtocolString(isolate(), v8Frame->GetScriptNameOrSourceURL()));
1429 return stackFrame;
1430 }
1431 }
1432 auto sourceURL =
1433 toProtocolString(isolate(), v8Frame->GetScriptNameOrSourceURL());
1434 auto hasSourceURLComment =
1435 v8Frame->GetScriptName() != v8Frame->GetScriptNameOrSourceURL();
1436 stackFrame = std::make_shared<StackFrame>(std::move(functionName), scriptId,
1437 std::move(sourceURL), lineNumber,
1438 columnNumber, hasSourceURLComment);
1439 m_cachedStackFrames.emplace(key, stackFrame);
1440 return stackFrame;
1441}
1442
1448
1450 auto it = m_contextGroupIdToDebuggerId.find(contextGroupId);
1451 if (it != m_contextGroupIdToDebuggerId.end()) return it->second;
1452 internal::V8DebuggerId debuggerId =
1455 it, std::make_pair(contextGroupId, debuggerId));
1456 return debuggerId;
1457}
1458
1460 v8::Local<v8::Object> object,
1461 V8InternalValueType type) {
1462 int contextId = InspectedContext::contextId(context);
1463 InspectedContext* inspectedContext = m_inspector->getContext(contextId);
1464 return inspectedContext ? inspectedContext->addInternalObject(object, type)
1465 : false;
1466}
1467
1469 fprintf(stdout, "Async stacks count: %zu\n", m_allAsyncStacks.size());
1470 fprintf(stdout, "Scheduled async tasks: %zu\n", m_asyncTaskStacks.size());
1471 fprintf(stdout, "Recurring async tasks: %zu\n", m_recurringTasks.size());
1472 fprintf(stdout, "\n");
1473}
1474
1479
1480} // namespace v8_inspector
union v8::internal::@341::BuiltinMetadata::KindSpecificData data
Builtins::Kind kind
Definition builtins.cc:40
static Local< Array > New(Isolate *isolate, int length=0)
Definition api.cc:8119
MicrotaskQueue * GetMicrotaskQueue()
Definition api.cc:7181
void SetCaptureStackTraceForUncaughtExceptions(bool capture, int frame_limit=10, StackTrace::StackTraceOptions options=StackTrace::kOverview)
Definition api.cc:10883
void RemoveNearHeapLimitCallback(NearHeapLimitCallback callback, size_t heap_limit)
Definition api.cc:10812
void RemoveCallCompletedCallback(CallCompletedCallback callback)
Definition api.cc:10467
void CancelTerminateExecution()
Definition api.cc:9898
void AddCallCompletedCallback(CallCompletedCallback callback)
Definition api.cc:10461
void RequestInterrupt(InterruptCallback callback, void *data)
Definition api.cc:9904
Local< Context > GetEnteredOrMicrotaskContext()
Definition api.cc:9765
void RestoreOriginalHeapLimit()
Definition api.cc:10667
void TerminateExecution()
Definition api.cc:9888
void AddNearHeapLimitCallback(NearHeapLimitCallback callback, void *data)
Definition api.cc:10806
Local< Context > GetCurrentContext()
Definition api.cc:9756
bool InContext()
Definition api.cc:9746
V8_INLINE Local< S > As() const
virtual void AddMicrotasksCompletedCallback(MicrotasksCompletedCallbackWithData callback, void *data=nullptr)=0
virtual void RemoveMicrotasksCompletedCallback(MicrotasksCompletedCallbackWithData callback, void *data=nullptr)=0
static Local< Object > New(Isolate *isolate)
Definition api.cc:7756
MaybeLocal< Array > PreviewEntries(bool *is_key_value)
Definition api.cc:11182
V8_INLINE Local< T > Get(Isolate *isolate) const
V8_INLINE void SetWeak(P *parameter, typename WeakCallbackInfo< P >::Callback callback, WeakCallbackType type)
V8_INLINE int ScriptId() const
Definition v8-message.h:214
V8_INLINE Local< Value > ResourceName() const
Definition v8-message.h:204
V8_INLINE bool IsString() const
Definition v8-value.h:642
constexpr void Add(E element)
Definition enum-set.h:50
constexpr bool contains(E element) const
Definition enum-set.h:35
static v8::Local< debug::GeneratorObject > Cast(v8::Local< v8::Value > value)
static std::unique_ptr< ScopeIterator > CreateForFunction(v8::Isolate *isolate, v8::Local< v8::Function > func)
static std::unique_ptr< ScopeIterator > CreateForGeneratorObject(v8::Isolate *isolate, v8::Local< v8::Object > generator)
static std::shared_ptr< AsyncStackTrace > capture(V8Debugger *, const String16 &description, bool skipTopFrame=false)
static uintptr_t store(V8Debugger *debugger, std::shared_ptr< AsyncStackTrace > stack)
bool addInternalObject(v8::Local< v8::Object > object, V8InternalValueType type)
size_t length() const
Definition string-16.h:58
static String16 fromInteger(int)
Definition string-16.cc:71
void didPauseOnInstrumentation(v8::debug::BreakpointId instrumentationId)
void didPause(int contextId, v8::Local< v8::Value > exception, const std::vector< v8::debug::BreakpointId > &hitBreakpoints, v8::debug::ExceptionType exceptionType, bool isUncaught, v8::debug::BreakReasons breakReasons)
static std::unique_ptr< V8DebuggerScript > Create(v8::Isolate *isolate, v8::Local< v8::debug::Script > script, bool isLiveEdit, V8DebuggerAgentImpl *agent, V8InspectorClient *client)
void terminateExecution(v8::Local< v8::Context > context, std::unique_ptr< TerminateExecutionCallback > callback)
static void terminateExecutionCompletedCallbackIgnoringData(v8::Isolate *isolate, void *)
std::unique_ptr< V8StackTraceImpl > createStackTrace(v8::Local< v8::StackTrace >)
v8::debug::ExceptionBreakState getPauseOnExceptionsState()
std::shared_ptr< StackFrame > symbolize(v8::Local< v8::StackFrame > v8Frame)
std::shared_ptr< AsyncStackTrace > stackTraceFor(int contextGroupId, const V8StackTraceId &id)
v8::MaybeLocal< v8::Value > generatorScopes(v8::Local< v8::Context >, v8::Local< v8::Value >)
void asyncTaskCanceledForStack(void *task)
bool isPausedInContextGroup(int contextGroupId) const
void quitMessageLoopIfAgentsFinishedInstrumentation()
std::unordered_map< CachedStackFrameKey, std::weak_ptr< StackFrame >, CachedStackFrameKey::Hash, CachedStackFrameKey::Equal > m_cachedStackFrames
void asyncTaskCanceled(void *task)
ActionAfterInstrumentation BreakOnInstrumentation(v8::Local< v8::Context > paused_context, v8::debug::BreakpointId) override
void externalAsyncTaskStarted(const V8StackTraceId &parent)
void removeBreakpoint(v8::debug::BreakpointId id)
void setPauseOnNextCall(bool, int targetContextGroupId)
bool m_taskWithScheduledBreakPauseRequested
void asyncTaskStarted(void *task)
v8::Local< v8::Array > queryObjects(v8::Local< v8::Context > context, v8::Local< v8::Object > prototype)
bool IsFunctionBlackboxed(v8::Local< v8::debug::Script > script, const v8::debug::Location &start, const v8::debug::Location &end) override
internal::V8DebuggerId debuggerIdFor(int contextGroupId)
std::unordered_map< V8DebuggerAgentImpl *, int > m_maxAsyncCallStackDepthMap
v8::debug::ExceptionBreakState m_pauseOnExceptionsState
std::unique_ptr< V8StackTraceImpl > captureStackTrace(bool fullStack)
v8::MaybeLocal< v8::Array > internalProperties(v8::Local< v8::Context >, v8::Local< v8::Value >)
void stepOutOfFunction(int targetContextGroupId)
int maxCallStackSizeToCapture() const
std::vector< std::unique_ptr< V8DebuggerScript > > getCompiledScripts(int contextGroupId, V8DebuggerAgentImpl *agent)
v8::MaybeLocal< v8::Value > getTargetScopes(v8::Local< v8::Context >, v8::Local< v8::Value >, ScopeTargetKind)
void AsyncEventOccurred(v8::debug::DebugAsyncActionType type, int id, bool isBlackboxed) override
void interruptAndBreak(int targetContextGroupId)
v8::MaybeLocal< v8::Array > privateMethods(v8::Local< v8::Context > context, v8::Local< v8::Value > value)
void installTerminateExecutionCallbacks(v8::Local< v8::Context > context)
void continueProgram(int targetContextGroupId, bool terminateOnResume=false)
void asyncTaskScheduledForStack(const StringView &taskName, void *task, bool recurring, bool skipTopFrame=false)
std::list< std::shared_ptr< AsyncStackTrace > > m_allAsyncStacks
V8StackTraceId storeCurrentStackTrace(const StringView &description)
std::unique_ptr< TerminateExecutionCallback > m_terminateExecutionCallback
void setMaxCallStackSizeToCapture(V8RuntimeAgentImpl *, int)
V8Debugger(v8::Isolate *, V8InspectorImpl *)
void asyncTaskFinishedForStack(void *task)
void handleProgramBreak(v8::Local< v8::Context > pausedContext, v8::Local< v8::Value > exception, const std::vector< v8::debug::BreakpointId > &hitBreakpoints, v8::debug::BreakReasons break_reasons, v8::debug::ExceptionType exception_type=v8::debug::kException, bool isUncaught=false)
std::unordered_map< V8RuntimeAgentImpl *, int > m_maxCallStackSizeToCaptureMap
v8::Global< v8::Context > m_terminateExecutionCallbackContext
bool isInInstrumentationPause() const
void asyncTaskFinishedForStepping(void *task)
StackTraceToExternalParent m_externalParents
void BreakpointConditionEvaluated(v8::Local< v8::Context > context, v8::debug::BreakpointId breakpoint_id, bool exception_thrown, v8::Local< v8::Value > exception) override
std::unordered_set< void * > m_recurringTasks
bool addInternalObject(v8::Local< v8::Context > context, v8::Local< v8::Object > object, V8InternalValueType type)
void externalAsyncTaskFinished(const V8StackTraceId &parent)
bool hasScheduledBreakOnNextFunctionCall() const
V8InspectorImpl * m_inspector
uintptr_t storeStackTrace(std::shared_ptr< AsyncStackTrace > stack)
void ExceptionThrown(v8::Local< v8::Context > paused_context, v8::Local< v8::Value > exception, v8::Local< v8::Value > promise, bool is_uncaught, v8::debug::ExceptionType exception_type) override
StoredStackTraces m_storedStackTraces
v8::MaybeLocal< v8::Array > collectionsEntries(v8::Local< v8::Context > context, v8::Local< v8::Value > value)
StackTraceToAsyncParent m_asyncParents
bool ShouldBeSkipped(v8::Local< v8::debug::Script > script, int line, int column) override
void ScriptCompiled(v8::Local< v8::debug::Script > script, bool is_live_edited, bool has_compile_error) override
std::shared_ptr< AsyncStackTrace > currentAsyncParent()
std::vector< V8StackTraceId > m_currentExternalParent
void asyncTaskCandidateForStepping(void *task)
void setAsyncCallStackDepth(V8DebuggerAgentImpl *, int)
String16 m_continueToLocationTargetCallFrames
void asyncTaskStartedForStepping(void *task)
void breakProgram(int targetContextGroupId)
std::unique_ptr< V8StackTraceImpl > m_continueToLocationStack
void asyncTaskCanceledForStepping(void *task)
AsyncTaskToStackTrace m_asyncTaskStacks
static size_t nearHeapLimitCallback(void *data, size_t current_heap_limit, size_t initial_heap_limit)
V8StackTraceId currentExternalParent()
v8::MaybeLocal< v8::Value > functionScopes(v8::Local< v8::Context >, v8::Local< v8::Function >)
V8InspectorImpl * inspector()
std::vector< void * > m_currentTasks
void stepIntoStatement(int targetContextGroupId, bool breakOnAsyncCall)
void asyncStackTraceCaptured(int id)
void asyncTaskScheduled(const StringView &taskName, void *task, bool recurring)
v8::Isolate * isolate() const
Definition v8-debugger.h:60
void BreakProgramRequested(v8::Local< v8::Context > paused_context, const std::vector< v8::debug::BreakpointId > &break_points_hit, v8::debug::BreakReasons break_reasons) override
void asyncTaskFinished(void *task)
std::unordered_map< int, internal::V8DebuggerId > m_contextGroupIdToDebuggerId
std::vector< std::shared_ptr< AsyncStackTrace > > m_currentAsyncParent
void stepOverStatement(int targetContextGroupId)
void setPauseOnExceptionsState(v8::debug::ExceptionBreakState)
void asyncParentFor(int stackTraceId, std::shared_ptr< AsyncStackTrace > *asyncParent, V8StackTraceId *externalParent) const
bool restartFrame(int targetContextGroupId, int callFrameOrdinal)
void breakProgramOnAssert(int targetContextGroupId)
void setMaxAsyncTaskStacksForTest(int limit)
Response continueToLocation(int targetContextGroupId, V8DebuggerScript *script, std::unique_ptr< protocol::Debugger::Location >, const String16 &targetCallFramess)
void asyncTaskStartedForStack(void *task)
static void terminateExecutionCompletedCallback(v8::Isolate *isolate)
virtual bool isInspectableHeapObject(v8::Local< v8::Object >)
virtual v8::Local< v8::Context > ensureDefaultContextInGroup(int contextGroupId)
virtual void runMessageLoopOnPause(int contextGroupId)
virtual void runMessageLoopOnInstrumentationPause(int contextGroupId)
virtual void maxAsyncCallStackDepthChanged(int depth)
v8::Isolate * isolate() const
InspectedContext * getContext(int groupId, int contextId) const
void forEachSession(int contextGroupId, const std::function< void(V8InspectorSessionImpl *)> &callback)
int contextGroupId(v8::Local< v8::Context >) const
unsigned exceptionThrown(v8::Local< v8::Context >, StringView message, v8::Local< v8::Value > exception, StringView detailedMessage, StringView url, unsigned lineNumber, unsigned columnNumber, std::unique_ptr< V8StackTrace >, int scriptId) override
static std::unique_ptr< V8StackTraceImpl > capture(V8Debugger *, int maxStackSize)
static std::unique_ptr< V8StackTraceImpl > create(V8Debugger *, v8::Local< v8::StackTrace >, int maxStackSize)
static constexpr int kDefaultMaxCallStackSizeToCapture
static V8DebuggerId generate(V8InspectorImpl *)
int start
int end
MicrotaskQueue * microtask_queue
Definition execution.cc:77
refactor address components for immediate indexing make OptimizeMaglevOnNextCall optimize to turbofan instead of maglev filter for tracing turbofan compilation nullptr
TNode< Object > receiver
TNode< Object > callback
ZoneVector< RpoNumber > & result
ZoneStack< RpoNumber > & stack
ZoneVector< Entry > entries
void SetBreakPointsActive(Isolate *v8_isolate, bool is_active)
bool PrepareRestartFrame(Isolate *v8_isolate, int callFrameOrdinal)
@ kDebugStackTraceCaptured
void BreakRightNow(Isolate *v8_isolate, base::EnumSet< debug::BreakReason > break_reasons)
void SetBreakOnNextFunctionCall(Isolate *isolate)
bool CanBreakProgram(Isolate *v8_isolate)
bool GetPrivateMembers(Local< Context > context, Local< Object > object, int filter, LocalVector< Value > *names_out, LocalVector< Value > *values_out)
void ChangeBreakOnException(Isolate *isolate, ExceptionBreakState type)
MaybeLocal< Array > GetInternalProperties(Isolate *v8_isolate, Local< Value > value)
void SetTerminateOnResume(Isolate *v8_isolate)
void PrepareStep(Isolate *v8_isolate, StepAction action)
void ClearStepping(Isolate *v8_isolate)
void RemoveBreakpoint(Isolate *v8_isolate, BreakpointId id)
void GetLoadedScripts(Isolate *v8_isolate, std::vector< v8::Global< Script > > &scripts)
void SetAsyncEventDelegate(Isolate *v8_isolate, AsyncEventDelegate *delegate)
void ClearBreakOnNextFunctionCall(Isolate *isolate)
v8_inspector::V8Inspector * GetInspector(Isolate *isolate)
v8::Local< v8::Message > CreateMessageFromException(Isolate *v8_isolate, v8::Local< v8::Value > v8_error)
void SetDebugDelegate(Isolate *v8_isolate, DebugDelegate *delegate)
MaybeLocal< Context > GetCreationContext(Local< Object > value)
V8_INLINE uint64_t TraceId()
Definition trace-id.h:12
String16 toProtocolString(v8::Isolate *isolate, v8::Local< v8::String > value)
StringView toStringView(const String16 &string)
v8::Local< v8::String > toV8String(v8::Isolate *isolate, const String16 &string)
v8::Maybe< bool > createDataProperty(v8::Local< v8::Context > context, v8::Local< v8::Object > object, v8::Local< v8::Name > key, v8::Local< v8::Value > value)
String16 toProtocolStringWithTypeCheck(v8::Isolate *isolate, v8::Local< v8::Value > value)
String16 toString16(const StringView &string)
v8::Local< v8::String > toV8StringInternalized(v8::Isolate *isolate, const String16 &string)
V8_INLINE Local< Primitive > Null(Isolate *isolate)
bool ToLocal(v8::internal::MaybeDirectHandle< v8::internal::Object > maybe, Local< T > *local)
Definition api.h:303
#define UNREACHABLE()
Definition logging.h:67
#define CHECK(condition)
Definition logging.h:124
#define DCHECK_IMPLIES(v1, v2)
Definition logging.h:493
#define DCHECK_GE(v1, v2)
Definition logging.h:488
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
#define TRACE_EVENT_END0(category_group, name)
#define TRACE_DISABLED_BY_DEFAULT(name)
#define TRACE_STR_COPY(str)
Definition trace-event.h:50
v8::Local< v8::Context > m_context
v8::Isolate * m_isolate
V8InspectorImpl * m_inspector
v8::Local< v8::Value > m_prototype
#define END_ALLOW_USE_DEPRECATED()
Definition v8config.h:634
#define START_ALLOW_USE_DEPRECATED()
Definition v8config.h:633
std::unique_ptr< ValueMirror > value
std::unique_ptr< ValueMirror > key