From 0dbe4372666f40c2240878a642271d8384af1ad5 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Thu, 28 Apr 2016 23:40:57 +0300 Subject: [PATCH] Further work on IDEA debugger --- .../teavm/idea/debug/TeaVMDebugProcess.java | 8 +- .../teavm/idea/debug/TeaVMExecutionStack.java | 75 +++++++++++++++++++ .../org/teavm/idea/debug/TeaVMStackFrame.java | 54 +++++++++++++ .../teavm/idea/debug/TeaVMSuspendContext.java | 36 +++++++++ 4 files changed, 171 insertions(+), 2 deletions(-) create mode 100644 tools/idea/src/main/java/org/teavm/idea/debug/TeaVMExecutionStack.java create mode 100644 tools/idea/src/main/java/org/teavm/idea/debug/TeaVMStackFrame.java create mode 100644 tools/idea/src/main/java/org/teavm/idea/debug/TeaVMSuspendContext.java diff --git a/tools/idea/src/main/java/org/teavm/idea/debug/TeaVMDebugProcess.java b/tools/idea/src/main/java/org/teavm/idea/debug/TeaVMDebugProcess.java index b1e52d138..f02343d2e 100644 --- a/tools/idea/src/main/java/org/teavm/idea/debug/TeaVMDebugProcess.java +++ b/tools/idea/src/main/java/org/teavm/idea/debug/TeaVMDebugProcess.java @@ -44,12 +44,12 @@ public class TeaVMDebugProcess extends XDebugProcess { innerDebugger.addListener(new DebuggerListener() { @Override public void resumed() { - session.resume(); + getSession().resume(); } @Override public void paused() { - session.pause(); + handlePaused(); } @Override @@ -115,6 +115,10 @@ public class TeaVMDebugProcess extends XDebugProcess { innerDebugger.continueToLocation(position.getFile().getPath(), position.getLine()); } + private void handlePaused() { + getSession().positionReached(new TeaVMSuspendContext(innerDebugger, getSession().getProject())); + } + @NotNull @Override public XBreakpointHandler[] getBreakpointHandlers() { diff --git a/tools/idea/src/main/java/org/teavm/idea/debug/TeaVMExecutionStack.java b/tools/idea/src/main/java/org/teavm/idea/debug/TeaVMExecutionStack.java new file mode 100644 index 000000000..1f45ee0a0 --- /dev/null +++ b/tools/idea/src/main/java/org/teavm/idea/debug/TeaVMExecutionStack.java @@ -0,0 +1,75 @@ +/* + * Copyright 2016 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.idea.debug; + +import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ProjectRootManager; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.xdebugger.frame.XExecutionStack; +import com.intellij.xdebugger.frame.XStackFrame; +import java.util.Arrays; +import java.util.Objects; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.teavm.debugging.CallFrame; +import org.teavm.debugging.Debugger; + +public class TeaVMExecutionStack extends XExecutionStack { + private Debugger innerDebugger; + private TeaVMStackFrame[] frames; + private ProjectRootManager rootManager; + + public TeaVMExecutionStack(@NotNull Debugger innerDebugger, @NotNull Project project) { + super("TeaVM"); + this.innerDebugger = innerDebugger; + rootManager = ProjectRootManager.getInstance(project); + } + + @Nullable + @Override + public XStackFrame getTopFrame() { + TeaVMStackFrame[] frames = calculateFrames(); + return frames.length > 0 ? frames[0] : null; + } + + @NotNull + private TeaVMStackFrame[] calculateFrames() { + if (frames == null) { + CallFrame[] innerCallStack = innerDebugger.getCallStack(); + frames = new TeaVMStackFrame[innerCallStack.length]; + for (int i = 0; i < innerCallStack.length; ++i) { + frames[i] = new TeaVMStackFrame(this, innerCallStack[i]); + } + } + return frames; + } + + @Override + public void computeStackFrames(int firstFrameIndex, XStackFrameContainer container) { + TeaVMStackFrame[] frames = calculateFrames(); + int index = Math.min(firstFrameIndex, frames.length); + container.addStackFrames(Arrays.asList(frames).subList(index, frames.length), true); + } + + @Nullable + VirtualFile findVirtualFile(@NotNull String partialPath) { + return Arrays.stream(rootManager.getContentSourceRoots()) + .map(sourceRoot -> sourceRoot.findFileByRelativePath(partialPath)) + .filter(Objects::nonNull) + .findFirst() + .orElse(null); + } +} diff --git a/tools/idea/src/main/java/org/teavm/idea/debug/TeaVMStackFrame.java b/tools/idea/src/main/java/org/teavm/idea/debug/TeaVMStackFrame.java new file mode 100644 index 000000000..82e4aea0d --- /dev/null +++ b/tools/idea/src/main/java/org/teavm/idea/debug/TeaVMStackFrame.java @@ -0,0 +1,54 @@ +/* + * Copyright 2016 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.idea.debug; + +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.xdebugger.XDebuggerUtil; +import com.intellij.xdebugger.XSourcePosition; +import com.intellij.xdebugger.frame.XStackFrame; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.teavm.debugging.CallFrame; +import org.teavm.debugging.information.SourceLocation; + +class TeaVMStackFrame extends XStackFrame { + private TeaVMExecutionStack stack; + private CallFrame innerFrame; + private XSourcePosition position; + + TeaVMStackFrame(@NotNull TeaVMExecutionStack stack, @NotNull CallFrame innerFrame) { + this.stack = stack; + this.innerFrame = innerFrame; + } + + @Nullable + @Override + public XSourcePosition getSourcePosition() { + if (position == null) { + VirtualFile virtualFile = null; + int line = -1; + SourceLocation innerLocation = innerFrame.getLocation(); + if (innerLocation != null) { + if (innerLocation.getFileName() != null) { + virtualFile = stack.findVirtualFile(innerLocation.getFileName()); + } + line = innerLocation.getLine(); + } + position = XDebuggerUtil.getInstance().createPosition(virtualFile, line); + } + return position; + } +} diff --git a/tools/idea/src/main/java/org/teavm/idea/debug/TeaVMSuspendContext.java b/tools/idea/src/main/java/org/teavm/idea/debug/TeaVMSuspendContext.java new file mode 100644 index 000000000..8d0f1ac42 --- /dev/null +++ b/tools/idea/src/main/java/org/teavm/idea/debug/TeaVMSuspendContext.java @@ -0,0 +1,36 @@ +/* + * Copyright 2016 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.idea.debug; + +import com.intellij.openapi.project.Project; +import com.intellij.xdebugger.frame.XExecutionStack; +import com.intellij.xdebugger.frame.XSuspendContext; +import org.jetbrains.annotations.Nullable; +import org.teavm.debugging.Debugger; + +class TeaVMSuspendContext extends XSuspendContext { + private XExecutionStack executionStack; + + TeaVMSuspendContext(Debugger innerDebugger, Project project) { + executionStack = new TeaVMExecutionStack(innerDebugger, project); + } + + @Nullable + @Override + public XExecutionStack getActiveExecutionStack() { + return executionStack; + } +}