diff --git a/deps/chakrashim/include/v8-debug.h b/deps/chakrashim/include/v8-debug.h index 77de7d88421..52e424a36a5 100644 --- a/deps/chakrashim/include/v8-debug.h +++ b/deps/chakrashim/include/v8-debug.h @@ -91,7 +91,7 @@ class V8_EXPORT Debug { static Local GetDebugContext(Isolate* isolate); static void EnableDebug(); - static void EnableInspector(); + static void EnableInspector(bool enableReplayDebug = false); static void SetLiveEditEnabled(Isolate* isolate, bool enable); }; diff --git a/deps/chakrashim/src/inspector/inspector.gypi b/deps/chakrashim/src/inspector/inspector.gypi index a240711fe8f..62e18a1d208 100644 --- a/deps/chakrashim/src/inspector/inspector.gypi +++ b/deps/chakrashim/src/inspector/inspector.gypi @@ -16,9 +16,12 @@ '<(SHARED_INTERMEDIATE_DIR)/src/inspector/protocol/Runtime.h', '<(SHARED_INTERMEDIATE_DIR)/src/inspector/protocol/Schema.cpp', '<(SHARED_INTERMEDIATE_DIR)/src/inspector/protocol/Schema.h', + '<(SHARED_INTERMEDIATE_DIR)/src/inspector/protocol/TimeTravel.cpp', + '<(SHARED_INTERMEDIATE_DIR)/src/inspector/protocol/TimeTravel.h', '<(SHARED_INTERMEDIATE_DIR)/include/inspector/Debugger.h', '<(SHARED_INTERMEDIATE_DIR)/include/inspector/Runtime.h', '<(SHARED_INTERMEDIATE_DIR)/include/inspector/Schema.h', + '<(SHARED_INTERMEDIATE_DIR)/include/inspector/TimeTravel.h', ], 'inspector_all_sources': [ @@ -65,6 +68,8 @@ 'src/inspector/v8-schema-agent-impl.h', 'src/inspector/v8-stack-trace-impl.cc', 'src/inspector/v8-stack-trace-impl.h', + 'src/inspector/v8-timetravel-agent-impl.cc', + 'src/inspector/v8-timetravel-agent-impl.h', 'src/inspector/v8-value-copier.cc', 'src/inspector/v8-value-copier.h', ] diff --git a/deps/chakrashim/src/inspector/js_protocol.json b/deps/chakrashim/src/inspector/js_protocol.json index e1c5e3e818d..1d6592983c6 100644 --- a/deps/chakrashim/src/inspector/js_protocol.json +++ b/deps/chakrashim/src/inspector/js_protocol.json @@ -777,5 +777,19 @@ "description": "Issued when new console message is added." } ] + }, + { + "domain": "TimeTravel", + "description": "TimeTravel domain exposes JavaScript time travel capabilities. It allows stepping backwards through execution.", + "commands": [ + { + "name": "stepBack", + "description": "Steps backwards to the previous statement." + }, + { + "name": "reverse", + "description": "Resumes JavaScript execution in reverse." + } + ] }] } diff --git a/deps/chakrashim/src/inspector/v8-debugger-agent-impl.cc b/deps/chakrashim/src/inspector/v8-debugger-agent-impl.cc index a9f2e5ef927..c2744c26440 100644 --- a/deps/chakrashim/src/inspector/v8-debugger-agent-impl.cc +++ b/deps/chakrashim/src/inspector/v8-debugger-agent-impl.cc @@ -654,6 +654,20 @@ void V8DebuggerAgentImpl::stepOut(ErrorString* errorString) { m_debugger->stepOutOfFunction(); } +void V8DebuggerAgentImpl::reverse(ErrorString* errorString) { + if (!assertPaused(errorString)) return; + m_scheduledDebuggerStep = ReverseContinue; + m_steppingFromFramework = false; + m_debugger->reverse(); +} + +void V8DebuggerAgentImpl::stepBack(ErrorString* errorString) { + if (!assertPaused(errorString)) return; + m_scheduledDebuggerStep = StepBack; + m_steppingFromFramework = isTopPausedCallFrameBlackboxed(); + m_debugger->stepBack(); +} + void V8DebuggerAgentImpl::setPauseOnExceptions( ErrorString* errorString, const String16& stringPauseState) { if (!checkEnabled(errorString)) return; diff --git a/deps/chakrashim/src/inspector/v8-debugger-agent-impl.h b/deps/chakrashim/src/inspector/v8-debugger-agent-impl.h index 502336303af..3f2f533d2bc 100644 --- a/deps/chakrashim/src/inspector/v8-debugger-agent-impl.h +++ b/deps/chakrashim/src/inspector/v8-debugger-agent-impl.h @@ -110,6 +110,10 @@ class V8DebuggerAgentImpl : public protocol::Debugger::Backend { std::unique_ptr> positions) override; + // Time travel implementations + void reverse(ErrorString*); + void stepBack(ErrorString*); + bool enabled(); void setBreakpointAt(const String16& scriptId, int lineNumber, @@ -171,7 +175,14 @@ class V8DebuggerAgentImpl : public protocol::Debugger::Backend { using DebugServerBreakpointToBreakpointIdAndSourceMap = protocol::HashMap>; - enum DebuggerStep { NoStep = 0, StepInto, StepOver, StepOut }; + enum DebuggerStep { + StepInto = 0, + StepOver, + StepOut, + StepBack, + ReverseContinue, + NoStep + }; V8InspectorImpl* m_inspector; V8Debugger* m_debugger; diff --git a/deps/chakrashim/src/inspector/v8-debugger.cc b/deps/chakrashim/src/inspector/v8-debugger.cc index 3b69e8e9229..8b2e9f98772 100644 --- a/deps/chakrashim/src/inspector/v8-debugger.cc +++ b/deps/chakrashim/src/inspector/v8-debugger.cc @@ -256,6 +256,18 @@ void V8Debugger::clearStepping() { JsDiagSetStepType(JsDiagStepTypeContinue); } +void V8Debugger::reverse() { + DCHECK(isPaused()); + JsDiagSetStepType(JsDiagStepTypeReverseContinue); + continueProgram(); +} + +void V8Debugger::stepBack() { + DCHECK(isPaused()); + JsDiagSetStepType(JsDiagStepTypeStepBack); + continueProgram(); +} + bool V8Debugger::setScriptSource( const String16& sourceID, v8::Local newSource, bool dryRun, ErrorString* error, diff --git a/deps/chakrashim/src/inspector/v8-debugger.h b/deps/chakrashim/src/inspector/v8-debugger.h index 23fc2928d19..a0d7398bd11 100644 --- a/deps/chakrashim/src/inspector/v8-debugger.h +++ b/deps/chakrashim/src/inspector/v8-debugger.h @@ -58,6 +58,10 @@ class V8Debugger { void stepOutOfFunction(); void clearStepping(); + // Time travel + void reverse(); + void stepBack(); + bool setScriptSource(const String16& sourceID, v8::Local newSource, bool dryRun, ErrorString*, diff --git a/deps/chakrashim/src/inspector/v8-inspector-session-impl.cc b/deps/chakrashim/src/inspector/v8-inspector-session-impl.cc index f9f77e95566..6846ac59e5a 100644 --- a/deps/chakrashim/src/inspector/v8-inspector-session-impl.cc +++ b/deps/chakrashim/src/inspector/v8-inspector-session-impl.cc @@ -16,6 +16,9 @@ #include "src/inspector/v8-inspector-impl.h" #include "src/inspector/v8-runtime-agent-impl.h" #include "src/inspector/v8-schema-agent-impl.h" +#include "src/inspector/v8-timetravel-agent-impl.h" + +#include "src/jsrtinspector.h" namespace v8_inspector { @@ -28,7 +31,9 @@ bool V8InspectorSession::canDispatchMethod(const StringView& method) { stringViewStartsWith(method, protocol::Console::Metainfo::commandPrefix) || stringViewStartsWith(method, - protocol::Schema::Metainfo::commandPrefix); + protocol::Schema::Metainfo::commandPrefix) || + stringViewStartsWith(method, + protocol::TimeTravel::Metainfo::commandPrefix); } std::unique_ptr V8InspectorSessionImpl::create( @@ -77,6 +82,11 @@ V8InspectorSessionImpl::V8InspectorSessionImpl(V8InspectorImpl* inspector, this, this, agentState(protocol::Schema::Metainfo::domainName))); protocol::Schema::Dispatcher::wire(&m_dispatcher, m_schemaAgent.get()); + m_timeTravelAgent = wrapUnique(new V8TimeTravelAgentImpl( + this, this, agentState(protocol::TimeTravel::Metainfo::domainName))); + protocol::TimeTravel::Dispatcher::wire(&m_dispatcher, + m_timeTravelAgent.get()); + if (savedState.length()) { m_runtimeAgent->restore(); m_debuggerAgent->restore(); @@ -173,6 +183,14 @@ V8InspectorSessionImpl::supportedDomainsImpl() { .setName(protocol::Schema::Metainfo::domainName) .setVersion(protocol::Schema::Metainfo::version) .build()); + + if (m_timeTravelAgent->enabled()) { + result.push_back(protocol::Schema::Domain::create() + .setName(protocol::TimeTravel::Metainfo::domainName) + .setVersion(protocol::TimeTravel::Metainfo::version) + .build()); + } + return result; } diff --git a/deps/chakrashim/src/inspector/v8-inspector-session-impl.h b/deps/chakrashim/src/inspector/v8-inspector-session-impl.h index d18eb00e398..68d2c68b5ac 100644 --- a/deps/chakrashim/src/inspector/v8-inspector-session-impl.h +++ b/deps/chakrashim/src/inspector/v8-inspector-session-impl.h @@ -22,6 +22,7 @@ class V8DebuggerAgentImpl; class V8InspectorImpl; class V8RuntimeAgentImpl; class V8SchemaAgentImpl; +class V8TimeTravelAgentImpl; using protocol::ErrorString; @@ -38,6 +39,7 @@ class V8InspectorSessionImpl : public V8InspectorSession, V8DebuggerAgentImpl* debuggerAgent() { return m_debuggerAgent.get(); } V8SchemaAgentImpl* schemaAgent() { return m_schemaAgent.get(); } V8RuntimeAgentImpl* runtimeAgent() { return m_runtimeAgent.get(); } + V8TimeTravelAgentImpl* timeTravelAgent() { return m_timeTravelAgent.get(); } int contextGroupId() const { return m_contextGroupId; } void reset(); @@ -85,6 +87,7 @@ class V8InspectorSessionImpl : public V8InspectorSession, std::unique_ptr m_debuggerAgent; std::unique_ptr m_consoleAgent; std::unique_ptr m_schemaAgent; + std::unique_ptr m_timeTravelAgent; DISALLOW_COPY_AND_ASSIGN(V8InspectorSessionImpl); }; diff --git a/deps/chakrashim/src/inspector/v8-timetravel-agent-impl.cc b/deps/chakrashim/src/inspector/v8-timetravel-agent-impl.cc new file mode 100644 index 00000000000..11749391a5b --- /dev/null +++ b/deps/chakrashim/src/inspector/v8-timetravel-agent-impl.cc @@ -0,0 +1,50 @@ +// Copyright 2015 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. + +#include "src/inspector/v8-timetravel-agent-impl.h" +#include "src/inspector/v8-inspector-session-impl.h" +#include "src/inspector/v8-debugger-agent-impl.h" +#include "src/jsrtinspector.h" + +namespace v8_inspector { + +V8TimeTravelAgentImpl::V8TimeTravelAgentImpl( + V8InspectorSessionImpl* session, protocol::FrontendChannel* frontendChannel, + protocol::DictionaryValue* state) + : m_session(session), + m_frontend(frontendChannel), + m_state(state) {} + +V8TimeTravelAgentImpl::~V8TimeTravelAgentImpl() {} + +bool V8TimeTravelAgentImpl::checkEnabled(ErrorString* errorString) { + if (enabled()) { + return true; + } + + *errorString = "TimeTravel agent is not enabled"; + return false; +} + +bool V8TimeTravelAgentImpl::enabled() { + return jsrt::Inspector::IsReplayDebugEnabled(); +} + +void V8TimeTravelAgentImpl::reverse(ErrorString* errorString) { + if (!checkEnabled(errorString)) { + return; + } + + m_session->debuggerAgent()->reverse(errorString); +} + +void V8TimeTravelAgentImpl::stepBack(ErrorString* errorString) { + if (!checkEnabled(errorString)) { + return; + } + + m_session->debuggerAgent()->stepBack(errorString); +} + +} // namespace v8_inspector diff --git a/deps/chakrashim/src/inspector/v8-timetravel-agent-impl.h b/deps/chakrashim/src/inspector/v8-timetravel-agent-impl.h new file mode 100644 index 00000000000..4b3b001c4ec --- /dev/null +++ b/deps/chakrashim/src/inspector/v8-timetravel-agent-impl.h @@ -0,0 +1,46 @@ +// Copyright 2015 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. + +#ifndef V8_INSPECTOR_V8TIMETRAVELAGENTIMPL_H_ +#define V8_INSPECTOR_V8TIMETRAVELAGENTIMPL_H_ + +#include + +#include "src/base/macros.h" +#include "src/inspector/protocol/TimeTravel.h" +#include "src/inspector/protocol/Forward.h" + +namespace v8_inspector { + +class V8Debugger; +class V8InspectorImpl; +class V8InspectorSessionImpl; + +using protocol::ErrorString; + +class V8TimeTravelAgentImpl : public protocol::TimeTravel::Backend { + public: + V8TimeTravelAgentImpl(V8InspectorSessionImpl*, protocol::FrontendChannel*, + protocol::DictionaryValue* state); + ~V8TimeTravelAgentImpl() override; + + // Part of the protocol. + void reverse(ErrorString*) override; + void stepBack(ErrorString*) override; + + bool enabled(); + + private: + bool checkEnabled(ErrorString*); + + V8InspectorSessionImpl* m_session; + protocol::TimeTravel::Frontend m_frontend; + protocol::DictionaryValue* m_state; + + DISALLOW_COPY_AND_ASSIGN(V8TimeTravelAgentImpl); +}; + +} // namespace v8_inspector + +#endif // V8_INSPECTOR_V8TIMETRAVELAGENTIMPL_H_ diff --git a/deps/chakrashim/src/jsrtinspector.cc b/deps/chakrashim/src/jsrtinspector.cc index f46df4add0b..7f647cfeab3 100644 --- a/deps/chakrashim/src/jsrtinspector.cc +++ b/deps/chakrashim/src/jsrtinspector.cc @@ -26,6 +26,7 @@ namespace v8 { extern THREAD_LOCAL bool g_EnableInspector; + extern THREAD_LOCAL bool g_EnableReplayDebug; } namespace jsrt { @@ -159,6 +160,10 @@ namespace jsrt { return v8::g_EnableInspector; } + bool Inspector::IsReplayDebugEnabled() { + return v8::g_EnableReplayDebug; + } + void Inspector::StartDebugging(JsRuntimeHandle runtime) { JsErrorCode errorCode = JsDiagStartDebugging( runtime, JsDiagDebugEventHandler, nullptr); diff --git a/deps/chakrashim/src/jsrtinspector.h b/deps/chakrashim/src/jsrtinspector.h index eede5c3ee15..065c9a3bce1 100644 --- a/deps/chakrashim/src/jsrtinspector.h +++ b/deps/chakrashim/src/jsrtinspector.h @@ -29,6 +29,7 @@ class InspectorBreakQueue; class Inspector { public: static bool IsInspectorEnabled(); + static bool IsReplayDebugEnabled(); static void StartDebugging(JsRuntimeHandle runtime); static void RequestAsyncBreak(JsRuntimeHandle runtime, v8::InterruptCallback callback, diff --git a/deps/chakrashim/src/v8debug.cc b/deps/chakrashim/src/v8debug.cc index 1b4462066b1..8915c3b45e3 100644 --- a/deps/chakrashim/src/v8debug.cc +++ b/deps/chakrashim/src/v8debug.cc @@ -25,13 +25,15 @@ namespace v8 { THREAD_LOCAL bool g_EnableDebug = false; THREAD_LOCAL bool g_EnableInspector = false; + THREAD_LOCAL bool g_EnableReplayDebug = false; void Debug::EnableDebug() { g_EnableDebug = true; } - void Debug::EnableInspector() { + void Debug::EnableInspector(bool enableReplayDebug) { g_EnableInspector = true; + g_EnableReplayDebug = enableReplayDebug; } Local Debug::GetDebugContext(Isolate* isolate) { diff --git a/src/node.cc b/src/node.cc index 9f6c02ee798..2e93896e3f9 100644 --- a/src/node.cc +++ b/src/node.cc @@ -4468,12 +4468,14 @@ void Init(int* argc, } #endif - // CHAKRA-TODO : fix this to not do it here #ifdef NODE_ENGINE_CHAKRACORE + // CHAKRA-TODO : fix this to not do it here if (debug_options.inspector_enabled()) { +#if ENABLE_TTD_NODE + v8::Debug::EnableInspector(s_doTTReplay && s_doTTDebug); +#else v8::Debug::EnableInspector(); - } else if (debug_options.debugger_enabled()) { - v8::Debug::EnableDebug(); +#endif } #endif @@ -4618,9 +4620,7 @@ inline int Start(Isolate* isolate, void* isolate_context, const char* path = argc > 1 ? argv[1] : nullptr; StartDebug(&env, path, debug_options); - bool debugger_enabled = - debug_options.debugger_enabled() || debug_options.inspector_enabled(); - if (debugger_enabled && !debugger_running) + if (debug_options.inspector_enabled() && !debugger_running) return 12; // Signal internal error. { @@ -4638,10 +4638,6 @@ inline int Start(Isolate* isolate, void* isolate_context, env.set_trace_sync_io(trace_sync_io); - // Enable debugger - if (debug_options.debugger_enabled()) - EnableDebug(&env); - if (load_napi_modules) { ProcessEmitWarning(&env, "N-API is an experimental feature " "and could change at any time."); @@ -4792,12 +4788,11 @@ inline int Start_TTDReplay(Isolate* isolate, void* isolate_context, Environment env(isolate_data, context); env.Start(argc, argv, exec_argc, exec_argv, v8_is_profiling); - bool debug_enabled = - debug_options.debugger_enabled() || debug_options.inspector_enabled(); - // Start debug agent when argv has --debug - if (debug_enabled) - StartDebug(&env, nullptr, debug_options); + StartDebug(&env, nullptr, debug_options); + + if (debug_options.inspector_enabled() && !debugger_running) + return 12; // Signal internal error. { Environment::AsyncCallbackScope callback_scope(&env); @@ -4806,10 +4801,6 @@ inline int Start_TTDReplay(Isolate* isolate, void* isolate_context, env.set_trace_sync_io(trace_sync_io); - // Enable debugger - if (debug_enabled) - EnableDebug(&env); - //// TTD Specific code JsTTDStart();