|
|
|
@@ -30,6 +30,7 @@ import me.topchetoeu.jscript.runtime.EventLoop;
|
|
|
|
import me.topchetoeu.jscript.runtime.Frame;
|
|
|
|
import me.topchetoeu.jscript.runtime.Frame;
|
|
|
|
import me.topchetoeu.jscript.runtime.debug.DebugContext;
|
|
|
|
import me.topchetoeu.jscript.runtime.debug.DebugContext;
|
|
|
|
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
|
|
|
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
|
|
|
|
|
|
|
import me.topchetoeu.jscript.runtime.exceptions.SyntaxException;
|
|
|
|
import me.topchetoeu.jscript.runtime.scope.GlobalScope;
|
|
|
|
import me.topchetoeu.jscript.runtime.scope.GlobalScope;
|
|
|
|
import me.topchetoeu.jscript.runtime.values.ArrayValue;
|
|
|
|
import me.topchetoeu.jscript.runtime.values.ArrayValue;
|
|
|
|
import me.topchetoeu.jscript.runtime.values.FunctionValue;
|
|
|
|
import me.topchetoeu.jscript.runtime.values.FunctionValue;
|
|
|
|
@@ -41,7 +42,9 @@ import me.topchetoeu.jscript.runtime.values.Values;
|
|
|
|
public class SimpleDebugger implements Debugger {
|
|
|
|
public class SimpleDebugger implements Debugger {
|
|
|
|
public static final Set<String> VSCODE_EMPTY = Set.of(
|
|
|
|
public static final Set<String> VSCODE_EMPTY = Set.of(
|
|
|
|
"function(...runtimeArgs){\n let t = 1024; let e = null;\n if(e)try{let r=\"<<default preview>>\",i=e.call(this,r);if(i!==r)return String(i)}catch(r){return`<<indescribable>>${JSON.stringify([String(r),\"object\"])}`}if(typeof this==\"object\"&&this){let r;for(let i of[Symbol.for(\"debug.description\"),Symbol.for(\"nodejs.util.inspect.custom\")])try{r=this[i]();break}catch{}if(!r&&!String(this.toString).includes(\"[native code]\")&&(r=String(this)),r&&!r.startsWith(\"[object \"))return r.length>=t?r.slice(0,t)+\"\\u2026\":r}\n ;\n\n}",
|
|
|
|
"function(...runtimeArgs){\n let t = 1024; let e = null;\n if(e)try{let r=\"<<default preview>>\",i=e.call(this,r);if(i!==r)return String(i)}catch(r){return`<<indescribable>>${JSON.stringify([String(r),\"object\"])}`}if(typeof this==\"object\"&&this){let r;for(let i of[Symbol.for(\"debug.description\"),Symbol.for(\"nodejs.util.inspect.custom\")])try{r=this[i]();break}catch{}if(!r&&!String(this.toString).includes(\"[native code]\")&&(r=String(this)),r&&!r.startsWith(\"[object \"))return r.length>=t?r.slice(0,t)+\"\\u2026\":r}\n ;\n\n}",
|
|
|
|
|
|
|
|
"function(...runtimeArgs){\n let r = 1024; let e = null;\n if(e)try{let t=\"<<default preview>>\",n=e.call(this,t);if(n!==t)return String(n)}catch(t){return`<<indescribable>>${JSON.stringify([String(t),\"object\"])}`}if(typeof this==\"object\"&&this){let t;for(let n of[Symbol.for(\"debug.description\"),Symbol.for(\"nodejs.util.inspect.custom\")])if(typeof this[n]==\"function\")try{t=this[n]();break}catch{}if(!t&&!String(this.toString).includes(\"[native code]\")&&(t=String(this)),t&&!t.startsWith(\"[object\"))return t.length>=r?t.slice(0,r)+\"\\u2026\":t};}",
|
|
|
|
"function(...runtimeArgs){\n let t = 1024; let e = null;\n let r={},i=\"<<default preview>>\";if(typeof this!=\"object\"||!this)return r;for(let[n,s]of Object.entries(this)){if(e)try{let o=e.call(s,i);if(o!==i){r[n]=String(o);continue}}catch(o){r[n]=`<<indescribable>>${JSON.stringify([String(o),n])}`;continue}if(typeof s==\"object\"&&s){let o;for(let a of runtimeArgs[0])try{o=s[a]();break}catch{}!o&&!String(s.toString).includes(\"[native code]\")&&(o=String(s)),o&&!o.startsWith(\"[object \")&&(r[n]=o.length>=t?o.slice(0,t)+\"\\u2026\":o)}}return r\n ;\n\n}",
|
|
|
|
"function(...runtimeArgs){\n let t = 1024; let e = null;\n let r={},i=\"<<default preview>>\";if(typeof this!=\"object\"||!this)return r;for(let[n,s]of Object.entries(this)){if(e)try{let o=e.call(s,i);if(o!==i){r[n]=String(o);continue}}catch(o){r[n]=`<<indescribable>>${JSON.stringify([String(o),n])}`;continue}if(typeof s==\"object\"&&s){let o;for(let a of runtimeArgs[0])try{o=s[a]();break}catch{}!o&&!String(s.toString).includes(\"[native code]\")&&(o=String(s)),o&&!o.startsWith(\"[object \")&&(r[n]=o.length>=t?o.slice(0,t)+\"\\u2026\":o)}}return r\n ;\n\n}",
|
|
|
|
|
|
|
|
"function(...runtimeArgs){\n let r = 1024; let e = null;\n let t={},n=\"<<default preview>>\";if(typeof this!=\"object\"||!this)return t;for(let[i,o]of Object.entries(this)){if(e)try{let s=e.call(o,n);if(s!==n){t[i]=String(s);continue}}catch(s){t[i]=`<<indescribable>>${JSON.stringify([String(s),i])}`;continue}if(typeof o==\"object\"&&o){let s;for(let a of runtimeArgs[0])if(typeof o[a]==\"function\")try{s=o[a]();break}catch{}!s&&!String(o.toString).includes(\"[native code]\")&&(s=String(o)),s&&!s.startsWith(\"[object \")&&(t[i]=s.length>=r?s.slice(0,r)+\"\\u2026\":s)}}return t\n ;\n\n}",
|
|
|
|
"function(){let t={__proto__:this.__proto__\n},e=Object.getOwnPropertyNames(this);for(let r=0;r<e.length;++r){let i=e[r],n=i>>>0;if(String(n>>>0)===i&&n>>>0!==4294967295)continue;let s=Object.getOwnPropertyDescriptor(this,i);s&&Object.defineProperty(t,i,s)}return t}",
|
|
|
|
"function(){let t={__proto__:this.__proto__\n},e=Object.getOwnPropertyNames(this);for(let r=0;r<e.length;++r){let i=e[r],n=i>>>0;if(String(n>>>0)===i&&n>>>0!==4294967295)continue;let s=Object.getOwnPropertyDescriptor(this,i);s&&Object.defineProperty(t,i,s)}return t}",
|
|
|
|
"function(){return[Symbol.for(\"debug.description\"),Symbol.for(\"nodejs.util.inspect.custom\")]\n}"
|
|
|
|
"function(){return[Symbol.for(\"debug.description\"),Symbol.for(\"nodejs.util.inspect.custom\")]\n}"
|
|
|
|
);
|
|
|
|
);
|
|
|
|
@@ -83,7 +86,9 @@ public class SimpleDebugger implements Debugger {
|
|
|
|
public final String condition;
|
|
|
|
public final String condition;
|
|
|
|
public final Pattern pattern;
|
|
|
|
public final Pattern pattern;
|
|
|
|
public final int line, start;
|
|
|
|
public final int line, start;
|
|
|
|
public final WeakHashMap<FunctionBody, Set<Location>> resolvedLocations = new WeakHashMap<>();
|
|
|
|
public final long locNum;
|
|
|
|
|
|
|
|
public final HashMap<Filename, Location> resolvedLocations = new HashMap<>();
|
|
|
|
|
|
|
|
public final HashMap<Filename, Long> resolvedDistances = new HashMap<>();
|
|
|
|
|
|
|
|
|
|
|
|
public Breakpoint(int id, Pattern pattern, int line, int start, String condition) {
|
|
|
|
public Breakpoint(int id, Pattern pattern, int line, int start, String condition) {
|
|
|
|
this.id = id;
|
|
|
|
this.id = id;
|
|
|
|
@@ -91,18 +96,28 @@ public class SimpleDebugger implements Debugger {
|
|
|
|
this.pattern = pattern;
|
|
|
|
this.pattern = pattern;
|
|
|
|
this.line = line;
|
|
|
|
this.line = line;
|
|
|
|
this.start = start;
|
|
|
|
this.start = start;
|
|
|
|
|
|
|
|
this.locNum = start | ((long)line << 32);
|
|
|
|
|
|
|
|
|
|
|
|
if (condition != null && condition.trim().equals("")) condition = null;
|
|
|
|
if (condition != null && condition.trim().equals("")) condition = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// TODO: Figure out how to unload a breakpoint
|
|
|
|
// TODO: Figure out how to unload a breakpoint
|
|
|
|
|
|
|
|
// TODO: Do location resolution with function boundaries
|
|
|
|
public void addFunc(FunctionBody body, FunctionMap map) {
|
|
|
|
public void addFunc(FunctionBody body, FunctionMap map) {
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
for (var loc : map.correctBreakpoint(pattern, line, start)) {
|
|
|
|
for (var loc : map.correctBreakpoint(pattern, line, start)) {
|
|
|
|
if (!resolvedLocations.containsKey(body)) resolvedLocations.put(body, new HashSet<>());
|
|
|
|
var currNum = loc.start() + ((long)loc.line() << 32);
|
|
|
|
var set = resolvedLocations.get(body);
|
|
|
|
long currDist = 0;
|
|
|
|
set.add(loc);
|
|
|
|
if (currNum > locNum) currDist = currNum - locNum;
|
|
|
|
|
|
|
|
else currDist = locNum - currNum;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if ( currDist > resolvedDistances.getOrDefault(loc.filename(), Long.MAX_VALUE)) continue;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
resolvedLocations.put(loc.filename(), loc);
|
|
|
|
|
|
|
|
resolvedDistances.put(loc.filename(), currDist);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (var loc : resolvedLocations.values()) {
|
|
|
|
ws.send(new V8Event("Debugger.breakpointResolved", new JSONMap()
|
|
|
|
ws.send(new V8Event("Debugger.breakpointResolved", new JSONMap()
|
|
|
|
.set("breakpointId", id)
|
|
|
|
.set("breakpointId", id)
|
|
|
|
.set("location", serializeLocation(loc))
|
|
|
|
.set("location", serializeLocation(loc))
|
|
|
|
@@ -202,8 +217,9 @@ public class SimpleDebugger implements Debugger {
|
|
|
|
|
|
|
|
|
|
|
|
private ObjectValue emptyObject = new ObjectValue();
|
|
|
|
private ObjectValue emptyObject = new ObjectValue();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private WeakHashMap<DebugContext, DebugContext> contexts = new WeakHashMap<>();
|
|
|
|
private WeakHashMap<FunctionBody, FunctionMap> mappings = new WeakHashMap<>();
|
|
|
|
private WeakHashMap<FunctionBody, FunctionMap> mappings = new WeakHashMap<>();
|
|
|
|
private WeakHashMap<FunctionBody, HashMap<Location, Breakpoint>> bpLocs = new WeakHashMap<>();
|
|
|
|
private HashMap<Location, HashSet<Breakpoint>> bpLocs = new HashMap<>();
|
|
|
|
|
|
|
|
|
|
|
|
private HashMap<Integer, Breakpoint> idToBreakpoint = new HashMap<>();
|
|
|
|
private HashMap<Integer, Breakpoint> idToBreakpoint = new HashMap<>();
|
|
|
|
|
|
|
|
|
|
|
|
@@ -226,6 +242,8 @@ public class SimpleDebugger implements Debugger {
|
|
|
|
private int stepOutPtr = 0;
|
|
|
|
private int stepOutPtr = 0;
|
|
|
|
|
|
|
|
|
|
|
|
private boolean compare(String src, String target) {
|
|
|
|
private boolean compare(String src, String target) {
|
|
|
|
|
|
|
|
src = src.replaceAll("\\s", "");
|
|
|
|
|
|
|
|
target = target.replaceAll("\\s", "");
|
|
|
|
if (src.length() != target.length()) return false;
|
|
|
|
if (src.length() != target.length()) return false;
|
|
|
|
var diff = 0;
|
|
|
|
var diff = 0;
|
|
|
|
var all = 0;
|
|
|
|
var all = 0;
|
|
|
|
@@ -291,13 +309,11 @@ public class SimpleDebugger implements Debugger {
|
|
|
|
bpLocs.clear();
|
|
|
|
bpLocs.clear();
|
|
|
|
|
|
|
|
|
|
|
|
for (var bp : idToBreakpoint.values()) {
|
|
|
|
for (var bp : idToBreakpoint.values()) {
|
|
|
|
for (var el : bp.resolvedLocations.entrySet()) {
|
|
|
|
for (var loc : bp.resolvedLocations.values()) {
|
|
|
|
if (!bpLocs.containsKey(el.getKey())) bpLocs.put(el.getKey(), new HashMap<>());
|
|
|
|
bpLocs.putIfAbsent(loc, new HashSet<>());
|
|
|
|
var map = bpLocs.get(el.getKey());
|
|
|
|
var set = bpLocs.get(loc);
|
|
|
|
|
|
|
|
|
|
|
|
for (var loc : el.getValue()) {
|
|
|
|
set.add(bp);
|
|
|
|
map.put(loc, bp);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@@ -333,10 +349,10 @@ public class SimpleDebugger implements Debugger {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
private JSONMap serializeObj(Context ctx, Object val, boolean byValue) {
|
|
|
|
private JSONMap serializeObj(Context ctx, Object val, boolean byValue) {
|
|
|
|
val = Values.normalize(null, val);
|
|
|
|
val = Values.normalize(null, val);
|
|
|
|
var newCtx = new Context();
|
|
|
|
var newEnv = new Environment();
|
|
|
|
newCtx.addAll(ctx);
|
|
|
|
newEnv.addAll(ctx);
|
|
|
|
newCtx.add(DebugContext.IGNORE);
|
|
|
|
newEnv.add(DebugContext.IGNORE);
|
|
|
|
ctx = newCtx;
|
|
|
|
ctx = newEnv.context();
|
|
|
|
|
|
|
|
|
|
|
|
if (val == Values.NULL) {
|
|
|
|
if (val == Values.NULL) {
|
|
|
|
return new JSONMap()
|
|
|
|
return new JSONMap()
|
|
|
|
@@ -366,6 +382,7 @@ public class SimpleDebugger implements Debugger {
|
|
|
|
if (subtype != null) res.set("subtype", subtype);
|
|
|
|
if (subtype != null) res.set("subtype", subtype);
|
|
|
|
if (className != null) {
|
|
|
|
if (className != null) {
|
|
|
|
res.set("className", className);
|
|
|
|
res.set("className", className);
|
|
|
|
|
|
|
|
res.set("description", className);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (obj instanceof ArrayValue) res.set("description", "Array(" + ((ArrayValue)obj).size() + ")");
|
|
|
|
if (obj instanceof ArrayValue) res.set("description", "Array(" + ((ArrayValue)obj).size() + ")");
|
|
|
|
@@ -381,7 +398,7 @@ public class SimpleDebugger implements Debugger {
|
|
|
|
catch (Exception e) { }
|
|
|
|
catch (Exception e) { }
|
|
|
|
|
|
|
|
|
|
|
|
try { res.set("description", className + (defaultToString ? "" : " { " + Values.toString(ctx, obj) + " }")); }
|
|
|
|
try { res.set("description", className + (defaultToString ? "" : " { " + Values.toString(ctx, obj) + " }")); }
|
|
|
|
catch (EngineException e) { res.set("description", className); }
|
|
|
|
catch (EngineException e) { }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -537,10 +554,12 @@ public class SimpleDebugger implements Debugger {
|
|
|
|
var ctx = new Context(env);
|
|
|
|
var ctx = new Context(env);
|
|
|
|
var awaiter = engine.pushMsg(false, ctx.environment, new Filename("jscript", "eval"), code, codeFrame.frame.thisArg, codeFrame.frame.args);
|
|
|
|
var awaiter = engine.pushMsg(false, ctx.environment, new Filename("jscript", "eval"), code, codeFrame.frame.thisArg, codeFrame.frame.args);
|
|
|
|
|
|
|
|
|
|
|
|
engine.run(true);
|
|
|
|
try {
|
|
|
|
|
|
|
|
engine.run(true);
|
|
|
|
try { return new RunResult(ctx, awaiter.await(), null); }
|
|
|
|
return new RunResult(ctx, awaiter.await(), null);
|
|
|
|
|
|
|
|
}
|
|
|
|
catch (EngineException e) { return new RunResult(ctx, null, e); }
|
|
|
|
catch (EngineException e) { return new RunResult(ctx, null, e); }
|
|
|
|
|
|
|
|
catch (SyntaxException e) { return new RunResult(ctx, null, EngineException.ofSyntax(e.toString())); }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private ObjectValue vscodeAutoSuggest(Context ctx, Object target, String query, boolean variable) {
|
|
|
|
private ObjectValue vscodeAutoSuggest(Context ctx, Object target, String query, boolean variable) {
|
|
|
|
@@ -634,11 +653,10 @@ public class SimpleDebugger implements Debugger {
|
|
|
|
execptionType = CatchType.NONE;
|
|
|
|
execptionType = CatchType.NONE;
|
|
|
|
state = State.RESUMED;
|
|
|
|
state = State.RESUMED;
|
|
|
|
|
|
|
|
|
|
|
|
// idToBptCand.clear();
|
|
|
|
mappings.clear();
|
|
|
|
|
|
|
|
bpLocs.clear();
|
|
|
|
|
|
|
|
|
|
|
|
idToBreakpoint.clear();
|
|
|
|
idToBreakpoint.clear();
|
|
|
|
// locToBreakpoint.clear();
|
|
|
|
|
|
|
|
// tmpBreakpts.clear();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
filenameToId.clear();
|
|
|
|
filenameToId.clear();
|
|
|
|
idToSource.clear();
|
|
|
|
idToSource.clear();
|
|
|
|
@@ -656,6 +674,9 @@ public class SimpleDebugger implements Debugger {
|
|
|
|
stepOutFrame = currFrame = null;
|
|
|
|
stepOutFrame = currFrame = null;
|
|
|
|
stepOutPtr = 0;
|
|
|
|
stepOutPtr = 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (var ctx : contexts.keySet()) ctx.detachDebugger(this);
|
|
|
|
|
|
|
|
contexts.clear();
|
|
|
|
|
|
|
|
|
|
|
|
updateNotifier.next();
|
|
|
|
updateNotifier.next();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@@ -709,16 +730,15 @@ public class SimpleDebugger implements Debugger {
|
|
|
|
var bpt = new Breakpoint(nextId(), regex, line, col, cond);
|
|
|
|
var bpt = new Breakpoint(nextId(), regex, line, col, cond);
|
|
|
|
idToBreakpoint.put(bpt.id, bpt);
|
|
|
|
idToBreakpoint.put(bpt.id, bpt);
|
|
|
|
|
|
|
|
|
|
|
|
var locs = new JSONList();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (var el : mappings.entrySet()) {
|
|
|
|
for (var el : mappings.entrySet()) {
|
|
|
|
bpt.addFunc(el.getKey(), el.getValue());
|
|
|
|
bpt.addFunc(el.getKey(), el.getValue());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for (var el : bpt.resolvedLocations.values()) {
|
|
|
|
var locs = new JSONList();
|
|
|
|
for (var loc : el) {
|
|
|
|
|
|
|
|
locs.add(serializeLocation(loc));
|
|
|
|
for (var loc : bpt.resolvedLocations.values()) {
|
|
|
|
}
|
|
|
|
locs.add(serializeLocation(loc));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ws.send(msg.respond(new JSONMap()
|
|
|
|
ws.send(msg.respond(new JSONMap()
|
|
|
|
@@ -958,10 +978,11 @@ public class SimpleDebugger implements Debugger {
|
|
|
|
) {
|
|
|
|
) {
|
|
|
|
pauseDebug(ctx, null);
|
|
|
|
pauseDebug(ctx, null);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (isBreakpointable && bpLocs.getOrDefault(cf.function.body, new HashMap<>()).containsKey(loc)) {
|
|
|
|
else if (isBreakpointable && bpLocs.containsKey(loc)) {
|
|
|
|
var bp = bpLocs.get(cf.function.body).get(loc);
|
|
|
|
for (var bp : bpLocs.get(loc)) {
|
|
|
|
var ok = bp.condition == null ? true : Values.toBoolean(run(currFrame, bp.condition).result);
|
|
|
|
var ok = bp.condition == null ? true : Values.toBoolean(run(currFrame, bp.condition).result);
|
|
|
|
if (ok) pauseDebug(ctx, bp);
|
|
|
|
if (ok) pauseDebug(ctx, bp);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// else if (isBreakpointable && tmpBreakpts.remove(loc)) pauseDebug(ctx, null);
|
|
|
|
// else if (isBreakpointable && tmpBreakpts.remove(loc)) pauseDebug(ctx, null);
|
|
|
|
else if (isBreakpointable && pendingPause) {
|
|
|
|
else if (isBreakpointable && pendingPause) {
|
|
|
|
@@ -1033,6 +1054,7 @@ public class SimpleDebugger implements Debugger {
|
|
|
|
|
|
|
|
|
|
|
|
public SimpleDebugger attach(DebugContext ctx) {
|
|
|
|
public SimpleDebugger attach(DebugContext ctx) {
|
|
|
|
ctx.attachDebugger(this);
|
|
|
|
ctx.attachDebugger(this);
|
|
|
|
|
|
|
|
contexts.put(ctx, ctx);
|
|
|
|
return this;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|