fix: clean up debugger API
This commit is contained in:
parent
c0b895e00a
commit
d5fd6e650e
@ -8,6 +8,7 @@ import java.nio.file.Path;
|
||||
import me.topchetoeu.jscript.engine.Context;
|
||||
import me.topchetoeu.jscript.engine.Engine;
|
||||
import me.topchetoeu.jscript.engine.Environment;
|
||||
import me.topchetoeu.jscript.engine.debug.DebugContext;
|
||||
import me.topchetoeu.jscript.engine.debug.DebugServer;
|
||||
import me.topchetoeu.jscript.engine.debug.SimpleDebugger;
|
||||
import me.topchetoeu.jscript.engine.values.ArrayValue;
|
||||
@ -46,7 +47,7 @@ public class Main {
|
||||
}
|
||||
|
||||
static Thread engineTask, debugTask;
|
||||
static Engine engine = new Engine(true);
|
||||
static Engine engine = new Engine();
|
||||
static DebugServer debugServer = new DebugServer();
|
||||
static Environment environment = new Environment();
|
||||
|
||||
@ -133,7 +134,10 @@ public class Main {
|
||||
environment.add(ModuleRepo.ENV_KEY, ModuleRepo.ofFilesystem(fs));
|
||||
}
|
||||
private static void initEngine() {
|
||||
debugServer.targets.put("target", (ws, req) -> new SimpleDebugger(ws, engine));
|
||||
var ctx = new DebugContext();
|
||||
// engine.globalEnvironment.add(DebugContext.ENV_KEY, ctx);
|
||||
|
||||
debugServer.targets.put("target", (ws, req) -> new SimpleDebugger(ws).attach(ctx));
|
||||
engineTask = engine.start();
|
||||
debugTask = debugServer.start(new InetSocketAddress("127.0.0.1", 9229), true);
|
||||
}
|
||||
|
@ -94,7 +94,7 @@ public class Context implements Extensions {
|
||||
private Context curr = self;
|
||||
|
||||
private void update() {
|
||||
while (curr.frame == null && curr != null) curr = curr.parent;
|
||||
while (curr != null && curr.frame == null) curr = curr.parent;
|
||||
}
|
||||
|
||||
@Override public boolean hasNext() {
|
||||
|
@ -57,7 +57,6 @@ public class Engine {
|
||||
public final Environment globalEnvironment = new Environment();
|
||||
|
||||
public final int id = ++nextId;
|
||||
public final boolean debugging;
|
||||
public int maxStackFrames = 10000;
|
||||
|
||||
private Thread thread;
|
||||
@ -111,7 +110,6 @@ public class Engine {
|
||||
return pushMsg(micro, env, new UncompiledFunction(filename, raw), thisArg, args);
|
||||
}
|
||||
|
||||
public Engine(boolean debugging) {
|
||||
this.debugging = debugging;
|
||||
public Engine() {
|
||||
}
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ public interface DebugController {
|
||||
void onFramePop(Context ctx, CodeFrame frame);
|
||||
|
||||
public static DebugController empty() {
|
||||
return new DebugController() {
|
||||
return new DebugController () {
|
||||
@Override public void onFramePop(Context ctx, CodeFrame frame) { }
|
||||
@Override public void onFramePush(Context ctx, CodeFrame frame) { }
|
||||
@Override public boolean onInstruction(Context ctx, CodeFrame frame, Instruction instruction, Object returnVal, EngineException error, boolean caught) {
|
||||
|
@ -25,9 +25,6 @@ public interface DebugHandler {
|
||||
void getProperties(V8Message msg);
|
||||
void releaseObjectGroup(V8Message msg);
|
||||
void releaseObject(V8Message msg);
|
||||
/**
|
||||
* This method might not execute the actual code for well-known requests
|
||||
*/
|
||||
void callFunctionOn(V8Message msg);
|
||||
|
||||
void runtimeEnable(V8Message msg);
|
||||
|
@ -50,8 +50,6 @@ public class DebugServer {
|
||||
private void handle(WebSocket ws, Debugger debugger) {
|
||||
WebSocketMessage raw;
|
||||
|
||||
debugger.connect();
|
||||
|
||||
while ((raw = ws.receive()) != null) {
|
||||
if (raw.type != Type.Text) {
|
||||
ws.send(new V8Error("Expected a text message."));
|
||||
@ -72,8 +70,9 @@ public class DebugServer {
|
||||
switch (msg.name) {
|
||||
case "Debugger.enable":
|
||||
connNotifier.next();
|
||||
debugger.enable(msg); continue;
|
||||
case "Debugger.disable": debugger.disable(msg); continue;
|
||||
debugger.enable(msg);
|
||||
continue;
|
||||
case "Debugger.disable": debugger.close(); continue;
|
||||
|
||||
case "Debugger.setBreakpointByUrl": debugger.setBreakpointByUrl(msg); continue;
|
||||
case "Debugger.removeBreakpoint": debugger.removeBreakpoint(msg); continue;
|
||||
@ -116,7 +115,7 @@ public class DebugServer {
|
||||
}
|
||||
}
|
||||
|
||||
debugger.disconnect();
|
||||
debugger.close();
|
||||
}
|
||||
private void onWsConnect(HttpRequest req, Socket socket, DebuggerProvider debuggerProvider) {
|
||||
var key = req.headers.get("sec-websocket-key");
|
||||
@ -151,7 +150,7 @@ public class DebugServer {
|
||||
catch (RuntimeException e) {
|
||||
ws.send(new V8Error(e.getMessage()));
|
||||
}
|
||||
finally { ws.close(); debugger.disconnect(); }
|
||||
finally { ws.close(); debugger.close(); }
|
||||
}, "Debug Handler");
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
package me.topchetoeu.jscript.engine.debug;
|
||||
|
||||
public interface Debugger extends DebugHandler, DebugController {
|
||||
void connect();
|
||||
void disconnect();
|
||||
void close();
|
||||
}
|
||||
|
@ -174,7 +174,6 @@ public class SimpleDebugger implements Debugger {
|
||||
public State state = State.RESUMED;
|
||||
|
||||
public final WebSocket ws;
|
||||
public final Engine target;
|
||||
|
||||
private ObjectValue emptyObject = new ObjectValue();
|
||||
|
||||
@ -477,7 +476,7 @@ public class SimpleDebugger implements Debugger {
|
||||
|
||||
private RunResult run(Frame codeFrame, String code) {
|
||||
if (codeFrame == null) return new RunResult(null, code, new EngineException("Invalid code frame!"));
|
||||
var engine = new Engine(false);
|
||||
var engine = new Engine();
|
||||
var env = codeFrame.func.environment.fork();
|
||||
|
||||
env.global = new GlobalScope(codeFrame.local);
|
||||
@ -574,8 +573,36 @@ public class SimpleDebugger implements Debugger {
|
||||
updateNotifier.next();
|
||||
}
|
||||
@Override public synchronized void disable(V8Message msg) {
|
||||
enabled = false;
|
||||
close();
|
||||
ws.send(msg.respond());
|
||||
}
|
||||
public synchronized void close() {
|
||||
enabled = false;
|
||||
execptionType = CatchType.NONE;
|
||||
state = State.RESUMED;
|
||||
|
||||
idToBptCand.clear();
|
||||
|
||||
idToBreakpoint.clear();
|
||||
locToBreakpoint.clear();
|
||||
tmpBreakpts.clear();
|
||||
|
||||
filenameToId.clear();
|
||||
idToSource.clear();
|
||||
pendingSources.clear();
|
||||
|
||||
idToFrame.clear();
|
||||
codeFrameToFrame.clear();
|
||||
|
||||
idToObject.clear();
|
||||
objectToId.clear();
|
||||
objectGroups.clear();
|
||||
|
||||
pendingPause = false;
|
||||
|
||||
stepOutFrame = currFrame = null;
|
||||
stepOutPtr = 0;
|
||||
|
||||
updateNotifier.next();
|
||||
}
|
||||
|
||||
@ -952,19 +979,12 @@ public class SimpleDebugger implements Debugger {
|
||||
}
|
||||
}
|
||||
|
||||
@Override public synchronized void connect() {
|
||||
if (!DebugContext.get(target.globalEnvironment).attachDebugger(this)) {
|
||||
ws.send(new V8Error("A debugger is already attached to this engine."));
|
||||
}
|
||||
}
|
||||
@Override public synchronized void disconnect() {
|
||||
DebugContext.get(target.globalEnvironment).detachDebugger();
|
||||
enabled = false;
|
||||
updateNotifier.next();
|
||||
public SimpleDebugger attach(DebugContext ctx) {
|
||||
ctx.attachDebugger(this);
|
||||
return this;
|
||||
}
|
||||
|
||||
public SimpleDebugger(WebSocket ws, Engine target) {
|
||||
public SimpleDebugger(WebSocket ws) {
|
||||
this.ws = ws;
|
||||
this.target = target;
|
||||
}
|
||||
}
|
||||
|
@ -303,6 +303,13 @@ public class CodeFrame {
|
||||
return Runners.NO_RETURN;
|
||||
}
|
||||
|
||||
public void onPush() {
|
||||
DebugContext.get(ctx).onFramePush(ctx, this);
|
||||
}
|
||||
public void onPop() {
|
||||
DebugContext.get(ctx.parent).onFramePop(ctx.parent, this);
|
||||
}
|
||||
|
||||
public CodeFrame(Context ctx, Object thisArg, Object[] args, CodeFunction func) {
|
||||
this.args = args.clone();
|
||||
this.scope = new LocalScope(func.localsN, func.captures);
|
||||
|
@ -33,9 +33,16 @@ public class CodeFunction extends FunctionValue {
|
||||
public Object call(Context ctx, Object thisArg, Object ...args) {
|
||||
var frame = new CodeFrame(ctx, thisArg, args, this);
|
||||
|
||||
while (true) {
|
||||
var res = frame.next(Runners.NO_RETURN, Runners.NO_RETURN, null);
|
||||
if (res != Runners.NO_RETURN) return res;
|
||||
frame.onPush();
|
||||
|
||||
try {
|
||||
while (true) {
|
||||
var res = frame.next(Runners.NO_RETURN, Runners.NO_RETURN, null);
|
||||
if (res != Runners.NO_RETURN) return res;
|
||||
}
|
||||
}
|
||||
finally {
|
||||
frame.onPop();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,7 @@ import me.topchetoeu.jscript.interop.Native;
|
||||
private void next(Context ctx, Object inducedValue, Object inducedError) {
|
||||
Object res = null;
|
||||
|
||||
frame.onPush();
|
||||
awaiting = false;
|
||||
while (!awaiting) {
|
||||
try {
|
||||
@ -36,6 +37,7 @@ import me.topchetoeu.jscript.interop.Native;
|
||||
break;
|
||||
}
|
||||
}
|
||||
frame.onPop();
|
||||
|
||||
if (awaiting) {
|
||||
PromiseLib.then(ctx, frame.pop(), new NativeFunction(this::fulfill), new NativeFunction(this::reject));
|
||||
|
@ -30,6 +30,7 @@ import me.topchetoeu.jscript.interop.Native;
|
||||
Object res = null;
|
||||
state = 0;
|
||||
|
||||
frame.onPush();
|
||||
while (state == 0) {
|
||||
try {
|
||||
res = frame.next(inducedValue, inducedReturn, inducedError == Runners.NO_RETURN ? null : new EngineException(inducedError));
|
||||
@ -47,6 +48,7 @@ import me.topchetoeu.jscript.interop.Native;
|
||||
break;
|
||||
}
|
||||
}
|
||||
frame.onPop();
|
||||
|
||||
if (state == 1) {
|
||||
PromiseLib.then(ctx, frame.pop(), new NativeFunction(this::fulfill), new NativeFunction(this::reject));
|
||||
|
@ -26,6 +26,7 @@ import me.topchetoeu.jscript.interop.Native;
|
||||
Object res = null;
|
||||
yielding = false;
|
||||
|
||||
frame.onPush();
|
||||
while (!yielding) {
|
||||
try {
|
||||
res = frame.next(inducedValue, inducedReturn, inducedError == Runners.NO_RETURN ? null : new EngineException(inducedError));
|
||||
@ -40,6 +41,7 @@ import me.topchetoeu.jscript.interop.Native;
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
frame.onPop();
|
||||
|
||||
if (done) frame = null;
|
||||
else res = frame.pop();
|
||||
|
Loading…
Reference in New Issue
Block a user