package com.jetbrains.lang.dart.ide.runner.server.vmService; import com.intellij.xdebugger.breakpoints.XBreakpointHandler; import com.intellij.xdebugger.breakpoints.XBreakpointProperties; import com.intellij.xdebugger.breakpoints.XLineBreakpoint; import com.jetbrains.lang.dart.ide.runner.DartLineBreakpointType; import gnu.trove.THashMap; import gnu.trove.THashSet; import org.dartlang.vm.service.element.Breakpoint; import org.jetbrains.annotations.NotNull; import java.util.*; import static com.intellij.icons.AllIcons.Debugger.Db_invalid_breakpoint; import static com.intellij.icons.AllIcons.Debugger.Db_verified_breakpoint; public class DartVmServiceBreakpointHandler extends XBreakpointHandler<XLineBreakpoint<XBreakpointProperties>> { private final DartVmServiceDebugProcess myDebugProcess; private final Set<XLineBreakpoint<XBreakpointProperties>> myXBreakpoints = new THashSet<>(); private final Map<String, IsolateBreakpointInfo> myIsolateInfo = new THashMap<>(); private final Map<String, XLineBreakpoint<XBreakpointProperties>> myVmBreakpointIdToXBreakpointMap = new THashMap<>(); public DartVmServiceBreakpointHandler(@NotNull final DartVmServiceDebugProcess debugProcess) { super(DartLineBreakpointType.class); myDebugProcess = debugProcess; } @Override public void registerBreakpoint(@NotNull final XLineBreakpoint<XBreakpointProperties> xBreakpoint) { myXBreakpoints.add(xBreakpoint); final VmServiceWrapper vmServiceWrapper = myDebugProcess.getVmServiceWrapper(); if (vmServiceWrapper != null) { vmServiceWrapper.addBreakpointForIsolates(xBreakpoint, myDebugProcess.getIsolateInfos()); } } @Override public void unregisterBreakpoint(@NotNull final XLineBreakpoint<XBreakpointProperties> xBreakpoint, boolean temporary) { myXBreakpoints.remove(xBreakpoint); for (IsolateBreakpointInfo info : myIsolateInfo.values()) { info.unregisterBreakpoint(xBreakpoint); } } public Set<XLineBreakpoint<XBreakpointProperties>> getXBreakpoints() { return myXBreakpoints; } public void vmBreakpointAdded(@NotNull final XLineBreakpoint<XBreakpointProperties> xBreakpoint, @NotNull final String isolateId, @NotNull final Breakpoint vmBreakpoint) { myVmBreakpointIdToXBreakpointMap.put(vmBreakpoint.getId(), xBreakpoint); IsolateBreakpointInfo info = getIsolateInfo(isolateId); info.vmBreakpointAdded(xBreakpoint, vmBreakpoint); if (vmBreakpoint.getResolved()) { breakpointResolved(vmBreakpoint); } } public void temporaryBreakpointAdded(String isolateId, Breakpoint vmBreakpoint) { getIsolateInfo(isolateId).temporaryVmBreakpointAdded(vmBreakpoint.getId()); } public void removeTemporaryBreakpoints(String isolateId) { getIsolateInfo(isolateId).removeTemporaryBreakpoints(); } public void removeAllVmBreakpoints(@NotNull String isolateId) { final Set<String> vmBreakpoints = getIsolateInfo(isolateId).removeAllVmBreakpoints(); for (String vmBreakpointId : vmBreakpoints) { myVmBreakpointIdToXBreakpointMap.remove(vmBreakpointId); } } private IsolateBreakpointInfo getIsolateInfo(String isolateId) { IsolateBreakpointInfo info = myIsolateInfo.get(isolateId); if (info == null) { info = new IsolateBreakpointInfo(isolateId, myDebugProcess); myIsolateInfo.put(isolateId, info); } return info; } public void breakpointResolved(@NotNull final Breakpoint vmBreakpoint) { final XLineBreakpoint<XBreakpointProperties> xBreakpoint = myVmBreakpointIdToXBreakpointMap.get(vmBreakpoint.getId()); // This can be null when the breakpoint has been set by another debugger client. if (xBreakpoint != null) { myDebugProcess.getSession().updateBreakpointPresentation(xBreakpoint, Db_verified_breakpoint, null); } } public void breakpointFailed(@NotNull final XLineBreakpoint<XBreakpointProperties> xBreakpoint) { // can this xBreakpoint be resolved for other isolate? myDebugProcess.getSession().updateBreakpointPresentation(xBreakpoint, Db_invalid_breakpoint, null); } public XLineBreakpoint<XBreakpointProperties> getXBreakpoint(@NotNull final Breakpoint vmBreakpoint) { return myVmBreakpointIdToXBreakpointMap.get(vmBreakpoint.getId()); } } class IsolateBreakpointInfo { private final String myIsolateId; private final DartVmServiceDebugProcess myDebugProcess; private final List<String> myTemporaryVmBreakpointIds = new ArrayList<>(); private final Map<XLineBreakpoint<XBreakpointProperties>, Set<String>> myXBreakpointToVmBreakpointIdsMap = new THashMap<>(); IsolateBreakpointInfo(@NotNull String isolateId, @NotNull DartVmServiceDebugProcess debugProcess) { this.myIsolateId = isolateId; this.myDebugProcess = debugProcess; } public void removeTemporaryBreakpoints() { for (String breakpointId : myTemporaryVmBreakpointIds) { myDebugProcess.getVmServiceWrapper().removeBreakpoint(myIsolateId, breakpointId); } myTemporaryVmBreakpointIds.clear(); } public Set<String> removeAllVmBreakpoints() { if (!myDebugProcess.isIsolateAlive(myIsolateId)) { return new HashSet<>(); } final Set<String> allVmBreakpoints = new HashSet<>(); synchronized (myXBreakpointToVmBreakpointIdsMap) { for (Set<String> bps : myXBreakpointToVmBreakpointIdsMap.values()) { allVmBreakpoints.addAll(bps); } myXBreakpointToVmBreakpointIdsMap.clear(); } for (String vmBreakpointId : allVmBreakpoints) { myDebugProcess.getVmServiceWrapper().removeBreakpoint(myIsolateId, vmBreakpointId); } return allVmBreakpoints; } public void temporaryVmBreakpointAdded(String vmBreakpointId) { myTemporaryVmBreakpointIds.add(vmBreakpointId); } public void vmBreakpointAdded(XLineBreakpoint<XBreakpointProperties> xBreakpoint, Breakpoint vmBreakpoint) { getVmBreakpoints(xBreakpoint).add(vmBreakpoint.getId()); } public void unregisterBreakpoint(XLineBreakpoint<XBreakpointProperties> xBreakpoint) { if (myDebugProcess.isIsolateAlive(myIsolateId)) { for (String vmBreakpointId : getVmBreakpoints(xBreakpoint)) { myDebugProcess.getVmServiceWrapper().removeBreakpoint(myIsolateId, vmBreakpointId); } } myXBreakpointToVmBreakpointIdsMap.remove(xBreakpoint); } private Set<String> getVmBreakpoints(XLineBreakpoint<XBreakpointProperties> xBreakpoint) { synchronized (myXBreakpointToVmBreakpointIdsMap) { Set<String> vmBreakpoints = myXBreakpointToVmBreakpointIdsMap.get(xBreakpoint); if (vmBreakpoints == null) { vmBreakpoints = new HashSet<>(); myXBreakpointToVmBreakpointIdsMap.put(xBreakpoint, vmBreakpoints); } return vmBreakpoints; } } }