Implement escargot debugger restart support

Implement restart in escargot and python debugger.
Also add debugger test.

Signed-off-by: Ádám László Kulcsár <adam.kulcsar@szteszoftver.hu>
This commit is contained in:
Ádám László Kulcsár 2026-05-05 11:51:10 +02:00
commit d7b58a0937
14 changed files with 218 additions and 103 deletions

View file

@ -1986,7 +1986,7 @@ class DebuggerC : public Debugger {
public:
virtual void init(const char* options, Context* context) override {}
virtual void parseCompleted(String* source, String* srcName, size_t originLineOffset, String* error = nullptr) override;
virtual void stopAtBreakpoint(ByteCodeBlock* byteCodeBlock, uint32_t offset, ExecutionState* state) override;
virtual bool stopAtBreakpoint(ByteCodeBlock* byteCodeBlock, uint32_t offset, ExecutionState* state) override;
virtual void byteCodeReleaseNotification(ByteCodeBlock* byteCodeBlock) override;
virtual void exceptionCaught(String* message, SavedStackTraceDataVector& exceptionTrace) override;
virtual void consoleOut(String* output) override;
@ -2057,7 +2057,7 @@ static LexicalEnvironment* getFunctionLexEnv(ExecutionState* state)
return nullptr;
}
void DebuggerC::stopAtBreakpoint(ByteCodeBlock* byteCodeBlock, uint32_t offset, ExecutionState* state)
bool DebuggerC::stopAtBreakpoint(ByteCodeBlock* byteCodeBlock, uint32_t offset, ExecutionState* state)
{
DebuggerOperationsRef::BreakpointOperations operations(reinterpret_cast<DebuggerOperationsRef::WeakCodeRef*>(byteCodeBlock), toRef(state), offset);
@ -2092,6 +2092,7 @@ void DebuggerC::stopAtBreakpoint(ByteCodeBlock* byteCodeBlock, uint32_t offset,
break;
}
}
return false;
}
void DebuggerC::byteCodeReleaseNotification(ByteCodeBlock* byteCodeBlock)
@ -3442,6 +3443,24 @@ bool ContextRef::isWaitBeforeExit()
#endif /* ESCARGOT_DEBUGGER */
}
bool ContextRef::isDebuggerRestartTrue()
{
#ifdef ESCARGOT_DEBUGGER
return isDebuggerRunning() && toImpl(this)->debugger()->getRestart();
#else /* !ESCARGOT_DEBUGGER */
return false;
#endif /* ESCARGOT_DEBUGGER */
}
void ContextRef::setDebuggerRestart()
{
#ifdef ESCARGOT_DEBUGGER
if (isDebuggerRunning()) {
toImpl(this)->debugger()->setRestart(false);
}
#endif /* ESCARGOT_DEBUGGER */
}
void ContextRef::printDebugger(StringRef* output)
{
#ifdef ESCARGOT_DEBUGGER

View file

@ -957,9 +957,11 @@ public:
bool initDebugger(const char* options);
bool isDebuggerRunning();
bool isWaitBeforeExit();
bool isDebuggerRestartTrue();
void printDebugger(StringRef* output);
void pumpDebuggerEvents();
void setAsAlwaysStopState();
void setDebuggerRestart();
StringRef* getClientSource(StringRef** sourceName);
typedef OptionalRef<ValueRef> (*VirtualIdentifierCallback)(ExecutionStateRef* state, ValueRef* name);

View file

@ -142,7 +142,7 @@ public:
return m_activeSavedStackTrace;
}
inline void processDisabledBreakpoint(ByteCodeBlock* byteCodeBlock, uint32_t offset, ExecutionState* state)
inline bool processDisabledBreakpoint(ByteCodeBlock* byteCodeBlock, uint32_t offset, ExecutionState* state)
{
if (m_stopState != ESCARGOT_DEBUGGER_ALWAYS_STOP && m_stopState != state) {
m_delay--;
@ -154,6 +154,8 @@ public:
if (m_stopState == ESCARGOT_DEBUGGER_ALWAYS_STOP || m_stopState == state) {
stopAtBreakpoint(byteCodeBlock, offset, state);
}
return m_restartDebugging;
}
static inline void updateStopState(Debugger* debugger, ExecutionState* state, ExecutionState* newState)
@ -189,7 +191,7 @@ public:
virtual void init(const char* options, Context* context) = 0;
virtual void parseCompleted(String* source, String* srcName, size_t originLineOffset, String* error = nullptr) = 0;
virtual void stopAtBreakpoint(ByteCodeBlock* byteCodeBlock, uint32_t offset, ExecutionState* state) = 0;
virtual bool stopAtBreakpoint(ByteCodeBlock* byteCodeBlock, uint32_t offset, ExecutionState* state) = 0;
virtual void byteCodeReleaseNotification(ByteCodeBlock* byteCodeBlock) = 0;
virtual void exceptionCaught(String* message, SavedStackTraceDataVector& exceptionTrace) = 0;
virtual void consoleOut(String* output) = 0;
@ -210,6 +212,16 @@ public:
Vector<Object*, GCUtil::gc_malloc_allocator<Object*>> m_activeObjects;
bool getRestart()
{
return m_restartDebugging;
}
void setRestart(bool b)
{
m_restartDebugging = b;
}
protected:
Debugger()
: m_delay(ESCARGOT_DEBUGGER_MESSAGE_PROCESS_DELAY)
@ -234,6 +246,7 @@ protected:
ExecutionState* m_stopState;
std::vector<BreakpointLocationsInfo*> m_breakpointLocationsVector;
Vector<uintptr_t, GCUtil::gc_malloc_atomic_allocator<uintptr_t>> m_releasedFunctions;
bool m_restartDebugging;
private:
Context* m_context;

View file

@ -258,14 +258,14 @@ void DebuggerDevtools::sendPausedEvent(ByteCodeBlock* byteCodeBlock, const uint3
sendMessage(msg, msg.length());
}
void DebuggerDevtools::stopAtBreakpoint(ByteCodeBlock* byteCodeBlock, uint32_t offset, ExecutionState* state)
bool DebuggerDevtools::stopAtBreakpoint(ByteCodeBlock* byteCodeBlock, uint32_t offset, ExecutionState* state)
{
if (m_stopState == ESCARGOT_DEBUGGER_IN_EVAL_MODE) {
m_delay--;
if (m_delay == 0) {
processEvents(state, byteCodeBlock);
}
return;
return false;
}
sendPausedEvent(byteCodeBlock, offset, state, !m_startBreakpoint);
@ -275,7 +275,7 @@ void DebuggerDevtools::stopAtBreakpoint(ByteCodeBlock* byteCodeBlock, uint32_t o
}
if (!enabled()) {
return;
return false;
}
ASSERT(m_activeObjects.empty());
@ -286,6 +286,8 @@ void DebuggerDevtools::stopAtBreakpoint(ByteCodeBlock* byteCodeBlock, uint32_t o
m_activeObjects.clear();
m_delay = ESCARGOT_DEBUGGER_MESSAGE_PROCESS_DELAY;
return false;
}
void DebuggerDevtools::byteCodeReleaseNotification(ByteCodeBlock* byteCodeBlock)

View file

@ -55,7 +55,7 @@ public:
bool skipSourceCode(String* srcName) const override;
void parseCompleted(String* source, String* srcName, size_t originLineOffset, String* error = nullptr) override;
void stopAtBreakpoint(ByteCodeBlock* byteCodeBlock, uint32_t offset, ExecutionState* state) override;
bool stopAtBreakpoint(ByteCodeBlock* byteCodeBlock, uint32_t offset, ExecutionState* state) override;
void byteCodeReleaseNotification(ByteCodeBlock* byteCodeBlock) override;
void exceptionCaught(String* message, SavedStackTraceDataVector& exceptionTrace) override;
void consoleOut(String* output) override;

View file

@ -219,14 +219,14 @@ void DebuggerEscargot::sendVariableObjectInfo(uint8_t subType, Object* object)
send(ESCARGOT_MESSAGE_VARIABLE, &variableObjectInfo, sizeof(VariableObjectInfo));
}
void DebuggerEscargot::stopAtBreakpoint(ByteCodeBlock* byteCodeBlock, uint32_t offset, ExecutionState* state)
bool DebuggerEscargot::stopAtBreakpoint(ByteCodeBlock* byteCodeBlock, uint32_t offset, ExecutionState* state)
{
if (m_stopState == ESCARGOT_DEBUGGER_IN_EVAL_MODE) {
m_delay--;
if (m_delay == 0) {
processEvents(state, byteCodeBlock);
}
return;
return m_restartDebugging;
}
BreakpointOffset breakpointOffset;
@ -238,7 +238,7 @@ void DebuggerEscargot::stopAtBreakpoint(ByteCodeBlock* byteCodeBlock, uint32_t o
send(ESCARGOT_MESSAGE_BREAKPOINT_HIT, &breakpointOffset, sizeof(BreakpointOffset));
if (!enabled()) {
return;
return m_restartDebugging;
}
ASSERT(m_activeObjects.size() == 0);
@ -249,6 +249,8 @@ void DebuggerEscargot::stopAtBreakpoint(ByteCodeBlock* byteCodeBlock, uint32_t o
m_activeObjects.clear();
m_delay = ESCARGOT_DEBUGGER_MESSAGE_PROCESS_DELAY;
return m_restartDebugging;
}
void DebuggerEscargot::byteCodeReleaseNotification(ByteCodeBlock* byteCodeBlock)
@ -899,6 +901,10 @@ bool DebuggerEscargot::processEvents(ExecutionState* state, Optional<ByteCodeBlo
m_stopState = stopState;
return false;
}
case ESCARGOT_MESSAGE_RESTART: {
setRestart(true);
return true;
}
case ESCARGOT_MESSAGE_WATCH_8BIT_START:
case ESCARGOT_MESSAGE_WATCH_16BIT_START:
case ESCARGOT_MESSAGE_EVAL_8BIT_START:

View file

@ -109,36 +109,37 @@ public:
ESCARGOT_MESSAGE_STEP = 3,
ESCARGOT_MESSAGE_NEXT = 4,
ESCARGOT_MESSAGE_FINISH = 5,
ESCARGOT_MESSAGE_RESTART = 6,
// These four must be in the same order.
ESCARGOT_MESSAGE_EVAL_8BIT_START = 6,
ESCARGOT_MESSAGE_EVAL_8BIT = 7,
ESCARGOT_MESSAGE_EVAL_16BIT_START = 8,
ESCARGOT_MESSAGE_EVAL_16BIT = 9,
ESCARGOT_MESSAGE_EVAL_8BIT_START = 7,
ESCARGOT_MESSAGE_EVAL_8BIT = 8,
ESCARGOT_MESSAGE_EVAL_16BIT_START = 9,
ESCARGOT_MESSAGE_EVAL_16BIT = 10,
// These four must be in the same order.
ESCARGOT_MESSAGE_EVAL_WITHOUT_STOP_8BIT_START = 10,
ESCARGOT_MESSAGE_EVAL_WITHOUT_STOP_8BIT = 11,
ESCARGOT_MESSAGE_EVAL_WITHOUT_STOP_16BIT_START = 12,
ESCARGOT_MESSAGE_EVAL_WITHOUT_STOP_16BIT = 13,
ESCARGOT_MESSAGE_EVAL_WITHOUT_STOP_8BIT_START = 11,
ESCARGOT_MESSAGE_EVAL_WITHOUT_STOP_8BIT = 12,
ESCARGOT_MESSAGE_EVAL_WITHOUT_STOP_16BIT_START = 13,
ESCARGOT_MESSAGE_EVAL_WITHOUT_STOP_16BIT = 14,
// These four must be in the same order.
ESCARGOT_MESSAGE_WATCH_8BIT_START = 14,
ESCARGOT_MESSAGE_WATCH_8BIT = 15,
ESCARGOT_MESSAGE_WATCH_16BIT_START = 16,
ESCARGOT_MESSAGE_WATCH_16BIT = 17,
ESCARGOT_MESSAGE_GET_BACKTRACE = 18,
ESCARGOT_MESSAGE_GET_SCOPE_CHAIN = 19,
ESCARGOT_MESSAGE_GET_SCOPE_VARIABLES = 20,
ESCARGOT_MESSAGE_GET_OBJECT = 21,
ESCARGOT_MESSAGE_WATCH_8BIT_START = 15,
ESCARGOT_MESSAGE_WATCH_8BIT = 16,
ESCARGOT_MESSAGE_WATCH_16BIT_START = 17,
ESCARGOT_MESSAGE_WATCH_16BIT = 18,
ESCARGOT_MESSAGE_GET_BACKTRACE = 19,
ESCARGOT_MESSAGE_GET_SCOPE_CHAIN = 20,
ESCARGOT_MESSAGE_GET_SCOPE_VARIABLES = 21,
ESCARGOT_MESSAGE_GET_OBJECT = 22,
// These four must be in the same order.
ESCARGOT_DEBUGGER_CLIENT_SOURCE_8BIT_START = 22,
ESCARGOT_DEBUGGER_CLIENT_SOURCE_8BIT = 23,
ESCARGOT_DEBUGGER_CLIENT_SOURCE_16BIT_START = 24,
ESCARGOT_DEBUGGER_CLIENT_SOURCE_16BIT = 25,
ESCARGOT_DEBUGGER_THERE_WAS_NO_SOURCE = 26,
ESCARGOT_DEBUGGER_PENDING_CONFIG = 27,
ESCARGOT_DEBUGGER_PENDING_RESUME = 28,
ESCARGOT_DEBUGGER_WAIT_BEFORE_EXIT = 29,
ESCARGOT_DEBUGGER_TAKE_HEAP_SNAPSHOT = 30,
ESCARGOT_DEBUGGER_STOP = 31
ESCARGOT_DEBUGGER_CLIENT_SOURCE_8BIT_START = 23,
ESCARGOT_DEBUGGER_CLIENT_SOURCE_8BIT = 24,
ESCARGOT_DEBUGGER_CLIENT_SOURCE_16BIT_START = 25,
ESCARGOT_DEBUGGER_CLIENT_SOURCE_16BIT = 26,
ESCARGOT_DEBUGGER_THERE_WAS_NO_SOURCE = 27,
ESCARGOT_DEBUGGER_PENDING_CONFIG = 28,
ESCARGOT_DEBUGGER_PENDING_RESUME = 29,
ESCARGOT_DEBUGGER_WAIT_BEFORE_EXIT = 30,
ESCARGOT_DEBUGGER_TAKE_HEAP_SNAPSHOT = 31,
ESCARGOT_DEBUGGER_STOP = 32
};
@ -190,7 +191,7 @@ public:
void init(const char* options, Context* context) override;
void parseCompleted(String* source, String* srcName, size_t originLineOffset, String* error = nullptr) override;
void stopAtBreakpoint(ByteCodeBlock* byteCodeBlock, uint32_t offset, ExecutionState* state) override;
bool stopAtBreakpoint(ByteCodeBlock* byteCodeBlock, uint32_t offset, ExecutionState* state) override;
void byteCodeReleaseNotification(ByteCodeBlock* byteCodeBlock) override;
void exceptionCaught(String* message, SavedStackTraceDataVector& exceptionTrace) override;
void consoleOut(String* output) override;

View file

@ -763,6 +763,14 @@ Value Interpreter::interpret(ExecutionState* state, ByteCodeBlock* byteCodeBlock
// Return F.[[Call]](V, argumentsList).
registerFile[code->m_resultIndex] = callee.asPointerValue()->call(*state, Value(), code->m_argumentCount, &registerFile[code->m_argumentsStartIndex]);
#ifdef ESCARGOT_DEBUGGER
if (state->context()->debuggerEnabled()) {
if (state->context()->debugger()->getRestart()) {
return Value(true);
}
}
#endif /* ESCARGOT_DEBUGGER */
ADD_PROGRAM_COUNTER(Call);
NEXT_INSTRUCTION();
}
@ -1715,7 +1723,10 @@ Value Interpreter::interpret(ExecutionState* state, ByteCodeBlock* byteCodeBlock
:
{
if (state->context()->debuggerEnabled()) {
state->context()->debugger()->processDisabledBreakpoint(byteCodeBlock, (uint32_t)(programCounter - (size_t)byteCodeBlock->m_code.data()), state);
bool restart = state->context()->debugger()->processDisabledBreakpoint(byteCodeBlock, (uint32_t)(programCounter - (size_t)byteCodeBlock->m_code.data()), state);
if (restart) {
return Value(true);
}
}
ADD_PROGRAM_COUNTER(BreakpointDisabled);
@ -1726,7 +1737,10 @@ Value Interpreter::interpret(ExecutionState* state, ByteCodeBlock* byteCodeBlock
:
{
if (state->context()->debuggerEnabled()) {
state->context()->debugger()->stopAtBreakpoint(byteCodeBlock, (uint32_t)(programCounter - (size_t)byteCodeBlock->m_code.data()), state);
bool restart = state->context()->debugger()->stopAtBreakpoint(byteCodeBlock, (uint32_t)(programCounter - (size_t)byteCodeBlock->m_code.data()), state);
if (restart) {
return Value(true);
}
}
ADD_PROGRAM_COUNTER(BreakpointEnabled);

View file

@ -898,48 +898,61 @@ static bool evalScript(ContextRef* context, StringRef* source, StringRef* srcNam
isModule = isModule || true;
}
auto scriptInitializeResult = context->scriptParser()->initializeScript(source, srcName, isModule);
if (!scriptInitializeResult.script) {
fprintf(stderr, "Script parsing error: ");
switch (scriptInitializeResult.parseErrorCode) {
case Escargot::ErrorObjectRef::Code::SyntaxError:
fprintf(stderr, "SyntaxError");
break;
case Escargot::ErrorObjectRef::Code::EvalError:
fprintf(stderr, "EvalError");
break;
case Escargot::ErrorObjectRef::Code::RangeError:
fprintf(stderr, "RangeError");
break;
case Escargot::ErrorObjectRef::Code::ReferenceError:
fprintf(stderr, "ReferenceError");
break;
case Escargot::ErrorObjectRef::Code::TypeError:
fprintf(stderr, "TypeError");
break;
case Escargot::ErrorObjectRef::Code::URIError:
fprintf(stderr, "URIError");
break;
default:
break;
bool shouldRestart = false;
do {
if (shouldRestart) {
source = Evaluator::execute(context, [](ExecutionStateRef* state, StringRef* str) -> ValueRef* { return builtinHelperFileRead(state, str->toStdUTF8String().c_str(), "read").get(); }, srcName).result->asString();
}
fprintf(stderr, ": %s\n", scriptInitializeResult.parseErrorMessage->toStdUTF8String().data());
return false;
}
shouldRestart = false;
auto evalResult = Evaluator::execute(context, [](ExecutionStateRef* state, ScriptRef* script) -> ValueRef* { return script->execute(state); }, scriptInitializeResult.script.get());
if (!evalResult.isSuccessful()) {
fprintf(stderr, "Uncaught %s:\n", evalResult.resultOrErrorToString(context)->toStdUTF8String().data());
for (size_t i = 0; i < evalResult.stackTrace.size(); i++) {
fprintf(stderr, "%s (%d:%d)\n", evalResult.stackTrace[i].srcName->toStdUTF8String().data(), (int)evalResult.stackTrace[i].loc.line, (int)evalResult.stackTrace[i].loc.column);
auto scriptInitializeResult = context->scriptParser()->initializeScript(source, srcName, isModule);
if (!scriptInitializeResult.script) {
fprintf(stderr, "Script parsing error: ");
switch (scriptInitializeResult.parseErrorCode) {
case Escargot::ErrorObjectRef::Code::SyntaxError:
fprintf(stderr, "SyntaxError");
break;
case Escargot::ErrorObjectRef::Code::EvalError:
fprintf(stderr, "EvalError");
break;
case Escargot::ErrorObjectRef::Code::RangeError:
fprintf(stderr, "RangeError");
break;
case Escargot::ErrorObjectRef::Code::ReferenceError:
fprintf(stderr, "ReferenceError");
break;
case Escargot::ErrorObjectRef::Code::TypeError:
fprintf(stderr, "TypeError");
break;
case Escargot::ErrorObjectRef::Code::URIError:
fprintf(stderr, "URIError");
break;
default:
break;
}
fprintf(stderr, ": %s\n", scriptInitializeResult.parseErrorMessage->toStdUTF8String().data());
return false;
}
return false;
}
if (shouldPrintScriptResult) {
puts(evalResult.resultOrErrorToString(context)->toStdUTF8String().data());
}
auto evalResult = Evaluator::execute(context, [](ExecutionStateRef* state, ScriptRef* script) -> ValueRef* { return script->execute(state); }, scriptInitializeResult.script.get());
if (!evalResult.isSuccessful()) {
fprintf(stderr, "Uncaught %s:\n", evalResult.resultOrErrorToString(context)->toStdUTF8String().data());
for (size_t i = 0; i < evalResult.stackTrace.size(); i++) {
fprintf(stderr, "%s (%d:%d)\n", evalResult.stackTrace[i].srcName->toStdUTF8String().data(), (int)evalResult.stackTrace[i].loc.line, (int)evalResult.stackTrace[i].loc.column);
}
return false;
}
if (context->isDebuggerRestartTrue()) {
shouldRestart = true;
context->setDebuggerRestart();
}
if (shouldPrintScriptResult) {
puts(evalResult.resultOrErrorToString(context)->toStdUTF8String().data());
}
} while (shouldRestart);
bool result = true;
while (context->vmInstance()->hasPendingJob() || context->vmInstance()->hasPendingJobFromAnotherThread()) {

View file

@ -228,6 +228,12 @@ class DebuggerPrompt(Cmd):
else:
pprint(self.debugger.function_list)
def do_restart(self, args):
""" Restart current debugging from the start of the file """
self.debugger.send_restart()
self.debugger.step()
self.stop = True
do_re = do_restart
def _scroll_direction(debugger, direction):
""" Helper function for do_scroll """

View file

@ -85,32 +85,33 @@ ESCARGOT_MESSAGE_CONTINUE = 2
ESCARGOT_MESSAGE_STEP = 3
ESCARGOT_MESSAGE_NEXT = 4
ESCARGOT_MESSAGE_FINISH = 5
ESCARGOT_MESSAGE_EVAL_8BIT_START = 6
ESCARGOT_MESSAGE_EVAL_8BIT = 7
ESCARGOT_MESSAGE_EVAL_16BIT_START = 8
ESCARGOT_MESSAGE_EVAL_16BIT = 9
ESCARGOT_MESSAGE_EVAL_WITHOUT_STOP_8BIT_START = 10
ESCARGOT_MESSAGE_EVAL_WITHOUT_STOP_8BIT = 11
ESCARGOT_MESSAGE_EVAL_WITHOUT_STOP_16BIT_START = 12
ESCARGOT_MESSAGE_EVAL_WITHOUT_STOP_16BIT = 13
ESCARGOT_MESSAGE_WATCH_8BIT_START = 14
ESCARGOT_MESSAGE_WATCH_8BIT = 15
ESCARGOT_MESSAGE_WATCH_16BIT_START = 16
ESCARGOT_MESSAGE_WATCH_16BIT = 17
ESCARGOT_MESSAGE_GET_BACKTRACE = 18
ESCARGOT_MESSAGE_GET_SCOPE_CHAIN = 19
ESCARGOT_MESSAGE_GET_SCOPE_VARIABLES = 20
ESCARGOT_MESSAGE_GET_OBJECT = 21
ESCARGOT_DEBUGGER_CLIENT_SOURCE_8BIT_START = 22
ESCARGOT_DEBUGGER_CLIENT_SOURCE_8BIT = 23
ESCARGOT_DEBUGGER_CLIENT_SOURCE_16BIT_START = 24
ESCARGOT_DEBUGGER_CLIENT_SOURCE_16BIT = 25
ESCARGOT_DEBUGGER_THERE_WAS_NO_SOURCE = 26
ESCARGOT_DEBUGGER_PENDING_CONFIG = 27
ESCARGOT_DEBUGGER_PENDING_RESUME = 28
ESCARGOT_DEBUGGER_WAIT_BEFORE_EXIT = 29
ESCARGOT_DEBUGGER_TAKE_HEAP_SNAPSHOT = 30
ESCARGOT_DEBUGGER_STOP = 31
ESCARGOT_MESSAGE_RESTART = 6
ESCARGOT_MESSAGE_EVAL_8BIT_START = 7
ESCARGOT_MESSAGE_EVAL_8BIT = 8
ESCARGOT_MESSAGE_EVAL_16BIT_START = 9
ESCARGOT_MESSAGE_EVAL_16BIT = 10
ESCARGOT_MESSAGE_EVAL_WITHOUT_STOP_8BIT_START = 11
ESCARGOT_MESSAGE_EVAL_WITHOUT_STOP_8BIT = 12
ESCARGOT_MESSAGE_EVAL_WITHOUT_STOP_16BIT_START = 13
ESCARGOT_MESSAGE_EVAL_WITHOUT_STOP_16BIT = 14
ESCARGOT_MESSAGE_WATCH_8BIT_START = 15
ESCARGOT_MESSAGE_WATCH_8BIT = 16
ESCARGOT_MESSAGE_WATCH_16BIT_START = 17
ESCARGOT_MESSAGE_WATCH_16BIT = 18
ESCARGOT_MESSAGE_GET_BACKTRACE = 19
ESCARGOT_MESSAGE_GET_SCOPE_CHAIN = 20
ESCARGOT_MESSAGE_GET_SCOPE_VARIABLES = 21
ESCARGOT_MESSAGE_GET_OBJECT = 22
ESCARGOT_DEBUGGER_CLIENT_SOURCE_8BIT_START = 23
ESCARGOT_DEBUGGER_CLIENT_SOURCE_8BIT = 24
ESCARGOT_DEBUGGER_CLIENT_SOURCE_16BIT_START = 25
ESCARGOT_DEBUGGER_CLIENT_SOURCE_16BIT = 26
ESCARGOT_DEBUGGER_THERE_WAS_NO_SOURCE = 27
ESCARGOT_DEBUGGER_PENDING_CONFIG = 28
ESCARGOT_DEBUGGER_PENDING_RESUME = 29
ESCARGOT_DEBUGGER_WAIT_BEFORE_EXIT = 30
ESCARGOT_DEBUGGER_TAKE_HEAP_SNAPSHOT = 31
ESCARGOT_DEBUGGER_STOP = 32
# Environment record types
@ -638,6 +639,10 @@ class Debugger(object):
command_id)
self.channel.send_message(self.byte_order, message)
def send_restart(self):
self.prompt = False
self._exec_command(ESCARGOT_MESSAGE_RESTART)
def do_continue(self):
self.prompt = False
self._exec_command(ESCARGOT_MESSAGE_CONTINUE)

View file

@ -0,0 +1,6 @@
s
restart
n
s
re
c

View file

@ -0,0 +1,18 @@
Connecting to: localhost:6501
Connection created!!!
Stopped at tools/debugger/tests/do_restart.js:9
(escargot-debugger) s
Stopped at tools/debugger/tests/do_restart.js:2 (in hello() at line:1, col:1)
(escargot-debugger) restart
Stopped at tools/debugger/tests/do_restart.js:9
(escargot-debugger) n
Print: Hello world!
Stopped at tools/debugger/tests/do_restart.js:10
(escargot-debugger) s
Stopped at tools/debugger/tests/do_restart.js:6 (in bye() at line:5, col:1)
(escargot-debugger) re
Stopped at tools/debugger/tests/do_restart.js:9
(escargot-debugger) c
Print: Hello world!
Print: Bye world!
Connection closed.

View file

@ -0,0 +1,10 @@
function hello() {
print("Hello world!");
}
function bye() {
print("Bye world!");
}
hello();
bye();