mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
Wasm: working on step-in and step-over in debugger
This commit is contained in:
parent
159db29757
commit
a6add26aaa
|
@ -51,7 +51,7 @@ public class ControlFlowInfo {
|
|||
for (int i = 0; i < functions.size(); ++i) {
|
||||
var range = functions.get(i);
|
||||
out.println("Range #" + i + ": [" + range.start() + ".." + range.end() + ")");
|
||||
for (var iter = range.iterator(); iter.hasNext(); iter.next()) {
|
||||
for (var iter = range.iterator(0); iter.hasNext(); iter.next()) {
|
||||
out.print(" " + Integer.toHexString(iter.address()));
|
||||
if (iter.isCall()) {
|
||||
out.print(" (call)");
|
||||
|
|
|
@ -21,7 +21,9 @@ public class FunctionControlFlow {
|
|||
int[] offsets;
|
||||
int[] data;
|
||||
|
||||
FunctionControlFlow(int[] offsets, int[] data) {
|
||||
FunctionControlFlow(int start, int end, int[] offsets, int[] data) {
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
this.offsets = offsets;
|
||||
this.data = data;
|
||||
}
|
||||
|
@ -34,7 +36,33 @@ public class FunctionControlFlow {
|
|||
return end;
|
||||
}
|
||||
|
||||
public FunctionControlFlowIterator iterator() {
|
||||
return new FunctionControlFlowIterator(this);
|
||||
public FunctionControlFlowIterator iterator(int index) {
|
||||
return new FunctionControlFlowIterator(this, index);
|
||||
}
|
||||
|
||||
public int count() {
|
||||
return offsets.length;
|
||||
}
|
||||
|
||||
public int findIndex(int address) {
|
||||
var l = 0;
|
||||
var u = offsets.length;
|
||||
while (true) {
|
||||
var i = (l + u) / 2;
|
||||
var t = data[offsets[i]];
|
||||
if (address == t) {
|
||||
return i;
|
||||
} else if (address > t) {
|
||||
l = i + 1;
|
||||
if (l > u) {
|
||||
return i + 1;
|
||||
}
|
||||
} else {
|
||||
u = i - 1;
|
||||
if (u < l) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,9 +18,16 @@ package org.teavm.backend.wasm.debug.info;
|
|||
import com.carrotsearch.hppc.IntArrayList;
|
||||
|
||||
public class FunctionControlFlowBuilder {
|
||||
private int start;
|
||||
private int end;
|
||||
private IntArrayList offsets = new IntArrayList();
|
||||
private IntArrayList data = new IntArrayList();
|
||||
|
||||
public FunctionControlFlowBuilder(int start, int end) {
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
}
|
||||
|
||||
public void addBranch(int position, int[] targets) {
|
||||
offsets.add(data.size() << 1);
|
||||
data.add(position);
|
||||
|
@ -38,6 +45,6 @@ public class FunctionControlFlowBuilder {
|
|||
}
|
||||
|
||||
public FunctionControlFlow build() {
|
||||
return new FunctionControlFlow(offsets.toArray(), data.toArray());
|
||||
return new FunctionControlFlow(start, end, offsets.toArray(), data.toArray());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,8 +24,9 @@ public class FunctionControlFlowIterator {
|
|||
private int offset;
|
||||
private boolean isCall;
|
||||
|
||||
FunctionControlFlowIterator(FunctionControlFlow controlFlow) {
|
||||
FunctionControlFlowIterator(FunctionControlFlow controlFlow, int index) {
|
||||
this.controlFlow = controlFlow;
|
||||
this.index = 0;
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
|
@ -37,6 +38,10 @@ public class FunctionControlFlowIterator {
|
|||
valid = false;
|
||||
}
|
||||
|
||||
public void rewind(int index) {
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
private void fill() {
|
||||
if (!valid) {
|
||||
valid = true;
|
||||
|
|
|
@ -49,13 +49,18 @@ public class LineInfoUnpackedSequence {
|
|||
}
|
||||
|
||||
public InstructionLocation find(int address) {
|
||||
var index = findIndex(address);
|
||||
return index >= 0 ? locations.get(index) : null;
|
||||
}
|
||||
|
||||
public int findIndex(int address) {
|
||||
if (address < startAddress || address >= endAddress) {
|
||||
return null;
|
||||
return -1;
|
||||
}
|
||||
var index = CollectionUtil.binarySearch(locations, address, InstructionLocation::address);
|
||||
if (index < 0) {
|
||||
index = -index;
|
||||
}
|
||||
return locations.get(Math.min(locations.size() - 1, index));
|
||||
return Math.min(locations.size() - 1, index);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,223 @@
|
|||
/*
|
||||
* Copyright 2022 Alexey Andreev.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.teavm.backend.wasm.debug.info;
|
||||
|
||||
import com.carrotsearch.hppc.IntArrayDeque;
|
||||
import com.carrotsearch.hppc.IntHashSet;
|
||||
import com.carrotsearch.hppc.IntSet;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import org.teavm.backend.wasm.debug.parser.DebugInfoParser;
|
||||
import org.teavm.common.ByteArrayAsyncInputStream;
|
||||
import org.teavm.common.CollectionUtil;
|
||||
|
||||
public class StepLocationsFinder {
|
||||
public final DebugInfo debugInfo;
|
||||
private LineInfoSequence lines;
|
||||
private FunctionControlFlow graph;
|
||||
private List<Point> points;
|
||||
private IntArrayDeque queue = new IntArrayDeque();
|
||||
private String currentFileName;
|
||||
private int currentLine;
|
||||
private boolean enterMethod;
|
||||
private IntSet breakpointAddresses = new IntHashSet();
|
||||
private IntSet callAddresses = new IntHashSet();
|
||||
private IntSet visited = new IntHashSet();
|
||||
|
||||
public StepLocationsFinder(DebugInfo debugInfo) {
|
||||
this.debugInfo = debugInfo;
|
||||
}
|
||||
|
||||
public boolean step(String fileName, int line, int address, boolean enterMethod) {
|
||||
address -= debugInfo.offset();
|
||||
updatePoints(address);
|
||||
if (points == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var index = CollectionUtil.binarySearch(points, address, p -> p.address);
|
||||
if (index < 0) {
|
||||
index = -index - 2;
|
||||
}
|
||||
if (index < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this.enterMethod = enterMethod;
|
||||
currentFileName = fileName;
|
||||
currentLine = line;
|
||||
queue.addLast(index);
|
||||
callAddresses.clear();
|
||||
breakpointAddresses.clear();
|
||||
while (!queue.isEmpty()) {
|
||||
processTask();
|
||||
}
|
||||
visited.clear();
|
||||
currentFileName = null;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public int[] getBreakpointAddresses() {
|
||||
return breakpointAddresses.toArray();
|
||||
}
|
||||
|
||||
public int[] getCallAddresses() {
|
||||
return callAddresses.toArray();
|
||||
}
|
||||
|
||||
private void updatePoints(int address) {
|
||||
var lines = debugInfo.lines().find(address);
|
||||
var graph = debugInfo.controlFlow().find(address);
|
||||
if (lines == null || graph == null) {
|
||||
this.lines = null;
|
||||
this.graph = null;
|
||||
points = null;
|
||||
return;
|
||||
}
|
||||
|
||||
if (lines != this.lines || graph != this.graph) {
|
||||
this.lines = lines;
|
||||
this.graph = graph;
|
||||
points = null;
|
||||
}
|
||||
if (points == null) {
|
||||
points = createPoints();
|
||||
}
|
||||
}
|
||||
|
||||
private List<Point> createPoints() {
|
||||
var list = new ArrayList<Point>();
|
||||
var indexInLines = 0;
|
||||
var graphIter = graph.iterator(0);
|
||||
var commandExecutor = new LineInfoCommandExecutor();
|
||||
|
||||
while (indexInLines < lines.commands().size() && graphIter.hasNext()) {
|
||||
boolean nextInGraph;
|
||||
if (graphIter == null) {
|
||||
nextInGraph = false;
|
||||
} else if (indexInLines >= lines.commands().size()) {
|
||||
nextInGraph = true;
|
||||
} else {
|
||||
nextInGraph = lines.commands().get(indexInLines).address() >= graphIter.address();
|
||||
}
|
||||
if (nextInGraph) {
|
||||
var point = new Point(graphIter.address());
|
||||
list.add(point);
|
||||
point.isCall = graphIter.isCall();
|
||||
point.next = graphIter.targets();
|
||||
graphIter.next();
|
||||
} else {
|
||||
var cmd = lines.commands().get(indexInLines++);
|
||||
cmd.acceptVisitor(commandExecutor);
|
||||
var location = commandExecutor.createLocation();
|
||||
if (location != null && location.location() != null) {
|
||||
Point point;
|
||||
if (!list.isEmpty() && list.get(list.size() - 1).address == cmd.address()) {
|
||||
point = list.get(list.size() - 1);
|
||||
} else {
|
||||
point = new Point(cmd.address());
|
||||
list.add(point);
|
||||
}
|
||||
point.location = location.location();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (var point : list) {
|
||||
var next = point.next;
|
||||
if (next == null) {
|
||||
continue;
|
||||
}
|
||||
int j = 0;
|
||||
for (int i = 0; i < next.length; ++i) {
|
||||
var foundIndex = CollectionUtil.binarySearch(list, next[i], p -> p.address);
|
||||
if (foundIndex < 0) {
|
||||
foundIndex = -foundIndex - 1;
|
||||
}
|
||||
if (foundIndex >= list.size()) {
|
||||
continue;
|
||||
}
|
||||
next[j++] = foundIndex;
|
||||
}
|
||||
if (j != next.length) {
|
||||
if (j == 0) {
|
||||
point.next = null;
|
||||
} else {
|
||||
point.next = Arrays.copyOf(next, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
list.trimToSize();
|
||||
return list;
|
||||
}
|
||||
|
||||
private void processTask() {
|
||||
var index = queue.removeFirst();
|
||||
if (!visited.add(index)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var point = points.get(index);
|
||||
if (point.location != null && !isCurrent(point.location)) {
|
||||
breakpointAddresses.add(point.address + debugInfo.offset());
|
||||
return;
|
||||
}
|
||||
if (enterMethod) {
|
||||
breakpointAddresses.add(point.address + debugInfo.offset());
|
||||
callAddresses.add(point.address + debugInfo.offset());
|
||||
}
|
||||
if (point.next != null) {
|
||||
for (var nextIndex : point.next) {
|
||||
queue.addLast(nextIndex);
|
||||
}
|
||||
} else if (index < points.size() - 1) {
|
||||
queue.addLast(index + 1);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isCurrent(Location loc) {
|
||||
return loc.line() == currentLine && loc.file().fullName().equals(currentFileName);
|
||||
}
|
||||
|
||||
private static class Point {
|
||||
int address;
|
||||
int[] next;
|
||||
boolean isCall;
|
||||
Location location;
|
||||
|
||||
Point(int address) {
|
||||
this.address = address;
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
var file = new File("/home/konsoletyper/prog/apache-tomcat-10.0.4/webapps/wasm/classes.wasm");
|
||||
var input = new ByteArrayAsyncInputStream(Files.readAllBytes(file.toPath()));
|
||||
var parser = new DebugInfoParser(input);
|
||||
input.readFully(parser::parse);
|
||||
var debugInfo = parser.getDebugInfo();
|
||||
|
||||
var finder = new StepLocationsFinder(debugInfo);
|
||||
finder.step("org/teavm/samples/wasi/WasiTest2.java", 9, 0x943e + debugInfo.offset(), false);
|
||||
System.out.println(Arrays.toString(finder.getBreakpointAddresses()));
|
||||
}
|
||||
}
|
|
@ -31,7 +31,7 @@ import org.teavm.backend.wasm.parser.Opcode;
|
|||
public class ControlFlowParser implements CodeSectionListener, CodeListener, AddressListener {
|
||||
private int previousAddress;
|
||||
private int address;
|
||||
private FunctionControlFlowBuilder cfb;
|
||||
private int startAddress;
|
||||
private List<Branch> branches = new ArrayList<>();
|
||||
private List<FunctionControlFlow> ranges = new ArrayList<>();
|
||||
private List<Branch> pendingBranches = new ArrayList<>();
|
||||
|
@ -50,7 +50,7 @@ public class ControlFlowParser implements CodeSectionListener, CodeListener, Add
|
|||
|
||||
@Override
|
||||
public boolean functionStart(int index, int size) {
|
||||
cfb = new FunctionControlFlowBuilder();
|
||||
startAddress = address;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -71,7 +71,7 @@ public class ControlFlowParser implements CodeSectionListener, CodeListener, Add
|
|||
|
||||
private int startBlock(boolean loop) {
|
||||
var token = blocks.size();
|
||||
var branch = !loop ? newBranch(false) : null;
|
||||
var branch = !loop ? newPendingBranch(false) : null;
|
||||
var block = new Block(branch, address);
|
||||
blocks.add(block);
|
||||
if (branch != null) {
|
||||
|
@ -169,6 +169,7 @@ public class ControlFlowParser implements CodeSectionListener, CodeListener, Add
|
|||
|
||||
@Override
|
||||
public void functionEnd() {
|
||||
var cfb = new FunctionControlFlowBuilder(startAddress, address);
|
||||
for (var branch : branches) {
|
||||
if (branch.isCall) {
|
||||
cfb.addCall(branch.address, branch.targets.toArray());
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
package org.teavm.debugging;
|
||||
|
||||
import com.carrotsearch.hppc.IntHashSet;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Base64;
|
||||
import java.util.Collection;
|
||||
|
@ -25,9 +26,11 @@ import java.util.LinkedHashSet;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
import org.teavm.backend.wasm.debug.info.DebugInfo;
|
||||
import org.teavm.backend.wasm.debug.info.LineInfoFileCommand;
|
||||
import org.teavm.backend.wasm.debug.info.MethodInfo;
|
||||
import org.teavm.backend.wasm.debug.info.StepLocationsFinder;
|
||||
import org.teavm.backend.wasm.debug.parser.DebugInfoParser;
|
||||
import org.teavm.common.ByteArrayAsyncInputStream;
|
||||
import org.teavm.common.Promise;
|
||||
|
@ -53,6 +56,7 @@ public class Debugger {
|
|||
private JavaScriptDebugger javaScriptDebugger;
|
||||
private DebugInformationProvider debugInformationProvider;
|
||||
private List<JavaScriptBreakpoint> temporaryBreakpoints = new ArrayList<>();
|
||||
private Predicate<JavaScriptBreakpoint> temporaryBreakpointHandler;
|
||||
private Map<JavaScriptScript, DebugInformation> debugInformationMap = new HashMap<>();
|
||||
private Map<String, Set<DebugInformation>> debugInformationFileMap = new HashMap<>();
|
||||
private Map<JavaScriptScript, DebugInfo> wasmDebugInfoMap = new HashMap<>();
|
||||
|
@ -65,6 +69,7 @@ public class Debugger {
|
|||
private CallFrame[] callStack;
|
||||
private Set<String> scriptNames = new LinkedHashSet<>();
|
||||
private Set<String> allSourceFiles = new LinkedHashSet<>();
|
||||
private StepLocationsFinder wasmStepLocationsFinder;
|
||||
|
||||
public Debugger(JavaScriptDebugger javaScriptDebugger, DebugInformationProvider debugInformationProvider) {
|
||||
this.javaScriptDebugger = javaScriptDebugger;
|
||||
|
@ -113,51 +118,57 @@ public class Debugger {
|
|||
if (callStack == null || callStack.length == 0) {
|
||||
return jsStep(enterMethod);
|
||||
}
|
||||
var recentFrame = callStack[0];
|
||||
if (recentFrame.getLocation() == null || recentFrame.getLocation().getFileName() == null
|
||||
|| recentFrame.getLocation().getLine() < 0) {
|
||||
var frame = callStack[0];
|
||||
if (frame.getLocation() == null || frame.getLocation().getFileName() == null
|
||||
|| frame.getLocation().getLine() < 0) {
|
||||
return jsStep(enterMethod);
|
||||
}
|
||||
var successors = new HashSet<JavaScriptLocation>();
|
||||
boolean first = true;
|
||||
loop:
|
||||
for (var frame : callStack) {
|
||||
var script = frame.getOriginalLocation().getScript();
|
||||
var hasSuccessors = false;
|
||||
if (frame.getLocation() != null && frame.getLocation().getFileName() != null
|
||||
&& frame.getLocation().getLine() >= 0) {
|
||||
switch (script.getLanguage()) {
|
||||
case JS:
|
||||
if (!addJsBreakpoints(frame, script, enterMethod, first, successors)) {
|
||||
break loop;
|
||||
}
|
||||
hasSuccessors = addJsBreakpoints(frame, script, enterMethod, successors);
|
||||
break;
|
||||
case WASM: {
|
||||
var info = wasmDebugInfoMap.get(script);
|
||||
if (info != null) {
|
||||
return enterMethod ? javaScriptDebugger.stepInto() : javaScriptDebugger.stepOver();
|
||||
var promise = stepWasm(frame, enterMethod);
|
||||
if (promise != null) {
|
||||
return promise;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case UNKNOWN:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
enterMethod = false;
|
||||
first = false;
|
||||
}
|
||||
|
||||
if (hasSuccessors) {
|
||||
return jsStep(enterMethod);
|
||||
} else {
|
||||
return createTemporaryBreakpoints(successors, null).thenAsync(v -> javaScriptDebugger.stepOut());
|
||||
}
|
||||
}
|
||||
|
||||
private Promise<Void> createTemporaryBreakpoints(Collection<JavaScriptLocation> locations,
|
||||
Predicate<JavaScriptBreakpoint> handler) {
|
||||
var jsBreakpointPromises = new ArrayList<Promise<Void>>();
|
||||
for (var successor : successors) {
|
||||
jsBreakpointPromises.add(javaScriptDebugger.createBreakpoint(successor)
|
||||
for (var location : locations) {
|
||||
jsBreakpointPromises.add(javaScriptDebugger.createBreakpoint(location)
|
||||
.thenVoid(temporaryBreakpoints::add));
|
||||
}
|
||||
return Promise.allVoid(jsBreakpointPromises).thenAsync(v -> javaScriptDebugger.resume());
|
||||
temporaryBreakpointHandler = handler;
|
||||
return Promise.allVoid(jsBreakpointPromises);
|
||||
}
|
||||
|
||||
private boolean addJsBreakpoints(CallFrame frame, JavaScriptScript script, boolean enterMethod, boolean first,
|
||||
private boolean addJsBreakpoints(CallFrame frame, JavaScriptScript script, boolean enterMethod,
|
||||
Set<JavaScriptLocation> successors) {
|
||||
var debugInfo = debugInformationMap.get(script);
|
||||
boolean exits;
|
||||
if (frame.getLocation() != null && frame.getLocation().getFileName() != null
|
||||
&& frame.getLocation().getLine() >= 0 && debugInfo != null) {
|
||||
exits = addFollowing(debugInfo, frame.getLocation(), script, new HashSet<>(), successors);
|
||||
if (debugInfo == null) {
|
||||
return false;
|
||||
}
|
||||
addFollowing(debugInfo, frame.getLocation(), script, new HashSet<>(), successors);
|
||||
if (enterMethod) {
|
||||
var successorFinder = new CallSiteSuccessorFinder(debugInfo, script, successors);
|
||||
var callSites = debugInfo.getCallSites(frame.getLocation());
|
||||
|
@ -165,18 +176,33 @@ public class Debugger {
|
|||
callSite.acceptVisitor(successorFinder);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
exits = true;
|
||||
return true;
|
||||
}
|
||||
if (!exits) {
|
||||
|
||||
private Promise<Void> stepWasm(CallFrame frame, boolean enterMethod) {
|
||||
var debugInfo = wasmDebugInfoMap.get(frame.getOriginalLocation().getScript());
|
||||
if (debugInfo == null || debugInfo.controlFlow() == null || debugInfo.lines() == null) {
|
||||
return null;
|
||||
}
|
||||
if (wasmStepLocationsFinder == null || wasmStepLocationsFinder.debugInfo != debugInfo) {
|
||||
wasmStepLocationsFinder = new StepLocationsFinder(debugInfo);
|
||||
}
|
||||
wasmStepLocationsFinder.step(frame.getLocation().getFileName(), frame.getLocation().getLine(),
|
||||
frame.getOriginalLocation().getColumn(), enterMethod);
|
||||
|
||||
var locations = new ArrayList<JavaScriptLocation>();
|
||||
for (var breakpointAddress : wasmStepLocationsFinder.getBreakpointAddresses()) {
|
||||
locations.add(new JavaScriptLocation(frame.getOriginalLocation().getScript(), 0, breakpointAddress));
|
||||
}
|
||||
var callAddresses = IntHashSet.from(wasmStepLocationsFinder.getCallAddresses());
|
||||
var result = createTemporaryBreakpoints(locations, br -> {
|
||||
if (br != null && br.isValid() && callAddresses.contains(br.getLocation().getColumn())) {
|
||||
javaScriptDebugger.stepInto();
|
||||
return false;
|
||||
}
|
||||
if (!first && frame.getLocation() != null) {
|
||||
for (var location : debugInfo.getGeneratedLocations(frame.getLocation())) {
|
||||
successors.add(new JavaScriptLocation(script, location.getLine(), location.getColumn()));
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return true;
|
||||
});
|
||||
return result.thenVoid(x -> javaScriptDebugger.stepOut());
|
||||
}
|
||||
|
||||
static class CallSiteSuccessorFinder implements DebuggerCallSiteVisitor {
|
||||
|
@ -599,21 +625,30 @@ public class Debugger {
|
|||
}
|
||||
|
||||
private void firePaused(JavaScriptBreakpoint breakpoint) {
|
||||
List<JavaScriptBreakpoint> temporaryBreakpoints = new ArrayList<>(this.temporaryBreakpoints);
|
||||
var temporaryBreakpoints = new ArrayList<>(this.temporaryBreakpoints);
|
||||
var handler = temporaryBreakpointHandler;
|
||||
this.temporaryBreakpoints.clear();
|
||||
List<Promise<Void>> promises = new ArrayList<>();
|
||||
for (JavaScriptBreakpoint jsBreakpoint : temporaryBreakpoints) {
|
||||
temporaryBreakpointHandler = null;
|
||||
var promises = new ArrayList<Promise<Void>>();
|
||||
for (var jsBreakpoint : temporaryBreakpoints) {
|
||||
promises.add(jsBreakpoint.destroy());
|
||||
}
|
||||
callStack = null;
|
||||
Promise.allVoid(promises).thenVoid(v -> {
|
||||
Breakpoint javaBreakpoint = null;
|
||||
if (breakpoint != null && !temporaryBreakpoints.contains(breakpoint)) {
|
||||
JavaScriptBreakpoint tmpBreakpoint = null;
|
||||
if (breakpoint != null) {
|
||||
if (temporaryBreakpoints.contains(breakpoint)) {
|
||||
tmpBreakpoint = breakpoint;
|
||||
} else {
|
||||
javaBreakpoint = breakpointMap.get(breakpoint);
|
||||
}
|
||||
for (DebuggerListener listener : getListeners()) {
|
||||
}
|
||||
if (handler == null || !handler.test(tmpBreakpoint)) {
|
||||
for (var listener : getListeners()) {
|
||||
listener.paused(javaBreakpoint);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user