Permalink
Browse files

Scala debugger working without JDT debugger

Reworked the Scala debugger so it doesn't use the JDT debugger to
communicate with the VM.
A new launch delegate is added to the Scala application launch configuration type.
It creates a ScalaDebugTarget from the JDI connection to the vm.
Added a breakpoint manager, to create and delete the JDI requests needed.
Added a JDI event dispatcher, to pull the events from the JDI event queue and forwarding
them to the interested parties.
The management of the events and of the state of the debug elements is base on Scala actors.
Removed the debug preference page
Improved the access modifiers

Fix #1001130
  • Loading branch information...
1 parent a8d0572 commit d494b18021112d691f88d712928143f2322605b9 @skyluc skyluc committed Jul 4, 2012
Showing with 1,337 additions and 557 deletions.
  1. +0 −5 org.scala-ide.sdt.debug.tests/src/scala/tools/eclipse/debug/ScalaDebugComputeDetailTest.scala
  2. +0 −5 org.scala-ide.sdt.debug.tests/src/scala/tools/eclipse/debug/ScalaDebugResumeTest.scala
  3. +0 −1 org.scala-ide.sdt.debug.tests/src/scala/tools/eclipse/debug/ScalaDebugSteppingTest.scala
  4. +25 −5 org.scala-ide.sdt.debug.tests/src/scala/tools/eclipse/debug/ScalaDebugTestSession.scala
  5. +2 −2 ...ala-ide.sdt.debug.tests/src/scala/tools/eclipse/debug/model/ScalaDebugModelPresentationTest.scala
  6. +33 −21 org.scala-ide.sdt.debug.tests/src/scala/tools/eclipse/debug/model/ScalaDebugTargetTest.scala
  7. +3 −3 org.scala-ide.sdt.debug.tests/src/scala/tools/eclipse/debug/model/ScalaThreadTest.scala
  8. +3 −0 org.scala-ide.sdt.debug.tests/test-workspace/debug/AnonFunOnListString.launch
  9. +5 −2 org.scala-ide.sdt.debug.tests/test-workspace/debug/ForComprehensionListInt.launch
  10. +3 −0 org.scala-ide.sdt.debug.tests/test-workspace/debug/ForComprehensionListIntOptimized.launch
  11. +3 −0 org.scala-ide.sdt.debug.tests/test-workspace/debug/ForComprehensionListObject.launch
  12. +3 −0 org.scala-ide.sdt.debug.tests/test-workspace/debug/ForComprehensionListString.launch
  13. +3 −0 org.scala-ide.sdt.debug.tests/test-workspace/debug/ForComprehensionListString2.launch
  14. +3 −0 org.scala-ide.sdt.debug.tests/test-workspace/debug/SimpleStepping.launch
  15. +3 −0 org.scala-ide.sdt.debug.tests/test-workspace/debug/Variables.launch
  16. +13 −15 org.scala-ide.sdt.debug/plugin.xml
  17. +169 −0 org.scala-ide.sdt.debug/src/scala/tools/eclipse/debug/BreakpointSupport.scala
  18. +0 −38 org.scala-ide.sdt.debug/src/scala/tools/eclipse/debug/DebugPreferencePage.scala
  19. +21 −3 org.scala-ide.sdt.debug/src/scala/tools/eclipse/debug/JDIUtil.scala
  20. +130 −0 org.scala-ide.sdt.debug/src/scala/tools/eclipse/debug/ScalaDebugBreakpointManager.scala
  21. +17 −66 org.scala-ide.sdt.debug/src/scala/tools/eclipse/debug/ScalaDebugger.scala
  22. +6 −0 org.scala-ide.sdt.debug/src/scala/tools/eclipse/debug/command/ScalaStep.scala
  23. +98 −74 org.scala-ide.sdt.debug/src/scala/tools/eclipse/debug/command/ScalaStepInto.scala
  24. +96 −77 org.scala-ide.sdt.debug/src/scala/tools/eclipse/debug/command/ScalaStepOver.scala
  25. +64 −35 org.scala-ide.sdt.debug/src/scala/tools/eclipse/debug/command/ScalaStepReturn.scala
  26. +84 −0 org.scala-ide.sdt.debug/src/scala/tools/eclipse/debug/model/JdiRequestFactory.scala
  27. +4 −6 org.scala-ide.sdt.debug/src/scala/tools/eclipse/debug/model/ScalaDebugElement.scala
  28. +181 −107 org.scala-ide.sdt.debug/src/scala/tools/eclipse/debug/model/ScalaDebugTarget.scala
  29. +183 −0 org.scala-ide.sdt.debug/src/scala/tools/eclipse/debug/model/ScalaJdiEventDispatcher.scala
  30. +1 −1 org.scala-ide.sdt.debug/src/scala/tools/eclipse/debug/model/ScalaLogicalStructureProvider.scala
  31. +7 −3 org.scala-ide.sdt.debug/src/scala/tools/eclipse/debug/model/ScalaStackFrame.scala
  32. +125 −80 org.scala-ide.sdt.debug/src/scala/tools/eclipse/debug/model/ScalaThread.scala
  33. +8 −8 org.scala-ide.sdt.debug/src/scala/tools/eclipse/debug/model/ScalaVariable.scala
  34. +19 −0 ...ide.sdt.debug/src/scala/tools/eclipse/launching/ScalaApplicationLaunchConfigurationDelegate.scala
  35. +22 −0 org.scala-ide.sdt.debug/src/scala/tools/eclipse/launching/StandardVMScalaDebugger.scala
