diff --git a/teavm-chrome-rdp/src/main/java/org/teavm/chromerpd/ChromeRDPDebugger.java b/teavm-chrome-rdp/src/main/java/org/teavm/chromerpd/ChromeRDPDebugger.java new file mode 100644 index 000000000..c238e711c --- /dev/null +++ b/teavm-chrome-rdp/src/main/java/org/teavm/chromerpd/ChromeRDPDebugger.java @@ -0,0 +1,143 @@ +package org.teavm.chromerpd; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import org.teavm.debugging.*; + +/** + * + * @author Alexey Andreev + */ +public class ChromeRDPDebugger implements JavaScriptDebugger { + private ChromeRDPDebuggerEndpoint endpoint; + private List listeners = new ArrayList<>(); + private Set breakpoints = new HashSet<>(); + + void setEndpoint(ChromeRDPDebuggerEndpoint endpoint) { + if (this.endpoint == endpoint) { + return; + } + this.endpoint = endpoint; + if (endpoint != null) { + for (RDPBreakpoint breakpoint : breakpoints) { + endpoint.updateBreakpoint(breakpoint); + } + for (JavaScriptDebuggerListener listener : listeners) { + listener.attached(); + } + } else { + for (JavaScriptDebuggerListener listener : listeners) { + listener.detached(); + } + } + } + + @Override + public void addListener(JavaScriptDebuggerListener listener) { + listeners.add(listener); + } + + @Override + public void removeListener(JavaScriptDebuggerListener listener) { + listeners.remove(listener); + } + + @Override + public void suspend() { + if (endpoint != null) { + endpoint.suspend(); + } + } + + @Override + public void resume() { + if (endpoint != null) { + endpoint.resume(); + } + } + + @Override + public void stepInto() { + if (endpoint != null) { + endpoint.stepInto(); + } + } + + @Override + public void stepOut() { + if (endpoint != null) { + endpoint.stepOut(); + } + } + + @Override + public void stepOver() { + if (endpoint != null) { + endpoint.stepOver(); + } + } + + @Override + public void continueToLocation(JavaScriptLocation location) { + if (endpoint != null) { + endpoint.continueToLocation(location); + } + } + + @Override + public boolean isSuspended() { + return endpoint != null && endpoint.isSuspended(); + } + + @Override + public boolean isAttached() { + return endpoint != null; + } + + @Override + public JavaScriptCallFrame[] getCallStack() { + return endpoint != null ? endpoint.getCallStack() : null; + } + + @Override + public JavaScriptBreakpoint getCurrentBreakpoint() { + return endpoint != null ? endpoint.getCurrentBreakpoint() : null; + } + + @Override + public JavaScriptBreakpoint createBreakpoint(JavaScriptLocation location) { + RDPBreakpoint breakpoint = new RDPBreakpoint(this, location); + breakpoints.add(breakpoint); + if (endpoint != null) { + endpoint.updateBreakpoint(breakpoint); + } + return breakpoint; + } + + void destroyBreakpoint(RDPBreakpoint breakpoint) { + breakpoints.remove(breakpoint); + if (endpoint != null) { + endpoint.destroyBreakpoint(breakpoint); + } + } + + void fireResumed() { + for (JavaScriptDebuggerListener listener : listeners) { + listener.resumed(); + } + } + + void firePaused() { + for (JavaScriptDebuggerListener listener : listeners) { + listener.paused(); + } + } + + void fireScriptAdded(String script) { + for (JavaScriptDebuggerListener listener : listeners) { + listener.scriptAdded(script); + } + } +} diff --git a/teavm-chrome-rdp/src/main/java/org/teavm/chromerpd/ChromeRDPDebuggerEndpoint.java b/teavm-chrome-rdp/src/main/java/org/teavm/chromerpd/ChromeRDPDebuggerEndpoint.java index f5c56263f..85b33ddeb 100644 --- a/teavm-chrome-rdp/src/main/java/org/teavm/chromerpd/ChromeRDPDebuggerEndpoint.java +++ b/teavm-chrome-rdp/src/main/java/org/teavm/chromerpd/ChromeRDPDebuggerEndpoint.java @@ -16,14 +16,9 @@ package org.teavm.chromerpd; import java.io.IOException; -import java.util.ArrayList; import java.util.HashMap; -import java.util.List; import java.util.Map; -import javax.websocket.OnClose; -import javax.websocket.OnMessage; -import javax.websocket.OnOpen; -import javax.websocket.Session; +import javax.websocket.*; import javax.websocket.server.ServerEndpoint; import org.codehaus.jackson.JsonNode; import org.codehaus.jackson.map.ObjectMapper; @@ -39,8 +34,7 @@ import org.teavm.debugging.*; * @author Alexey Andreev */ @ServerEndpoint("/") -public class ChromeRDPDebuggerEndpoint implements JavaScriptDebugger { - private List listeners = new ArrayList<>(); +public class ChromeRDPDebuggerEndpoint { private Session session; private RDPCallFrame[] callStack = new RDPCallFrame[0]; private Map scripts = new HashMap<>(); @@ -50,24 +44,24 @@ public class ChromeRDPDebuggerEndpoint implements JavaScriptDebugger { private Map deferredResponses = new HashMap<>(); private int messageIdGenerator; boolean closed; - private ChromeRDPContainer container; + private ChromeRDPDebugger debugger; @OnOpen public void open(Session session) { this.session = session; - Object container = session.getUserProperties().get("rdp.container"); - if (container instanceof ChromeRDPContainer) { - this.container = (ChromeRDPContainer)container; - this.container.setDebugger(this); + Object debugger = session.getUserProperties().get("chrome.rdp"); + if (debugger instanceof ChromeRDPDebugger) { + this.debugger = (ChromeRDPDebugger)debugger; + this.debugger.setEndpoint(this); } } @OnClose public void close() { closed = true; - if (this.container != null) { - this.container.setDebugger(null); - this.container = null; + if (this.debugger != null) { + this.debugger.setEndpoint(null); + this.debugger = null; } } @@ -104,9 +98,7 @@ public class ChromeRDPDebuggerEndpoint implements JavaScriptDebugger { for (int i = 0; i < callFrames.length; ++i) { callFrames[i] = map(callFrameDTOs[i]); } - for (JavaScriptDebuggerListener listener : listeners) { - listener.paused(); - } + debugger.firePaused(); } RDPCallFrame map(CallFrameDTO dto) { @@ -127,9 +119,7 @@ public class ChromeRDPDebuggerEndpoint implements JavaScriptDebugger { private void fireResumed() { suspended = false; - for (JavaScriptDebuggerListener listener : listeners) { - listener.resumed(); - } + debugger.fireResumed(); } private void scriptParsed(ScriptParsedNotification params) { @@ -138,19 +128,7 @@ public class ChromeRDPDebuggerEndpoint implements JavaScriptDebugger { } scripts.put(params.getScriptId(), params.getUrl()); scriptIds.put(params.getUrl(), params.getScriptId()); - for (JavaScriptDebuggerListener listener : listeners) { - listener.scriptAdded(params.getUrl()); - } - } - - @Override - public void addListener(JavaScriptDebuggerListener listener) { - listeners.add(listener); - } - - @Override - public void removeListener(JavaScriptDebuggerListener listener) { - listeners.remove(listener); + debugger.fireScriptAdded(params.getUrl()); } private void sendMessage(Message message) { @@ -165,7 +143,6 @@ public class ChromeRDPDebuggerEndpoint implements JavaScriptDebugger { } } - @Override public void suspend() { if (closed) { return; @@ -175,7 +152,6 @@ public class ChromeRDPDebuggerEndpoint implements JavaScriptDebugger { sendMessage(message); } - @Override public void resume() { if (closed) { return; @@ -185,7 +161,6 @@ public class ChromeRDPDebuggerEndpoint implements JavaScriptDebugger { sendMessage(message); } - @Override public void stepInto() { if (closed) { return; @@ -195,7 +170,6 @@ public class ChromeRDPDebuggerEndpoint implements JavaScriptDebugger { sendMessage(message); } - @Override public void stepOut() { if (closed) { return; @@ -205,7 +179,6 @@ public class ChromeRDPDebuggerEndpoint implements JavaScriptDebugger { sendMessage(message); } - @Override public void stepOver() { if (closed) { return; @@ -215,7 +188,6 @@ public class ChromeRDPDebuggerEndpoint implements JavaScriptDebugger { sendMessage(message); } - @Override public void continueToLocation(JavaScriptLocation location) { Message message = new Message(); message.setMethod("Debugger.continueToLocation"); @@ -225,28 +197,24 @@ public class ChromeRDPDebuggerEndpoint implements JavaScriptDebugger { sendMessage(message); } - @Override public boolean isSuspended() { return suspended; } - @Override public JavaScriptCallFrame[] getCallStack() { return callStack; } - @Override public JavaScriptBreakpoint getCurrentBreakpoint() { return null; } - @Override - public JavaScriptBreakpoint createBreakpoint(JavaScriptLocation location) { + public void updateBreakpoint(RDPBreakpoint breakpoint) { Message message = new Message(); message.setId(messageIdGenerator++); message.setMethod("Debugger.setBreakpoint"); SetBreakpointCommand params = new SetBreakpointCommand(); - params.setLocation(unmap(location)); + params.setLocation(unmap(breakpoint.getLocation())); message.setParams(mapper.valueToTree(params)); Deferred deferred = new Deferred(); deferredResponses.put(message.getId(), deferred); @@ -254,18 +222,20 @@ public class ChromeRDPDebuggerEndpoint implements JavaScriptDebugger { try { SetBreakpointResponse response = mapper.reader(SetBreakpointResponse.class) .readValue((JsonNode)deferred.get()); - return new RDPBreakpoint(response.getBreakpointId(), this, map(response.getActualLocation())); + breakpoint.chromeId = response.getBreakpointId(); } catch (IOException e) { throw new RuntimeException(e); } } void destroyBreakpoint(RDPBreakpoint breakpoint) { - Message message = new Message(); - message.setMethod("Debugger.removeBreakpoint"); - RemoveBreakpointCommand params = new RemoveBreakpointCommand(); - params.setBreakpointId(breakpoint.getChromeId()); - message.setParams(mapper.valueToTree(params)); - sendMessage(message); + if (breakpoint.chromeId != null) { + Message message = new Message(); + message.setMethod("Debugger.removeBreakpoint"); + RemoveBreakpointCommand params = new RemoveBreakpointCommand(); + params.setBreakpointId(breakpoint.chromeId); + message.setParams(mapper.valueToTree(params)); + sendMessage(message); + } } } diff --git a/teavm-chrome-rdp/src/main/java/org/teavm/chromerpd/ChromeRDPServer.java b/teavm-chrome-rdp/src/main/java/org/teavm/chromerpd/ChromeRDPServer.java index aaeb2d3fe..8b312abc3 100644 --- a/teavm-chrome-rdp/src/main/java/org/teavm/chromerpd/ChromeRDPServer.java +++ b/teavm-chrome-rdp/src/main/java/org/teavm/chromerpd/ChromeRDPServer.java @@ -16,7 +16,6 @@ package org.teavm.chromerpd; import java.util.*; -import java.util.concurrent.atomic.AtomicReference; import javax.websocket.Decoder; import javax.websocket.Encoder; import javax.websocket.Extension; @@ -35,8 +34,7 @@ import org.teavm.debugging.JavaScriptDebugger; public class ChromeRDPServer { private int port = 2357; private Appendable output = System.err; - private AtomicReference debugger = new AtomicReference<>(); - private List listeners = new ArrayList<>(); + private ChromeRDPDebugger debugger = new ChromeRDPDebugger(); public int getPort() { return port; @@ -54,14 +52,6 @@ public class ChromeRDPServer { this.output = output; } - public void addListener(ChromeRDPServerListener listener) { - listeners.add(listener); - } - - public void removeListener(ChromeRDPServerListener listener) { - listeners.remove(listener); - } - public void start() { final Server server = new Server(); ServerConnector connector = new ServerConnector(server); @@ -88,11 +78,7 @@ public class ChromeRDPServer { private Map userProperties = new HashMap<>(); public RPDEndpointConfig() { - userProperties.put("rdp.container", new ChromeRDPContainer() { - @Override public void setDebugger(ChromeRDPDebuggerEndpoint debugger) { - ChromeRDPServer.this.setDebugger(debugger); - } - }); + userProperties.put("chrome.rdp", debugger); } @Override @@ -137,19 +123,6 @@ public class ChromeRDPServer { } public JavaScriptDebugger getDebugger() { - return debugger.get(); - } - - void setDebugger(JavaScriptDebugger debugger) { - if (debugger != null) { - if (!this.debugger.compareAndSet(null, debugger)) { - throw new IllegalStateException("Can't handle more than one connection"); - } - for (ChromeRDPServerListener listener : listeners) { - listener.connected(this); - } - } else { - this.debugger.set(null); - } + return debugger; } } diff --git a/teavm-chrome-rdp/src/main/java/org/teavm/chromerpd/ChromeRDPServerListener.java b/teavm-chrome-rdp/src/main/java/org/teavm/chromerpd/ChromeRDPServerListener.java deleted file mode 100644 index bd2822b6c..000000000 --- a/teavm-chrome-rdp/src/main/java/org/teavm/chromerpd/ChromeRDPServerListener.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2014 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.chromerpd; - -/** - * - * @author Alexey Andreev - */ -public interface ChromeRDPServerListener { - void connected(ChromeRDPServer server); -} diff --git a/teavm-chrome-rdp/src/main/java/org/teavm/chromerpd/RDPBreakpoint.java b/teavm-chrome-rdp/src/main/java/org/teavm/chromerpd/RDPBreakpoint.java index 55927e262..b4e0c37f8 100644 --- a/teavm-chrome-rdp/src/main/java/org/teavm/chromerpd/RDPBreakpoint.java +++ b/teavm-chrome-rdp/src/main/java/org/teavm/chromerpd/RDPBreakpoint.java @@ -23,20 +23,15 @@ import org.teavm.debugging.JavaScriptLocation; * @author Alexey Andreev */ public class RDPBreakpoint implements JavaScriptBreakpoint { - private String chromeId; - private ChromeRDPDebuggerEndpoint debugger; + String chromeId; + private ChromeRDPDebugger debugger; private JavaScriptLocation location; - public RDPBreakpoint(String chromeId, ChromeRDPDebuggerEndpoint debugger, JavaScriptLocation location) { - this.chromeId = chromeId; + RDPBreakpoint(ChromeRDPDebugger debugger, JavaScriptLocation location) { this.debugger = debugger; this.location = location; } - public String getChromeId() { - return chromeId; - } - @Override public JavaScriptLocation getLocation() { return location; @@ -44,8 +39,14 @@ public class RDPBreakpoint implements JavaScriptBreakpoint { @Override public void destroy() { - if (!debugger.closed) { + if (debugger != null) { debugger.destroyBreakpoint(this); + debugger = null; } } + + @Override + public boolean isValid() { + return false; + } } diff --git a/teavm-chrome-rdp/src/main/js/chrome/manifest.json b/teavm-chrome-rdp/src/main/js/chrome/manifest.json index 5b15ec3b1..22d5280e3 100644 --- a/teavm-chrome-rdp/src/main/js/chrome/manifest.json +++ b/teavm-chrome-rdp/src/main/js/chrome/manifest.json @@ -13,7 +13,6 @@ }, "background": { - "scripts": ["main.js"], - "persistent": false + "scripts": ["main.js"] } } \ No newline at end of file diff --git a/teavm-core/src/main/java/org/teavm/codegen/SourceWriter.java b/teavm-core/src/main/java/org/teavm/codegen/SourceWriter.java index 058e3656e..aabebf1e5 100644 --- a/teavm-core/src/main/java/org/teavm/codegen/SourceWriter.java +++ b/teavm-core/src/main/java/org/teavm/codegen/SourceWriter.java @@ -169,6 +169,7 @@ public class SourceWriter implements Appendable, LocationProvider { if (!minified) { innerWriter.append('\n'); column = 0; + ++line; lineStart = true; } return this; diff --git a/teavm-core/src/main/java/org/teavm/debugging/Breakpoint.java b/teavm-core/src/main/java/org/teavm/debugging/Breakpoint.java index 4bf0b9aef..e3bb0d29a 100644 --- a/teavm-core/src/main/java/org/teavm/debugging/Breakpoint.java +++ b/teavm-core/src/main/java/org/teavm/debugging/Breakpoint.java @@ -15,6 +15,7 @@ */ package org.teavm.debugging; +import java.util.ArrayList; import java.util.List; /** @@ -23,16 +24,13 @@ import java.util.List; */ public class Breakpoint { private Debugger debugger; - private List jsBreakpoints; + List jsBreakpoints = new ArrayList<>(); private SourceLocation location; + boolean valid; - Breakpoint(Debugger debugger, List jsBreakpoints, SourceLocation location) { + Breakpoint(Debugger debugger, SourceLocation location) { this.debugger = debugger; - this.jsBreakpoints = jsBreakpoints; this.location = location; - for (JavaScriptBreakpoint jsBreakpoint : jsBreakpoints) { - debugger.breakpointMap.put(jsBreakpoint, this); - } } public SourceLocation getLocation() { @@ -44,11 +42,17 @@ public class Breakpoint { jsBreakpoint.destroy(); debugger.breakpointMap.remove(jsBreakpoint); } + debugger.breakpoints.remove(this); jsBreakpoints.clear(); + debugger = null; + } + + public boolean isValid() { + return valid; } public boolean isDestroyed() { - return jsBreakpoints.isEmpty(); + return debugger == null; } public Debugger getDebugger() { diff --git a/teavm-core/src/main/java/org/teavm/debugging/DebugInformation.java b/teavm-core/src/main/java/org/teavm/debugging/DebugInformation.java index 9cdf877f5..b47a7cf5b 100644 --- a/teavm-core/src/main/java/org/teavm/debugging/DebugInformation.java +++ b/teavm-core/src/main/java/org/teavm/debugging/DebugInformation.java @@ -203,8 +203,8 @@ public class DebugInformation { ensureLine(sourceLine); generatedLocationSize.set(sourceLine, generatedLocationSize.get(sourceLine) + 1); int slot = generatedLocationStart.get(sourceLine); - slot = addData(slot, column); slot = addData(slot, line); + slot = addData(slot, column); generatedLocationStart.set(sourceLine, slot); } diff --git a/teavm-core/src/main/java/org/teavm/debugging/DebugInformationBuilder.java b/teavm-core/src/main/java/org/teavm/debugging/DebugInformationBuilder.java index 5f132ff5f..2d3350418 100644 --- a/teavm-core/src/main/java/org/teavm/debugging/DebugInformationBuilder.java +++ b/teavm-core/src/main/java/org/teavm/debugging/DebugInformationBuilder.java @@ -109,6 +109,13 @@ public class DebugInformationBuilder implements DebugInformationEmitter { IntegerArray values = new IntegerArray(1); public void add(LocationProvider location, int value) { + if (lines.size() > 1) { + int last = lines.size() - 1; + if (lines.get(last) == location.getLine() && columns.get(last) == location.getColumn()) { + values.set(last, value); + return; + } + } lines.add(location.getLine()); columns.add(location.getColumn()); values.add(value); diff --git a/teavm-core/src/main/java/org/teavm/debugging/DebugInformationReader.java b/teavm-core/src/main/java/org/teavm/debugging/DebugInformationReader.java index 868c0d09b..59ecb4d86 100644 --- a/teavm-core/src/main/java/org/teavm/debugging/DebugInformationReader.java +++ b/teavm-core/src/main/java/org/teavm/debugging/DebugInformationReader.java @@ -41,6 +41,7 @@ class DebugInformationReader { debugInfo.classMapping = readMapping(); debugInfo.methodMapping = readMapping(); debugInfo.rebuildFileDescriptions(); + debugInfo.rebuildMaps(); return debugInfo; } diff --git a/teavm-core/src/main/java/org/teavm/debugging/DebugInformationWriter.java b/teavm-core/src/main/java/org/teavm/debugging/DebugInformationWriter.java index 0029978d9..f50d6ba1f 100644 --- a/teavm-core/src/main/java/org/teavm/debugging/DebugInformationWriter.java +++ b/teavm-core/src/main/java/org/teavm/debugging/DebugInformationWriter.java @@ -52,8 +52,9 @@ class DebugInformationWriter { int[] lines = mapping.lines.clone(); int last = 0; for (int i = 0; i < lines.length; ++i) { - last = lines[i]; + int next = lines[i]; lines[i] -= last; + last = next; } writeRle(lines); resetRelativeNumber(); diff --git a/teavm-core/src/main/java/org/teavm/debugging/Debugger.java b/teavm-core/src/main/java/org/teavm/debugging/Debugger.java index 2c8994886..c5abc91f2 100644 --- a/teavm-core/src/main/java/org/teavm/debugging/Debugger.java +++ b/teavm-core/src/main/java/org/teavm/debugging/Debugger.java @@ -33,6 +33,7 @@ public class Debugger { private Map> debugInformationFileMap = new HashMap<>(); private Map scriptMap = new HashMap<>(); Map breakpointMap = new HashMap<>(); + Set breakpoints = new HashSet<>(); private CallFrame[] callStack; public Debugger(JavaScriptDebugger javaScriptDebugger, DebugInformationProvider debugInformationProvider) { @@ -58,23 +59,14 @@ public class Debugger { } public void stepInto() { - if (!javaScriptDebugger.isSuspended()) { - return; - } javaScriptDebugger.stepInto(); } public void stepOut() { - if (!javaScriptDebugger.isSuspended()) { - return; - } javaScriptDebugger.stepOut(); } public void stepOver() { - if (!javaScriptDebugger.isSuspended()) { - return; - } javaScriptDebugger.stepOver(); } @@ -114,19 +106,49 @@ public class Debugger { } public Breakpoint createBreakpoint(SourceLocation location) { - List jsBreakpoints = new ArrayList<>(); + Breakpoint breakpoint = new Breakpoint(this, location); + breakpoints.add(breakpoint); + updateInternalBreakpoints(breakpoint); + updateBreakpointStatus(breakpoint, false); + return breakpoint; + } + + public Set getBreakpoints() { + return Collections.unmodifiableSet(breakpoints); + } + + void updateInternalBreakpoints(Breakpoint breakpoint) { + for (JavaScriptBreakpoint jsBreakpoint : breakpoint.jsBreakpoints) { + breakpointMap.remove(jsBreakpoint); + jsBreakpoint.destroy(); + } + SourceLocation location = breakpoint.getLocation(); for (DebugInformation debugInformation : debugInformationBySource(location.getFileName())) { Collection locations = debugInformation.getGeneratedLocations(location); for (GeneratedLocation genLocation : locations) { JavaScriptLocation jsLocation = new JavaScriptLocation(scriptMap.get(debugInformation), genLocation.getLine(), genLocation.getColumn()); JavaScriptBreakpoint jsBreakpoint = javaScriptDebugger.createBreakpoint(jsLocation); - if (jsBreakpoint != null) { - jsBreakpoints.add(jsBreakpoint); + breakpoint.jsBreakpoints.add(jsBreakpoint); + } + } + } + + void updateBreakpointStatus(Breakpoint breakpoint, boolean fireEvent) { + boolean valid = false; + for (JavaScriptBreakpoint jsBreakpoint : breakpoint.jsBreakpoints) { + if (jsBreakpoint.isValid()) { + valid = true; + } + } + if (breakpoint.valid != valid) { + breakpoint.valid = valid; + if (fireEvent) { + for (DebuggerListener listener : listeners) { + listener.breakpointStatusChanged(breakpoint); } } } - return !jsBreakpoints.isEmpty() ? new Breakpoint(this, jsBreakpoints, location) : null; } public CallFrame[] getCallStack() { @@ -178,6 +200,14 @@ public class Debugger { list.add(debugInfo); } scriptMap.put(debugInfo, name); + for (Breakpoint breakpoint : breakpoints) { + updateInternalBreakpoints(breakpoint); + updateBreakpointStatus(breakpoint, true); + } + } + + public boolean isAttached() { + return javaScriptDebugger.isAttached(); } private JavaScriptDebuggerListener javaScriptListener = new JavaScriptDebuggerListener() { @@ -203,5 +233,35 @@ public class Debugger { public void scriptAdded(String name) { addScript(name); } + + @Override + public void attached() { + for (Breakpoint breakpoint : breakpoints) { + updateInternalBreakpoints(breakpoint); + updateBreakpointStatus(breakpoint, false); + } + for (DebuggerListener listener : listeners) { + listener.attached(); + } + } + + @Override + public void detached() { + for (Breakpoint breakpoint : breakpoints) { + updateBreakpointStatus(breakpoint, true); + } + for (DebuggerListener listener : listeners) { + listener.detached(); + } + } + + @Override + public void breakpointChanged(JavaScriptBreakpoint jsBreakpoint) { + Breakpoint breakpoint = breakpointMap.get(jsBreakpoint); + if (breakpoint != null) { + updateInternalBreakpoints(breakpoint); + updateBreakpointStatus(breakpoint, false); + } + } }; } diff --git a/teavm-core/src/main/java/org/teavm/debugging/DebuggerListener.java b/teavm-core/src/main/java/org/teavm/debugging/DebuggerListener.java index fed17ae70..a1b672905 100644 --- a/teavm-core/src/main/java/org/teavm/debugging/DebuggerListener.java +++ b/teavm-core/src/main/java/org/teavm/debugging/DebuggerListener.java @@ -23,4 +23,10 @@ public interface DebuggerListener { void resumed(); void paused(); + + void breakpointStatusChanged(Breakpoint breakpoint); + + void attached(); + + void detached(); } diff --git a/teavm-core/src/main/java/org/teavm/debugging/JavaScriptBreakpoint.java b/teavm-core/src/main/java/org/teavm/debugging/JavaScriptBreakpoint.java index b2049fcc4..009c2c417 100644 --- a/teavm-core/src/main/java/org/teavm/debugging/JavaScriptBreakpoint.java +++ b/teavm-core/src/main/java/org/teavm/debugging/JavaScriptBreakpoint.java @@ -22,5 +22,7 @@ package org.teavm.debugging; public interface JavaScriptBreakpoint { JavaScriptLocation getLocation(); + boolean isValid(); + void destroy(); } diff --git a/teavm-core/src/main/java/org/teavm/debugging/JavaScriptDebugger.java b/teavm-core/src/main/java/org/teavm/debugging/JavaScriptDebugger.java index a6cfcfcbc..a5ae97b65 100644 --- a/teavm-core/src/main/java/org/teavm/debugging/JavaScriptDebugger.java +++ b/teavm-core/src/main/java/org/teavm/debugging/JavaScriptDebugger.java @@ -38,6 +38,8 @@ public interface JavaScriptDebugger { boolean isSuspended(); + boolean isAttached(); + JavaScriptCallFrame[] getCallStack(); JavaScriptBreakpoint getCurrentBreakpoint(); diff --git a/teavm-core/src/main/java/org/teavm/debugging/JavaScriptDebuggerListener.java b/teavm-core/src/main/java/org/teavm/debugging/JavaScriptDebuggerListener.java index a7e99a37e..76baafc2e 100644 --- a/teavm-core/src/main/java/org/teavm/debugging/JavaScriptDebuggerListener.java +++ b/teavm-core/src/main/java/org/teavm/debugging/JavaScriptDebuggerListener.java @@ -24,5 +24,11 @@ public interface JavaScriptDebuggerListener { void resumed(); + void attached(); + + void detached(); + + void breakpointChanged(JavaScriptBreakpoint breakpoint); + void scriptAdded(String name); } diff --git a/teavm-core/src/main/java/org/teavm/javascript/Renderer.java b/teavm-core/src/main/java/org/teavm/javascript/Renderer.java index 40f496781..695c90b1d 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/Renderer.java +++ b/teavm-core/src/main/java/org/teavm/javascript/Renderer.java @@ -1498,6 +1498,9 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext writer.append("("); expr.getExpr().acceptVisitor(this); writer.append(" instanceof ").appendClass(clsName).append(")"); + if (expr.getLocation() != null) { + popLocation(); + } return; } }