v8-debugger.h 11.3 KB
Newer Older
1 2 3 4
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5 6
#ifndef V8_INSPECTOR_V8_DEBUGGER_H_
#define V8_INSPECTOR_V8_DEBUGGER_H_
7

8
#include <list>
9
#include <memory>
10
#include <unordered_map>
11
#include <unordered_set>
12 13
#include <vector>

14
#include "include/v8-inspector.h"
15
#include "src/base/macros.h"
16
#include "src/inspector/inspected-context.h"
17
#include "src/inspector/protocol/Debugger.h"
18 19
#include "src/inspector/protocol/Forward.h"
#include "src/inspector/protocol/Runtime.h"
20
#include "src/inspector/v8-debugger-id.h"
21
#include "src/inspector/v8-debugger-script.h"
22 23 24

namespace v8_inspector {

25
class AsyncStackTrace;
26
class StackFrame;
27
class V8Debugger;
28 29
class V8DebuggerAgentImpl;
class V8InspectorImpl;
30
class V8RuntimeAgentImpl;
31
class V8StackTraceImpl;
32
struct V8StackTraceId;
33

34 35 36 37 38 39
enum class WrapMode {
  kForceValue,
  kNoPreview,
  kWithPreview,
  kGenerateWebDriverValue
};
40

41
using protocol::Response;
42 43
using TerminateExecutionCallback =
    protocol::Runtime::Backend::TerminateExecutionCallback;
44

45 46
class V8Debugger : public v8::debug::DebugDelegate,
                   public v8::debug::AsyncEventDelegate {
47 48
 public:
  V8Debugger(v8::Isolate*, V8InspectorImpl*);
49
  ~V8Debugger() override;
50 51
  V8Debugger(const V8Debugger&) = delete;
  V8Debugger& operator=(const V8Debugger&) = delete;
52 53

  bool enabled() const;
54
  v8::Isolate* isolate() const { return m_isolate; }
55

56
  void setBreakpointsActive(bool);
57

58 59
  v8::debug::ExceptionBreakState getPauseOnExceptionsState();
  void setPauseOnExceptionsState(v8::debug::ExceptionBreakState);
60
  bool canBreakProgram();
61
  void breakProgram(int targetContextGroupId);
62
  void interruptAndBreak(int targetContextGroupId);
63 64
  void continueProgram(int targetContextGroupId,
                       bool terminateOnResume = false);
65
  void breakProgramOnAssert(int targetContextGroupId);
66

67
  void setPauseOnNextCall(bool, int targetContextGroupId);
68
  void stepIntoStatement(int targetContextGroupId, bool breakOnAsyncCall);
69 70
  void stepOverStatement(int targetContextGroupId);
  void stepOutOfFunction(int targetContextGroupId);
71

72 73
  void terminateExecution(std::unique_ptr<TerminateExecutionCallback> callback);

74
  Response continueToLocation(int targetContextGroupId,
75
                              V8DebuggerScript* script,
76 77
                              std::unique_ptr<protocol::Debugger::Location>,
                              const String16& targetCallFramess);
78
  bool restartFrame(int targetContextGroupId, int callFrameOrdinal);
79

80 81 82 83
  // Each script inherits debug data from v8::Context where it has been
  // compiled.
  // Only scripts whose debug data matches |contextGroupId| will be reported.
  // Passing 0 will result in reporting all scripts.
84 85
  std::vector<std::unique_ptr<V8DebuggerScript>> getCompiledScripts(
      int contextGroupId, V8DebuggerAgentImpl* agent);
86 87 88
  void enable();
  void disable();

89
  bool isPaused() const { return m_pausedContextGroupId; }
90
  bool isPausedInContextGroup(int contextGroupId) const;
91 92 93

  int maxAsyncCallChainDepth() { return m_maxAsyncCallStackDepth; }
  void setAsyncCallStackDepth(V8DebuggerAgentImpl*, int);
94

95 96 97
  int maxCallStackSizeToCapture() const { return m_maxCallStackSizeToCapture; }
  void setMaxCallStackSizeToCapture(V8RuntimeAgentImpl*, int);

98
  std::shared_ptr<AsyncStackTrace> currentAsyncParent();
99
  V8StackTraceId currentExternalParent();
100

101 102
  std::shared_ptr<StackFrame> symbolize(v8::Local<v8::StackFrame> v8Frame);

103 104 105 106 107 108
  std::unique_ptr<V8StackTraceImpl> createStackTrace(v8::Local<v8::StackTrace>);
  std::unique_ptr<V8StackTraceImpl> captureStackTrace(bool fullStack);

  v8::MaybeLocal<v8::Array> internalProperties(v8::Local<v8::Context>,
                                               v8::Local<v8::Value>);

109
  v8::Local<v8::Array> queryObjects(v8::Local<v8::Context> context,
110
                                    v8::Local<v8::Object> prototype);
111

112 113 114 115 116 117 118
  void asyncTaskScheduled(const StringView& taskName, void* task,
                          bool recurring);
  void asyncTaskCanceled(void* task);
  void asyncTaskStarted(void* task);
  void asyncTaskFinished(void* task);
  void allAsyncTasksCanceled();

119 120 121 122
  V8StackTraceId storeCurrentStackTrace(const StringView& description);
  void externalAsyncTaskStarted(const V8StackTraceId& parent);
  void externalAsyncTaskFinished(const V8StackTraceId& parent);

123 124
  uintptr_t storeStackTrace(std::shared_ptr<AsyncStackTrace> stack);

125 126 127
  void muteScriptParsedEvents();
  void unmuteScriptParsedEvents();

128 129
  V8InspectorImpl* inspector() { return m_inspector; }

130
  void setMaxAsyncTaskStacksForTest(int limit);
131
  void dumpAsyncTaskStacksStateForTest();
132

133
  internal::V8DebuggerId debuggerIdFor(int contextGroupId);
134 135 136
  std::shared_ptr<AsyncStackTrace> stackTraceFor(int contextGroupId,
                                                 const V8StackTraceId& id);

137 138 139
  void reportTermination();

 private:
140 141 142 143
  bool addInternalObject(v8::Local<v8::Context> context,
                         v8::Local<v8::Object> object,
                         V8InternalValueType type);

144
  void clearContinueToLocation();
145
  bool shouldContinueToCurrentLocation();
146

147 148
  static size_t nearHeapLimitCallback(void* data, size_t current_heap_limit,
                                      size_t initial_heap_limit);
149
  static void terminateExecutionCompletedCallback(v8::Isolate* isolate);
150 151
  static void terminateExecutionCompletedCallbackIgnoringData(
      v8::Isolate* isolate, void*);
152 153 154
  void handleProgramBreak(
      v8::Local<v8::Context> pausedContext, v8::Local<v8::Value> exception,
      const std::vector<v8::debug::BreakpointId>& hitBreakpoints,
155
      v8::debug::BreakReasons break_reasons,
156 157
      v8::debug::ExceptionType exception_type = v8::debug::kException,
      bool isUncaught = false);
158

159 160 161 162 163 164 165 166
  enum ScopeTargetKind {
    FUNCTION,
    GENERATOR,
  };
  v8::MaybeLocal<v8::Value> getTargetScopes(v8::Local<v8::Context>,
                                            v8::Local<v8::Value>,
                                            ScopeTargetKind);

167 168
  v8::MaybeLocal<v8::Value> functionScopes(v8::Local<v8::Context>,
                                           v8::Local<v8::Function>);
169 170
  v8::MaybeLocal<v8::Value> generatorScopes(v8::Local<v8::Context>,
                                            v8::Local<v8::Value>);
171 172
  v8::MaybeLocal<v8::Array> collectionsEntries(v8::Local<v8::Context> context,
                                               v8::Local<v8::Value> value);
173

174
  void asyncTaskScheduledForStack(const StringView& taskName, void* task,
175
                                  bool recurring, bool skipTopFrame = false);
176 177 178 179
  void asyncTaskCanceledForStack(void* task);
  void asyncTaskStartedForStack(void* task);
  void asyncTaskFinishedForStack(void* task);

180
  void asyncTaskCandidateForStepping(void* task);
181 182 183 184
  void asyncTaskStartedForStepping(void* task);
  void asyncTaskFinishedForStepping(void* task);
  void asyncTaskCanceledForStepping(void* task);

185
  // v8::debug::DebugEventListener implementation.
186 187
  void AsyncEventOccurred(v8::debug::DebugAsyncActionType type, int id,
                          bool isBlackboxed) override;
188
  void ScriptCompiled(v8::Local<v8::debug::Script> script, bool is_live_edited,
189
                      bool has_compile_error) override;
190
  void BreakProgramRequested(
191
      v8::Local<v8::Context> paused_context,
192
      const std::vector<v8::debug::BreakpointId>& break_points_hit,
193
      v8::debug::BreakReasons break_reasons) override;
194 195
  void BreakOnInstrumentation(v8::Local<v8::Context> paused_context,
                              v8::debug::BreakpointId) override;
196
  void ExceptionThrown(v8::Local<v8::Context> paused_context,
197
                       v8::Local<v8::Value> exception,
198 199
                       v8::Local<v8::Value> promise, bool is_uncaught,
                       v8::debug::ExceptionType exception_type) override;
200 201 202
  bool IsFunctionBlackboxed(v8::Local<v8::debug::Script> script,
                            const v8::debug::Location& start,
                            const v8::debug::Location& end) override;
203

204 205 206
  bool ShouldBeSkipped(v8::Local<v8::debug::Script> script, int line,
                       int column) override;

207 208
  int currentContextGroupId();

209 210
  bool hasScheduledBreakOnNextFunctionCall() const;

211 212 213
  v8::Isolate* m_isolate;
  V8InspectorImpl* m_inspector;
  int m_enableCount;
214

215
  int m_breakpointsActiveCount = 0;
216
  int m_ignoreScriptParsedEventsCounter;
217
  size_t m_originalHeapLimit = 0;
218
  bool m_scheduledOOMBreak = false;
219
  int m_targetContextGroupId = 0;
220
  int m_pausedContextGroupId = 0;
221
  int m_continueToLocationBreakpointId;
222 223
  String16 m_continueToLocationTargetCallFrames;
  std::unique_ptr<V8StackTraceImpl> m_continueToLocationStack;
224

225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254
  // We cache symbolized stack frames by (scriptId,lineNumber,columnNumber)
  // to reduce memory pressure for huge web apps with lots of deep async
  // stacks.
  struct CachedStackFrameKey {
    int scriptId;
    int lineNumber;
    int columnNumber;

    struct Equal {
      bool operator()(CachedStackFrameKey const& a,
                      CachedStackFrameKey const& b) const {
        return a.scriptId == b.scriptId && a.lineNumber == b.lineNumber &&
               a.columnNumber == b.columnNumber;
      }
    };

    struct Hash {
      size_t operator()(CachedStackFrameKey const& key) const {
        size_t code = 0;
        code = code * 31 + key.scriptId;
        code = code * 31 + key.lineNumber;
        code = code * 31 + key.columnNumber;
        return code;
      }
    };
  };
  std::unordered_map<CachedStackFrameKey, std::weak_ptr<StackFrame>,
                     CachedStackFrameKey::Hash, CachedStackFrameKey::Equal>
      m_cachedStackFrames;

255
  using AsyncTaskToStackTrace =
256
      std::unordered_map<void*, std::weak_ptr<AsyncStackTrace>>;
257
  AsyncTaskToStackTrace m_asyncTaskStacks;
258
  std::unordered_set<void*> m_recurringTasks;
259

260
  size_t m_maxAsyncCallStacks;
261
  int m_maxAsyncCallStackDepth;
262
  int m_maxCallStackSizeToCapture;
263

264
  std::vector<void*> m_currentTasks;
265
  std::vector<std::shared_ptr<AsyncStackTrace>> m_currentAsyncParent;
266
  std::vector<V8StackTraceId> m_currentExternalParent;
267 268 269 270 271 272

  void collectOldAsyncStacksIfNeeded();
  // V8Debugger owns all the async stacks, while most of the other references
  // are weak, which allows to collect some stacks when there are too many.
  std::list<std::shared_ptr<AsyncStackTrace>> m_allAsyncStacks;

273
  std::unordered_map<V8DebuggerAgentImpl*, int> m_maxAsyncCallStackDepthMap;
274
  std::unordered_map<V8RuntimeAgentImpl*, int> m_maxCallStackSizeToCaptureMap;
275
  void* m_taskWithScheduledBreak = nullptr;
276

277 278 279 280 281
  // If any of the following three is true, we schedule pause on next JS
  // execution using SetBreakOnNextFunctionCall.
  bool m_externalAsyncTaskPauseRequested = false;       // External async task.
  bool m_taskWithScheduledBreakPauseRequested = false;  // Local async task.
  bool m_pauseOnNextCallRequested = false;  // setPauseOnNextCall API call.
282

283
  v8::debug::ExceptionBreakState m_pauseOnExceptionsState;
284 285
  // Whether we should pause on async call execution (if any) while stepping in.
  // See Debugger.stepInto for details.
286
  bool m_pauseOnAsyncCall = false;
287

288
  using StackTraceIdToStackTrace =
289
      std::unordered_map<uintptr_t, std::weak_ptr<AsyncStackTrace>>;
290 291 292
  StackTraceIdToStackTrace m_storedStackTraces;
  uintptr_t m_lastStackTraceId = 0;

293
  std::unordered_map<int, internal::V8DebuggerId> m_contextGroupIdToDebuggerId;
294

295
  std::unique_ptr<TerminateExecutionCallback> m_terminateExecutionCallback;
296 297 298 299
};

}  // namespace v8_inspector

300
#endif  // V8_INSPECTOR_V8_DEBUGGER_H_