@@ -22,11 +22,6 @@ class ScalaDebugComputeDetailTest {
var session: ScalaDebugTestSession = null
- @Before
- def setScalaDebugMode() {
- ScalaDebugPlugin.plugin.getPreferenceStore.setValue(DebugPreferencePage.P_ENABLE, true)
- }
-
@Before
def refreshBinaryFiles() {
project.underlying.build(IncrementalProjectBuilder.CLEAN_BUILD, new NullProgressMonitor)
@@ -18,11 +18,6 @@ class ScalaDebugResumeTest {
var session: ScalaDebugTestSession = null
- @Before
- def setScalaDebugMode() {
- ScalaDebugPlugin.plugin.getPreferenceStore.setValue(DebugPreferencePage.P_ENABLE, true)
- }
-
@Before
def refreshBinaryFiles() {
project.underlying.build(IncrementalProjectBuilder.CLEAN_BUILD, new NullProgressMonitor)
@@ -23,7 +23,6 @@ class ScalaDebugSteppingTest {
@Before
def initializeTests() {
if (!initialized) {
- ScalaDebugPlugin.plugin.getPreferenceStore.setValue(DebugPreferencePage.P_ENABLE, true)
project.underlying.build(IncrementalProjectBuilder.CLEAN_BUILD, new NullProgressMonitor)
project.underlying.build(IncrementalProjectBuilder.INCREMENTAL_BUILD, new NullProgressMonitor)
initialized = true
@@ -11,6 +11,17 @@ import org.eclipse.debug.core.model.DebugElement
import scala.tools.eclipse.debug.model.ScalaDebugElement
import org.eclipse.jdt.internal.debug.core.model.JDIDebugElement
+object EclipseDebugEvent {
+ def unapply(event: DebugEvent): Option[(Int, DebugElement)] = {
+ event.getSource match {
+ case debugElement: DebugElement =>
+ Some(event.getKind, debugElement)
+ case _ =>
+ None
+ }
+ }
+}
+
class ScalaDebugTestSession(launchConfigurationFile: IFile) extends IDebugEventSetListener {
object State extends Enumeration {
@@ -100,13 +111,11 @@ class ScalaDebugTestSession(launchConfigurationFile: IFile) extends IDebugEventS
var debugTarget: ScalaDebugTarget = null
var currentStackFrame: ScalaStackFrame = null
- // if is not Scala 2.0, it is Scala 2.09
- lazy val isScala210 = debugTarget.javaTarget.getVM.classesByName("scala.ScalaObject").isEmpty
-
def runToLine(typeName: String, breakpointLine: Int) {
assertThat("Bad state before runToBreakpoint", state, anyOf(is(NOT_LAUNCHED), is(SUSPENDED)))
val breakpoint = JDIDebugModel.createLineBreakpoint(ResourcesPlugin.getWorkspace.getRoot, typeName, breakpointLine, -1, -1, -1, true, null)
+ waitForBreakpointsToBeInstalled
if (state eq NOT_LAUNCHED) {
launch()
@@ -177,18 +186,29 @@ class ScalaDebugTestSession(launchConfigurationFile: IFile) extends IDebugEventS
val launchConfiguration = DebugPlugin.getDefault.getLaunchManager.getLaunchConfiguration(launchConfigurationFile)
launchConfiguration.launch(ILaunchManager.DEBUG_MODE, null)
}
+
+ /**
+ * Breakpoints are set asynchronously. It is fine in the UI, but it create timing problems
+ * while running test.
+ * This method make sure there are no outstanding requests
+ */
+ private def waitForBreakpointsToBeInstalled() {
+ if (state ne NOT_LAUNCHED) {
+ debugTarget.breakpointManager.waitForAllCurrentEvents
+ }
+ }
// -----
/**
- * Check that all threads have a suspended count of 0, except the one of the current thread which should be 1
+ * Check that all threads have a suspended count of 0, except the one of the current thread, which should be 1
*/
def checkThreadsState() {
assertEquals("Bad state before checkThreadsState", SUSPENDED, state)
val currentThread = currentStackFrame.stackFrame.thread
import scala.collection.JavaConverters._
- debugTarget.javaTarget.getVM.allThreads.asScala.foreach(thread =>
+ debugTarget.virtualMachine.allThreads.asScala.foreach(thread =>
assertEquals("Wrong suspended count", if (thread == currentThread) 1 else 0, thread.suspendCount))
}
@@ -41,7 +41,7 @@ class ScalaDebugModelPresentationTest {
when(jdiThread.threadGroup).thenReturn(jdiThreadGroup)
when(jdiThreadGroup.name).thenReturn("not system")
- val scalaThread = new ScalaThread(null, jdiThread)
+ val scalaThread = ScalaThread(null, jdiThread)
assertEquals("Bad display name for Scala thread", "Thread [thread name]", modelPres.getText(scalaThread))
}
@@ -54,7 +54,7 @@ class ScalaDebugModelPresentationTest {
when(jdiThread.threadGroup).thenReturn(jdiThreadGroup)
when(jdiThreadGroup.name).thenReturn("system")
- val scalaThread = new ScalaThread(null, jdiThread)
+ val scalaThread = ScalaThread(null, jdiThread)
assertEquals("Bad display name for Scala system thread", "Deamon System Thread [system thread name]", modelPres.getText(scalaThread))
}
@@ -10,47 +10,59 @@ import java.util.ArrayList
import org.eclipse.debug.core.DebugPlugin
import org.junit.Before
import com.sun.jdi.event.ThreadStartEvent
+import com.sun.jdi.request.EventRequestManager
+import com.sun.jdi.request.ThreadStartRequest
+import com.sun.jdi.request.ThreadDeathRequest
+import org.eclipse.debug.core.Launch
+import com.sun.jdi.event.EventQueue
class ScalaDebugTargetTest {
-
+
@Before
def initializeDebugPlugin() {
if (DebugPlugin.getDefault == null) {
new DebugPlugin
}
}
-
+
@Test
def threadNotTwiceInList() {
- val THREAD_NAME= "thread name"
-
- val debugTarget= createDebugTarget
-
+ val THREAD_NAME = "thread name"
+ val debugTarget = createDebugTarget()
+
val event = mock(classOf[ThreadStartEvent])
val thread = mock(classOf[ThreadReference])
when(event.thread).thenReturn(thread)
when(thread.name).thenReturn(THREAD_NAME)
-
- debugTarget.handleEvent(event, null, false, null)
-
- val threads1= debugTarget.getThreads
+
+ debugTarget.eventActor !? event
+
+ val threads1 = debugTarget.getThreads
assertEquals("Wrong number of threads", 1, threads1.length)
assertEquals("Wrong thread name", THREAD_NAME, threads1(0).getName)
-
+
// a second start event should not result in a duplicate entry
- debugTarget.handleEvent(event, null, false, null)
-
- val threads2= debugTarget.getThreads
+ debugTarget.eventActor !? event
+
+ val threads2 = debugTarget.getThreads
assertEquals("Wrong number of threads", 1, threads2.length)
assertEquals("Wrong thread name", THREAD_NAME, threads2(0).getName)
}
-
+
+ /**
+ * Create a debug target with most of the JDI implementation mocked
+ */
def createDebugTarget(): ScalaDebugTarget = {
- val javaDebugTarget= mock(classOf[JDIDebugTarget])
- val vm= mock(classOf[VirtualMachine])
- when(javaDebugTarget.getVM).thenReturn(vm)
- when(vm.allThreads).thenReturn(new ArrayList[ThreadReference]())
- new ScalaDebugTarget(javaDebugTarget, null, null)
+ val virtualMachine = mock(classOf[VirtualMachine])
+ when(virtualMachine.allThreads).thenReturn(new ArrayList[ThreadReference]())
+ val eventRequestManager = mock(classOf[EventRequestManager])
+ when(virtualMachine.eventRequestManager).thenReturn(eventRequestManager)
+ when(virtualMachine.eventQueue).thenReturn(mock(classOf[EventQueue]))
+ val threadStartRequest = mock(classOf[ThreadStartRequest])
+ when(eventRequestManager.createThreadStartRequest).thenReturn(threadStartRequest)
+ val threadDeathRequest = mock(classOf[ThreadDeathRequest])
+ when(eventRequestManager.createThreadDeathRequest).thenReturn(threadDeathRequest)
+ ScalaDebugTarget(virtualMachine, mock(classOf[Launch]), null)
}
-}
+}
@@ -39,7 +39,7 @@ class ScalaThreadTest {
val jdiThreadGroup = createThreadGroup();
when(jdiThread.threadGroup).thenReturn(jdiThreadGroup)
- val thread = new ScalaThread(null, jdiThread)
+ val thread = ScalaThread(null, jdiThread)
assertEquals("Bad thread name", "some test string", thread.getName)
}
@@ -52,7 +52,7 @@ class ScalaThreadTest {
val jdiThreadGroup = createThreadGroup();
when(jdiThread.threadGroup).thenReturn(jdiThreadGroup)
- val thread = new ScalaThread(null, jdiThread)
+ val thread = ScalaThread(null, jdiThread)
assertEquals("Bad thread name on VMDisconnectedException", "<disconnected>", thread.getName)
}
@@ -65,7 +65,7 @@ class ScalaThreadTest {
val jdiThreadGroup = createThreadGroup();
when(jdiThread.threadGroup).thenReturn(jdiThreadGroup)
- val thread = new ScalaThread(null, jdiThread)
+ val thread = ScalaThread(null, jdiThread)
assertEquals("Bad thread name", "<garbage collected>", thread.getName)
}
@@ -7,6 +7,9 @@
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
<listEntry value="1"/>
</listAttribute>
+<mapAttribute key="org.eclipse.debug.core.preferred_launchers">
+<mapEntry key="[debug]" value="scala.application.new"/>
+</mapAttribute>
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="stepping.AnonFunOnListString"/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="debug"/>
</launchConfiguration>
@@ -2,11 +2,14 @@
<launchConfiguration type="scala.application">
<stringAttribute key="bad_container_name" value="/debug/f"/>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
-<listEntry value="/debug"/>
+<listEntry value="/debug/src/stepping/ForComprehensionListInt.scala"/>
</listAttribute>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
-<listEntry value="4"/>
+<listEntry value="1"/>
</listAttribute>
+<mapAttribute key="org.eclipse.debug.core.preferred_launchers">
+<mapEntry key="[debug]" value="scala.application.new"/>
+</mapAttribute>
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="stepping.ForComprehensionListInt"/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="debug"/>
</launchConfiguration>
@@ -7,6 +7,9 @@
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
<listEntry value="1"/>
</listAttribute>
+<mapAttribute key="org.eclipse.debug.core.preferred_launchers">
+<mapEntry key="[debug]" value="scala.application.new"/>
+</mapAttribute>
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="stepping.ForComprehensionListIntOptimized"/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="debug"/>
</launchConfiguration>
@@ -7,6 +7,9 @@
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
<listEntry value="1"/>
</listAttribute>
+<mapAttribute key="org.eclipse.debug.core.preferred_launchers">
+<mapEntry key="[debug]" value="scala.application.new"/>
+</mapAttribute>
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="stepping.ForComprehensionListObject"/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="debug"/>
</launchConfiguration>
@@ -7,6 +7,9 @@
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
<listEntry value="1"/>
</listAttribute>
+<mapAttribute key="org.eclipse.debug.core.preferred_launchers">
+<mapEntry key="[debug]" value="scala.application.new"/>
+</mapAttribute>
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="stepping.ForComprehensionListString"/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="debug"/>
</launchConfiguration>
@@ -7,6 +7,9 @@
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
<listEntry value="1"/>
</listAttribute>
+<mapAttribute key="org.eclipse.debug.core.preferred_launchers">
+<mapEntry key="[debug]" value="scala.application.new"/>
+</mapAttribute>
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="stepping.ForComprehensionListString2"/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="debug"/>
</launchConfiguration>
@@ -7,6 +7,9 @@
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
<listEntry value="1"/>
</listAttribute>
+<mapAttribute key="org.eclipse.debug.core.preferred_launchers">
+<mapEntry key="[debug]" value="scala.application.new"/>
+</mapAttribute>
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="stepping.SimpleStepping"/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="debug"/>
</launchConfiguration>
@@ -6,6 +6,9 @@
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
<listEntry value="1"/>
</listAttribute>
+<mapAttribute key="org.eclipse.debug.core.preferred_launchers">
+<mapEntry key="[debug]" value="scala.application.new"/>
+</mapAttribute>
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="debug.Variables"/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="debug"/>
</launchConfiguration>
@@ -1,21 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.2"?>
<plugin>
- <extension
- point="org.eclipse.ui.preferencePages">
- <page
- category="org.scala-ide.sdt.core.preferences"
- class="scala.tools.eclipse.debug.DebugPreferencePage"
- id="org.scala-ide.sdt.debug.preferences"
- name="Debug">
- </page>
- </extension>
- <extension
- point="org.eclipse.core.runtime.preferences">
- <initializer
- class="scala.tools.eclipse.debug.DebugPreferenceInitializer">
- </initializer>
- </extension>
<extension
point="org.eclipse.debug.ui.debugModelPresentations">
<debugModelPresentation
@@ -36,4 +21,17 @@
modelIdentifier="org.scala-ide.sdt.debug">
</logicalStructureProvider>
</extension>
+ <extension
+ point="org.eclipse.debug.core.launchDelegates">
+ <launchDelegate
+ delegate="scala.tools.eclipse.launching.ScalaApplicationLaunchConfigurationDelegate"
+ delegateDescription="The Scala JVM Launcher supports debugging of local Scala using the new Scala debugger"
+ id="scala.application.new"
+ modes="debug"
+ name="Scala Application (new debugger)"
+ sourceLocatorId="org.eclipse.jdt.launching.sourceLocator.JavaSourceLookupDirector"
+ sourcePathComputerId="org.eclipse.jdt.launching.sourceLookup.javaSourcePathComputer"
+ type="scala.application">
+ </launchDelegate>
+ </extension>
</plugin>
Oops, something went wrong.

0 comments on commit d494b18

Please sign in to comment.