You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@netbeans.apache.org by en...@apache.org on 2020/10/09 22:28:28 UTC
[netbeans] branch master updated: Improved stability of Truffle
debugger and implemented step from scripts to Java.
This is an automated email from the ASF dual-hosted git repository.
entl pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/netbeans.git
The following commit(s) were added to refs/heads/master by this push:
new f282d78 Improved stability of Truffle debugger and implemented step from scripts to Java.
new dfb0edb Merge pull request #2436 from entlicher/TruffleDebugStabilityAndStep2Java
f282d78 is described below
commit f282d78f09c4bf6296cbf062f12808c628287fdb
Author: Martin Entlicher <ma...@oracle.com>
AuthorDate: Fri Oct 9 15:09:14 2020 +0200
Improved stability of Truffle debugger and implemented step from scripts to Java.
---
java/api.debugger.jpda/apichanges.xml | 16 ++
java/api.debugger.jpda/manifest.mf | 2 +-
.../netbeans/api/debugger/jpda/JPDADebugger.java | 15 +-
.../org/netbeans/api/debugger/jpda/JPDAStep.java | 60 +++++++
.../org/netbeans/api/debugger/jpda/JPDAThread.java | 2 -
java/debugger.jpda.truffle/nbproject/project.xml | 9 +-
.../debugger/jpda/truffle/DebugManagerHandler.java | 2 +-
.../debugger/jpda/truffle/PersistentValues.java | 129 +++++++++++++++
.../debugger/jpda/truffle/RemoteServices.java | 175 +++++++++++++--------
.../debugger/jpda/truffle/TruffleDebugManager.java | 121 ++++----------
.../jpda/truffle/access/CurrentPCInfo.java | 2 +-
.../jpda/truffle/access/TruffleAccess.java | 4 +-
.../actions/PauseInGraalScriptActionProvider.java | 85 +++++-----
.../truffle/actions/RunToCursorActionProvider.java | 15 +-
.../jpda/truffle/actions/StepActionProvider.java | 49 +++++-
.../truffle/breakpoints/TruffleLineBreakpoint.java | 64 ++++++++
.../{ => impl}/TruffleBreakpointReader.java | 16 +-
.../{ => impl}/TruffleBreakpointsHandler.java | 57 +++++--
.../jpda/truffle/frames/TruffleStackFrame.java | 2 +-
.../debugger/jpda/truffle/source/Source.java | 2 +
.../truffle/source/SourceBinaryTranslator.java | 126 +++++++++++++++
.../jpda/truffle/vars/TruffleVariable.java | 8 +
.../truffle/vars/{ => impl}/TruffleEvaluator.java | 2 +-
.../truffle/vars/{ => impl}/TruffleExpression.java | 2 +-
.../jpda/truffle/vars/{ => impl}/TruffleScope.java | 3 +-
.../vars/{ => impl}/TruffleStackVariable.java | 8 +-
.../vars/{ => impl}/TruffleVariableImpl.java | 3 +-
.../models/TruffleLocalVariablesTreeModel.java | 2 +-
.../vars/models/TruffleVariablesNodeModel.java | 2 +-
.../vars/models/TruffleVariablesTableModel.java | 4 +-
.../vars/models/TruffleVariablesTreeModel.java | 4 +-
.../truffle/vars/tooltip/ToolTipAnnotation.java | 2 +-
.../jpda/backend/truffle/AgentClassLoader.java} | 31 ++--
.../jpda/backend/truffle/JPDATruffleAccessor.java | 5 +-
.../modules/debugger/jpda/JPDAStepImpl.java | 127 +++++++--------
.../jpda/breakpoints/LineBreakpointImpl.java | 15 +-
36 files changed, 834 insertions(+), 337 deletions(-)
diff --git a/java/api.debugger.jpda/apichanges.xml b/java/api.debugger.jpda/apichanges.xml
index 67a5177..69574ef 100644
--- a/java/api.debugger.jpda/apichanges.xml
+++ b/java/api.debugger.jpda/apichanges.xml
@@ -959,6 +959,22 @@ These are mainly class and thread filters and hit counts.
</description>
<class package="org.netbeans.api.debugger.jpda" name="ExceptionBreakpoint" />
</change>
+
+ <change>
+ <api name="JPDADebuggerAPI"/>
+ <summary>JPDAStep enhanced with stepping filters and JPDADebugger.getSession() added.</summary>
+ <version major="3" minor="19"/>
+ <date day="9" month="10" year="2020"/>
+ <author login="mentlicher"/>
+ <compatibility addition="yes" source="compatible" binary="compatible"/>
+ <description>
+ <code>JPDAStep</code> enhanced with stepping filters for better control.
+ <code>JPDADebugger.getSession()</code> added to be able to easily retrieve the session
+ this JPDA debugger belongs into.
+ </description>
+ <class package="org.netbeans.api.debugger.jpda" name="JPDAStep" />
+ <class package="org.netbeans.api.debugger.jpda" name="JPDADebugger" />
+ </change>
</changes>
<!-- Now the surrounding HTML text and document structure: -->
diff --git a/java/api.debugger.jpda/manifest.mf b/java/api.debugger.jpda/manifest.mf
index e545029..49338d3 100644
--- a/java/api.debugger.jpda/manifest.mf
+++ b/java/api.debugger.jpda/manifest.mf
@@ -1,6 +1,6 @@
Manifest-Version: 1.0
OpenIDE-Module: org.netbeans.api.debugger.jpda/2
OpenIDE-Module-Localizing-Bundle: org/netbeans/api/debugger/jpda/Bundle.properties
-OpenIDE-Module-Specification-Version: 3.18
+OpenIDE-Module-Specification-Version: 3.19
OpenIDE-Module-Package-Dependencies: com.sun.jdi[VirtualMachineManager]
diff --git a/java/api.debugger.jpda/src/org/netbeans/api/debugger/jpda/JPDADebugger.java b/java/api.debugger.jpda/src/org/netbeans/api/debugger/jpda/JPDADebugger.java
index 26d3e6a..d073f22 100644
--- a/java/api.debugger.jpda/src/org/netbeans/api/debugger/jpda/JPDADebugger.java
+++ b/java/api.debugger.jpda/src/org/netbeans/api/debugger/jpda/JPDADebugger.java
@@ -19,7 +19,6 @@
package org.netbeans.api.debugger.jpda;
-import com.sun.jdi.VirtualMachine;
import com.sun.jdi.connect.Connector.Argument;
import com.sun.jdi.connect.ListeningConnector;
import com.sun.jdi.request.EventRequest;
@@ -38,6 +37,7 @@ import java.util.Map;
import org.netbeans.api.debugger.DebuggerEngine;
import org.netbeans.api.debugger.DebuggerInfo;
import org.netbeans.api.debugger.DebuggerManager;
+import org.netbeans.api.debugger.Session;
import org.netbeans.api.debugger.jpda.event.JPDABreakpointEvent;
import org.netbeans.api.java.classpath.ClassPath;
@@ -552,7 +552,7 @@ public abstract class JPDADebugger {
public boolean canGetInstanceInfo() {
return false;
}
-
+
/**
* Get the list of all classes in the debuggee.
* @return The list of all classes.
@@ -614,7 +614,15 @@ public abstract class JPDADebugger {
public ThreadsCollector getThreadsCollector() {
return null;
}
-
+
+ /**
+ * Get the session associated with this debugger.
+ * @since 3.19
+ */
+ public Session getSession() {
+ throw new AbstractMethodError();
+ }
+
/**
* Creates a deadlock detector.
* @return deadlock detector with automatic detection of deadlock among suspended threads
@@ -746,7 +754,6 @@ public abstract class JPDADebugger {
String serviceName = (String) attrs.get(DebuggerProcessor.SERVICE_NAME);
return new ContextAware(serviceName);
}
-
}
}
diff --git a/java/api.debugger.jpda/src/org/netbeans/api/debugger/jpda/JPDAStep.java b/java/api.debugger.jpda/src/org/netbeans/api/debugger/jpda/JPDAStep.java
index 9b20316..1b895b7 100644
--- a/java/api.debugger.jpda/src/org/netbeans/api/debugger/jpda/JPDAStep.java
+++ b/java/api.debugger.jpda/src/org/netbeans/api/debugger/jpda/JPDAStep.java
@@ -20,9 +20,12 @@ package org.netbeans.api.debugger.jpda;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
+import java.util.Arrays;
import com.sun.jdi.request.StepRequest;
+import org.netbeans.api.debugger.Properties;
+
/**
* Represents one JPDA step.
*
@@ -32,6 +35,8 @@ public abstract class JPDAStep {
private int size;
private int depth;
private boolean hidden;
+ private String[] classFilters;
+ private boolean stepThroughFilters;
/** Associated JPDA debugger */
protected JPDADebugger debugger;
private PropertyChangeSupport pcs;
@@ -64,6 +69,9 @@ public abstract class JPDAStep {
this.depth = depth;
this.debugger = debugger;
this.hidden = false;
+ Properties p = Properties.getDefault().getProperties("debugger.options.JPDA"); // NOI18N
+ boolean useStepFilters = p.getBoolean("UseStepFilters", true);
+ this.stepThroughFilters = useStepFilters && p.getBoolean("StepThroughFilters", false);
pcs = new PropertyChangeSupport(this);
}
@@ -113,6 +121,58 @@ public abstract class JPDAStep {
return depth;
}
+ /**
+ * Add additional class exclusion filters to this step.
+ * The provided list of class filters is combined with the current
+ * {@link SmartSteppingFilter#getExclusionPatterns()} just for this step.
+ *
+ * @param classFilters A list of class filters
+ * @since 3.19
+ */
+ public void addSteppingFilters(String... classFilters) {
+ if (this.classFilters == null) {
+ this.classFilters = classFilters;
+ } else {
+ int cfl = this.classFilters.length;
+ this.classFilters = Arrays.copyOf(this.classFilters, cfl + classFilters.length);
+ System.arraycopy(classFilters, 0, this.classFilters, cfl, classFilters.length);
+ }
+ }
+
+ /**
+ * Get the additional exclusion filters of this step.
+ *
+ * @return A list of exclusion patterns, or <code>null</code> when no additional
+ * filters are provided
+ * @since 3.19
+ */
+ public String[] getSteppingFilters() {
+ return classFilters;
+ }
+
+ /**
+ * Set whether this step is stepping through exclusion filters, or not.
+ * The default value is taken from the option property.
+ *
+ * @param stepThroughFilters <code>true</code> to step through the filters,
+ * <code>false</code> otherwise
+ * @since 3.19
+ */
+ public void setStepThroughFilters(boolean stepThroughFilters) {
+ this.stepThroughFilters = stepThroughFilters;
+ }
+
+ /**
+ * Test whether this step is stepping through the exclusion filters.
+ *
+ * @return <code>true</code> to step through the filters,
+ * <code>false</code> otherwise
+ * @since 3.19
+ */
+ public boolean isStepThroughFilters() {
+ return stepThroughFilters;
+ }
+
/** Adds the step request to the associated
* {@link org.netbeans.api.debugger.jpda.JPDADebugger}.
* Method is not synchronized.
diff --git a/java/api.debugger.jpda/src/org/netbeans/api/debugger/jpda/JPDAThread.java b/java/api.debugger.jpda/src/org/netbeans/api/debugger/jpda/JPDAThread.java
index 8ec5ef0..e5e7e49 100644
--- a/java/api.debugger.jpda/src/org/netbeans/api/debugger/jpda/JPDAThread.java
+++ b/java/api.debugger.jpda/src/org/netbeans/api/debugger/jpda/JPDAThread.java
@@ -21,10 +21,8 @@ package org.netbeans.api.debugger.jpda;
import com.sun.jdi.AbsentInformationException;
import com.sun.jdi.ThreadReference;
-import java.beans.PropertyChangeListener;
import java.util.List;
import java.util.concurrent.locks.Lock;
-import org.netbeans.spi.debugger.jpda.EditorContext;
import org.netbeans.spi.debugger.jpda.EditorContext.Operation;
diff --git a/java/debugger.jpda.truffle/nbproject/project.xml b/java/debugger.jpda.truffle/nbproject/project.xml
index 60a04ac..aff8c0d 100644
--- a/java/debugger.jpda.truffle/nbproject/project.xml
+++ b/java/debugger.jpda.truffle/nbproject/project.xml
@@ -40,7 +40,7 @@
<compile-dependency/>
<run-dependency>
<release-version>2</release-version>
- <specification-version>3.5</specification-version>
+ <specification-version>3.19</specification-version>
</run-dependency>
</dependency>
<dependency>
@@ -269,7 +269,12 @@
</test-dependency>
</test-type>
</test-dependencies>
- <public-packages/>
+ <public-packages>
+ <package>org.netbeans.modules.debugger.jpda.truffle.breakpoints</package>
+ <package>org.netbeans.modules.debugger.jpda.truffle.frames</package>
+ <package>org.netbeans.modules.debugger.jpda.truffle.source</package>
+ <package>org.netbeans.modules.debugger.jpda.truffle.vars</package>
+ </public-packages>
<extra-compilation-unit>
<package-root>truffle-backend</package-root>
<classpath>${module.classpath}:${truffle-backend.cp.extra}</classpath>
diff --git a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/DebugManagerHandler.java b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/DebugManagerHandler.java
index 385b411..f2b03f6 100644
--- a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/DebugManagerHandler.java
+++ b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/DebugManagerHandler.java
@@ -65,7 +65,7 @@ import org.netbeans.modules.debugger.jpda.jdi.VirtualMachineWrapper;
import org.netbeans.modules.debugger.jpda.models.JPDAThreadImpl;
import org.netbeans.modules.debugger.jpda.truffle.access.TruffleAccess;
import static org.netbeans.modules.debugger.jpda.truffle.access.TruffleAccess.BASIC_CLASS_NAME;
-import org.netbeans.modules.debugger.jpda.truffle.breakpoints.TruffleBreakpointsHandler;
+import org.netbeans.modules.debugger.jpda.truffle.breakpoints.impl.TruffleBreakpointsHandler;
import org.netbeans.modules.debugger.jpda.truffle.options.TruffleOptions;
import org.netbeans.modules.javascript2.debug.breakpoints.JSLineBreakpoint;
import org.openide.util.Exceptions;
diff --git a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/PersistentValues.java b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/PersistentValues.java
new file mode 100644
index 0000000..1b0a7cc
--- /dev/null
+++ b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/PersistentValues.java
@@ -0,0 +1,129 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.netbeans.modules.debugger.jpda.truffle;
+
+import com.sun.jdi.ClassNotLoadedException;
+import com.sun.jdi.IncompatibleThreadStateException;
+import com.sun.jdi.InvalidTypeException;
+import com.sun.jdi.InvocationException;
+import com.sun.jdi.ObjectReference;
+import com.sun.jdi.StringReference;
+import com.sun.jdi.VirtualMachine;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Supplier;
+import org.netbeans.modules.debugger.jpda.jdi.InternalExceptionWrapper;
+import org.netbeans.modules.debugger.jpda.jdi.ObjectCollectedExceptionWrapper;
+import org.netbeans.modules.debugger.jpda.jdi.ObjectReferenceWrapper;
+import org.netbeans.modules.debugger.jpda.jdi.UnsupportedOperationExceptionWrapper;
+import org.netbeans.modules.debugger.jpda.jdi.VMDisconnectedExceptionWrapper;
+import org.netbeans.modules.debugger.jpda.jdi.VirtualMachineWrapper;
+
+/**
+ * Create values with disabled collection, which can be released later on.
+ * This is necessary e.g. for temporary variables so that they are not collected
+ * prematurely.
+ */
+public final class PersistentValues {
+
+ private final VirtualMachine vm;
+ private final List<ObjectReference> references = new ArrayList<>(5);
+
+ public PersistentValues(VirtualMachine vm) {
+ this.vm = vm;
+ }
+
+ public StringReference mirrorOf(String string) throws InternalExceptionWrapper, VMDisconnectedExceptionWrapper, UnsupportedOperationExceptionWrapper {
+ StringReference stringMirror = null;
+ while (stringMirror == null) {
+ stringMirror = VirtualMachineWrapper.mirrorOf(vm, string);
+ try {
+ ObjectReferenceWrapper.disableCollection(stringMirror);
+ } catch (ObjectCollectedExceptionWrapper ce) {
+ stringMirror = null;
+ }
+ }
+ references.add(stringMirror);
+ return stringMirror;
+ }
+
+ /**
+ * @return the reference or <code>null</code> in case of JDI exceptions.
+ */
+ public StringReference mirrorOf0(String string) {
+ try {
+ return mirrorOf(string);
+ } catch (InternalExceptionWrapper | UnsupportedOperationExceptionWrapper | VMDisconnectedExceptionWrapper e) {
+ return null;
+ }
+ }
+
+ public <T extends ObjectReference> T valueOf(ValueSupplier<T> valueSupplier) throws InternalExceptionWrapper, VMDisconnectedExceptionWrapper, UnsupportedOperationExceptionWrapper {
+ T value = null;
+ while (value == null) {
+ value = valueSupplier.get();
+ try {
+ ObjectReferenceWrapper.disableCollection(value);
+ } catch (ObjectCollectedExceptionWrapper ce) {
+ value = null;
+ }
+ }
+ references.add(value);
+ return value;
+ }
+
+ public <T extends ObjectReference> T invokeOf(InvokeSupplier<T> valueSupplier) throws InternalExceptionWrapper, VMDisconnectedExceptionWrapper, UnsupportedOperationExceptionWrapper, ClassNotLoadedException, IncompatibleThreadStateException, InvalidTypeException, InvocationException, ObjectCollectedExceptionWrapper {
+ T value = null;
+ while (value == null) {
+ value = valueSupplier.get();
+ try {
+ ObjectReferenceWrapper.disableCollection(value);
+ } catch (ObjectCollectedExceptionWrapper ce) {
+ value = null;
+ }
+ }
+ references.add(value);
+ return value;
+ }
+
+ public void collect() {
+ for (ObjectReference reference : references) {
+ try {
+ ObjectReferenceWrapper.enableCollection(reference);
+ } catch (InternalExceptionWrapper | ObjectCollectedExceptionWrapper | UnsupportedOperationExceptionWrapper ex) {
+ // continue
+ } catch (VMDisconnectedExceptionWrapper ex) {
+ break;
+ }
+ }
+ references.clear();
+ }
+
+ @FunctionalInterface
+ public interface ValueSupplier<T> {
+
+ public T get() throws InternalExceptionWrapper, VMDisconnectedExceptionWrapper, UnsupportedOperationExceptionWrapper;
+ }
+
+ @FunctionalInterface
+ public interface InvokeSupplier<T> {
+
+ public T get() throws InternalExceptionWrapper, VMDisconnectedExceptionWrapper, UnsupportedOperationExceptionWrapper, ClassNotLoadedException, IncompatibleThreadStateException, InvalidTypeException, InvocationException, ObjectCollectedExceptionWrapper;
+ }
+}
diff --git a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/RemoteServices.java b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/RemoteServices.java
index 5ad1d57..b566a93 100644
--- a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/RemoteServices.java
+++ b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/RemoteServices.java
@@ -23,6 +23,7 @@ import com.sun.jdi.ArrayReference;
import com.sun.jdi.ArrayType;
import com.sun.jdi.BooleanValue;
import com.sun.jdi.ByteValue;
+import com.sun.jdi.ClassLoaderReference;
import com.sun.jdi.ClassNotLoadedException;
import com.sun.jdi.ClassObjectReference;
import com.sun.jdi.ClassType;
@@ -43,6 +44,7 @@ import java.beans.PropertyChangeListener;
import java.beans.PropertyVetoException;
import java.io.IOException;
import java.io.InputStream;
+import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -94,6 +96,11 @@ public final class RemoteServices {
private static final Logger logger = Logger.getLogger(RemoteServices.class.getName());
static final String REMOTE_CLASSES_ZIPFILE = "/org/netbeans/modules/debugger/jpda/truffle/resources/JPDATruffleBackend.jar";
+
+ private static final String TRUFFLE_CLASS = "com.oracle.truffle.api.Truffle";
+ private static final String EXPORT_TRUFFLE_CLASS = "com.oracle.truffle.polyglot.LanguageCache$Loader";
+ private static final String EXPORT_TRUFFLE_METHOD = "exportTruffle";
+ private static final String EXPORT_TRUFFLE_SIGNAT = "(Ljava/lang/ClassLoader;)V";
private static final Map<JPDADebugger, ClassObjectReference> remoteServiceClasses = new WeakHashMap<>();
private static final Map<JPDADebugger, ThreadReference> remoteServiceAccess = new WeakHashMap<>();
@@ -125,7 +132,7 @@ public final class RemoteServices {
/* Use:
com.oracle.truffle.api.impl.TruffleLocator.class.getClassLoader()
*/
- ClassType truffleLocatorClass = getClass(vm, "com.oracle.truffle.api.impl.TruffleLocator");
+ ClassType truffleLocatorClass = getClass(vm, TRUFFLE_CLASS);
return truffleLocatorClass.classLoader();
}
@@ -167,6 +174,15 @@ public final class RemoteServices {
return cl;
}
+ private static int getTargetMajorVersion(VirtualMachine vm) throws InternalExceptionWrapper, VMDisconnectedExceptionWrapper {
+ String version = VirtualMachineWrapper.version(vm);
+ int dot = version.indexOf(".");
+ if (dot < 0) {
+ dot = version.length();
+ }
+ return Integer.parseInt(version.substring(0, dot));
+ }
+
public static ClassObjectReference uploadBasicClasses(JPDAThreadImpl t, String basicClassName) throws InvalidTypeException, ClassNotLoadedException, IncompatibleThreadStateException, InvocationException, IOException, PropertyVetoException, InternalExceptionWrapper, VMDisconnectedExceptionWrapper, ObjectCollectedExceptionWrapper, UnsupportedOperationExceptionWrapper, ClassNotPreparedExceptionWrapper {
ThreadReference tawt = t.getThreadReference();
VirtualMachine vm = tawt.virtualMachine();
@@ -189,59 +205,7 @@ public final class RemoteServices {
}
// Suppose that when there's the basic class loaded, there are all.
if (basicClass == null) { // Load the classes only if there's not the basic one.
- ObjectReference cl;
- cl = getTruffleClassLoader(tawt, vm);
- if (cl == null) {
- cl = getBootstrapClassLoader(tawt, vm);
- }
- if (cl == null) {
- cl = getContextClassLoader(tawt, vm);
- }
- ClassType classLoaderClass = (ClassType) ObjectReferenceWrapper.referenceType(cl);
-
- ByteValue[] mirrorBytesCache = new ByteValue[256];
- for (RemoteClass rc : remoteClasses) {
- String className = rc.name;
- ClassObjectReference theUploadedClass;
- ArrayReference byteArray = createTargetBytes(vm, rc.bytes, mirrorBytesCache);
- StringReference nameMirror = null;
- try {
- Method defineClass = ClassTypeWrapper.concreteMethodByName(classLoaderClass, "defineClass", "(Ljava/lang/String;[BII)Ljava/lang/Class;");
- boolean uploaded = false;
- while (!uploaded) {
- nameMirror = VirtualMachineWrapper.mirrorOf(vm, className);
- try {
- ObjectReferenceWrapper.disableCollection(nameMirror);
- uploaded = true;
- } catch (ObjectCollectedExceptionWrapper ocex) {
- // Just collected, try again...
- }
- }
- uploaded = false;
- while (!uploaded) {
- theUploadedClass = (ClassObjectReference) ObjectReferenceWrapper.invokeMethod(cl, tawt, defineClass, Arrays.asList(nameMirror, byteArray, vm.mirrorOf(0), vm.mirrorOf(rc.bytes.length)), ObjectReference.INVOKE_SINGLE_THREADED);
- if (basicClass == null && rc.name.indexOf('$') < 0 && rc.name.endsWith("Accessor")) {
- try {
- // Disable collection only of the basic class
- ObjectReferenceWrapper.disableCollection(theUploadedClass);
- basicClass = theUploadedClass;
- uploaded = true;
- } catch (ObjectCollectedExceptionWrapper ocex) {
- // Just collected, try again...
- }
- } else {
- uploaded = true;
- }
- }
- } finally {
- ObjectReferenceWrapper.enableCollection(byteArray); // We can dispose it now
- if (nameMirror != null) {
- ObjectReferenceWrapper.enableCollection(nameMirror);
- }
- }
- //Method resolveClass = classLoaderClass.concreteMethodByName("resolveClass", "(Ljava/lang/Class;)V");
- //systemClassLoader.invokeMethod(tawt, resolveClass, Arrays.asList(theUploadedClass), ObjectReference.INVOKE_SINGLE_THREADED);
- }
+ basicClass = doUpload(vm, tawt, remoteClasses);
}
if (basicClass != null) {
// Initialize the class:
@@ -266,6 +230,92 @@ public final class RemoteServices {
}
}
+ private static ClassObjectReference doUpload(VirtualMachine vm, ThreadReference tawt, List<RemoteClass> remoteClasses) throws InvalidTypeException, ClassNotLoadedException, IncompatibleThreadStateException, InvocationException, IOException, PropertyVetoException, InternalExceptionWrapper, VMDisconnectedExceptionWrapper, ObjectCollectedExceptionWrapper, UnsupportedOperationExceptionWrapper, ClassNotPreparedExceptionWrapper {
+ String agentClassLoaderName = "AgentClassLoader";
+ PersistentValues values = new PersistentValues(vm);
+ ByteValue[] mirrorBytesCache = new ByteValue[256];
+ ClassLoaderReference classLoader;
+ try {
+ if (getTargetMajorVersion(vm) > 8) { // Module system is in place
+ RemoteClass agent = null;
+ for (RemoteClass rc : remoteClasses) {
+ if (rc.name.endsWith(agentClassLoaderName)) {
+ agent = rc;
+ break;
+ }
+ }
+ if (agent == null) {
+ throw new IllegalStateException("The " + agentClassLoaderName + " class is missing.");
+ }
+ // Upload the class loader first, using the Truffle's class loader:
+ ClassType truffleLocatorClass = getClass(vm, TRUFFLE_CLASS);
+ ClassLoaderReference truffleClassLoader = truffleLocatorClass.classLoader();
+ ClassType classLoaderClass = (ClassType) ObjectReferenceWrapper.referenceType(truffleClassLoader);
+ // Define the class loader's code:
+ Method defineClass = ClassTypeWrapper.concreteMethodByName(classLoaderClass, "defineClass", "(Ljava/lang/String;[BII)Ljava/lang/Class;");
+ ArrayReference byteArray = createTargetBytes(vm, agent.bytes, mirrorBytesCache, values);
+ StringReference nameMirror = values.mirrorOf(agent.name);
+ ClassObjectReference theUploadedClassLoader = (ClassObjectReference) ObjectReferenceWrapper.invokeMethod(truffleClassLoader, tawt, defineClass, Arrays.asList(nameMirror, byteArray, vm.mirrorOf(0), vm.mirrorOf(agent.bytes.length)), ObjectReference.INVOKE_SINGLE_THREADED);
+ // We have the class loader's class. Create it's instance now.
+ // Find the constructor and call newInstance on it:
+ ClassType theClass = getClass(vm, Class.class.getName());
+ Method getDeclaredConstructors = ClassTypeWrapper.concreteMethodByName(theClass, "getDeclaredConstructors", "()[Ljava/lang/reflect/Constructor;");
+ ArrayReference constructors = (ArrayReference) ObjectReferenceWrapper.invokeMethod(theUploadedClassLoader, tawt, getDeclaredConstructors, Collections.emptyList(), ObjectReference.INVOKE_SINGLE_THREADED);
+ ObjectReference constructor = (ObjectReference) constructors.getValue(0);
+ ClassType constructorClass = getClass(vm, Constructor.class.getName());
+ Method newInstance = ClassTypeWrapper.concreteMethodByName(constructorClass, "newInstance", "([Ljava/lang/Object;)Ljava/lang/Object;");
+ ClassLoaderReference newInstanceOfClassLoader = values.invokeOf(() -> (ClassLoaderReference) constructor.invokeMethod(tawt, newInstance, Collections.emptyList(), ObjectReference.INVOKE_SINGLE_THREADED));
+ classLoader = (ClassLoaderReference) newInstanceOfClassLoader;
+
+ // We have an agent class loader that we'll use to define Truffle backend debugging classes.
+ // We need to export the agent class loader to Truffle so that we can upload classes that access Truffle APIs.
+ ClassType languageLoader = getClass(vm, EXPORT_TRUFFLE_CLASS);
+ if (languageLoader == null) {
+ Exceptions.printStackTrace(new IllegalStateException("Class " + EXPORT_TRUFFLE_CLASS + " not found in the debuggee."));
+ return null;
+ }
+ Method exportTruffle = ClassTypeWrapper.concreteMethodByName(languageLoader, EXPORT_TRUFFLE_METHOD, EXPORT_TRUFFLE_SIGNAT);
+ if (exportTruffle == null) {
+ Exceptions.printStackTrace(new IllegalStateException("Method " + EXPORT_TRUFFLE_METHOD + " was not found in " + EXPORT_TRUFFLE_CLASS +" in the debuggee."));
+ return null;
+ }
+ ClassTypeWrapper.invokeMethod(languageLoader, tawt, exportTruffle, Collections.singletonList(classLoader), ObjectReference.INVOKE_SINGLE_THREADED);
+ } else {
+ ObjectReference cl;
+ cl = getTruffleClassLoader(tawt, vm);
+ if (cl == null) {
+ cl = getBootstrapClassLoader(tawt, vm);
+ }
+ if (cl == null) {
+ cl = getContextClassLoader(tawt, vm);
+ }
+ classLoader = (ClassLoaderReference) cl;
+ }
+
+ ClassType classLoaderClass = (ClassType) ObjectReferenceWrapper.referenceType(classLoader);
+ ClassObjectReference basicClass = null;
+ for (RemoteClass rc : remoteClasses) {
+ String className = rc.name;
+ if (className.endsWith(agentClassLoaderName)) {
+ continue;
+ }
+ ClassObjectReference theUploadedClass;
+ ArrayReference byteArray = createTargetBytes(vm, rc.bytes, mirrorBytesCache, values);
+ Method defineClass = ClassTypeWrapper.concreteMethodByName(classLoaderClass, "defineClass", "(Ljava/lang/String;[BII)Ljava/lang/Class;");
+ StringReference nameMirror = values.mirrorOf(className);
+ theUploadedClass = values.invokeOf(() -> (ClassObjectReference) ObjectReferenceWrapper.invokeMethod(classLoader, tawt, defineClass, Arrays.asList(nameMirror, byteArray, vm.mirrorOf(0), vm.mirrorOf(rc.bytes.length)), ObjectReference.INVOKE_SINGLE_THREADED));
+ if (basicClass == null && rc.name.indexOf('$') < 0 && rc.name.endsWith("Accessor")) {
+ // Disable collection only of the basic class
+ ObjectReferenceWrapper.disableCollection(theUploadedClass);
+ basicClass = theUploadedClass;
+ }
+ }
+ return basicClass;
+ } finally {
+ values.collect();
+ }
+ }
+
private static void runOnBreakpoint(final JPDAThread awtThread, String bpClass, String bpMethod, final Runnable runnable, final CountDownLatch latch) {
final MethodBreakpoint mb = MethodBreakpoint.create(bpClass, bpMethod);
final JPDADebugger dbg = ((JPDAThreadImpl)awtThread).getDebugger();
@@ -616,25 +666,16 @@ public final class RemoteServices {
}
private static ArrayReference createTargetBytes(VirtualMachine vm, byte[] bytes,
- ByteValue[] mirrorBytesCache) throws InvalidTypeException,
+ ByteValue[] mirrorBytesCache,
+ PersistentValues persistValues) throws InvalidTypeException,
ClassNotLoadedException,
InternalExceptionWrapper,
VMDisconnectedExceptionWrapper,
ObjectCollectedExceptionWrapper,
UnsupportedOperationExceptionWrapper {
ArrayType bytesArrayClass = getArrayClass(vm, "byte[]");
- ArrayReference array = null;
- boolean disabledCollection = false;
- while (!disabledCollection) {
- array = ArrayTypeWrapper.newInstance(bytesArrayClass, bytes.length);
- try {
- ObjectReferenceWrapper.disableCollection(array);
- disabledCollection = true;
- } catch (ObjectCollectedExceptionWrapper ocex) {
- // Collected too soon, try again...
- }
- }
- List<Value> values = new ArrayList<Value>(bytes.length);
+ ArrayReference array = persistValues.valueOf(() -> ArrayTypeWrapper.newInstance(bytesArrayClass, bytes.length));
+ List<Value> values = new ArrayList<>(bytes.length);
for (int i = 0; i < bytes.length; i++) {
byte b = bytes[i];
ByteValue mb = mirrorBytesCache[128 + b];
diff --git a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/TruffleDebugManager.java b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/TruffleDebugManager.java
index 6f9b233..b37c0e9 100644
--- a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/TruffleDebugManager.java
+++ b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/TruffleDebugManager.java
@@ -20,18 +20,8 @@
package org.netbeans.modules.debugger.jpda.truffle;
import com.sun.jdi.ClassType;
-import com.sun.jdi.IncompatibleThreadStateException;
-import com.sun.jdi.Location;
-import com.sun.jdi.Method;
import com.sun.jdi.ObjectReference;
-import com.sun.jdi.ReferenceType;
-import com.sun.jdi.StackFrame;
-import com.sun.jdi.ThreadReference;
import com.sun.jdi.Value;
-import com.sun.jdi.event.Event;
-import com.sun.jdi.event.LocatableEvent;
-import com.sun.jdi.request.BreakpointRequest;
-import com.sun.jdi.request.EventRequest;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
@@ -47,39 +37,22 @@ import org.netbeans.api.debugger.DebuggerManager;
import org.netbeans.api.debugger.DebuggerManagerAdapter;
import org.netbeans.api.debugger.LazyDebuggerManagerListener;
import org.netbeans.api.debugger.Session;
-import org.netbeans.api.debugger.jpda.ClassLoadUnloadBreakpoint;
import org.netbeans.api.debugger.jpda.JPDABreakpoint;
import org.netbeans.api.debugger.jpda.JPDAClassType;
import org.netbeans.api.debugger.jpda.JPDADebugger;
+import org.netbeans.api.debugger.jpda.JPDAThread;
import org.netbeans.api.debugger.jpda.MethodBreakpoint;
import org.netbeans.api.debugger.jpda.ObjectVariable;
import org.netbeans.api.debugger.jpda.event.JPDABreakpointEvent;
import org.netbeans.api.debugger.jpda.event.JPDABreakpointListener;
import org.netbeans.modules.debugger.jpda.JPDADebuggerImpl;
import org.netbeans.modules.debugger.jpda.expr.JDIVariable;
-import org.netbeans.modules.debugger.jpda.jdi.ClassNotPreparedExceptionWrapper;
-import org.netbeans.modules.debugger.jpda.jdi.IllegalThreadStateExceptionWrapper;
-import org.netbeans.modules.debugger.jpda.jdi.InternalExceptionWrapper;
-import org.netbeans.modules.debugger.jpda.jdi.InvalidRequestStateExceptionWrapper;
-import org.netbeans.modules.debugger.jpda.jdi.InvalidStackFrameExceptionWrapper;
-import org.netbeans.modules.debugger.jpda.jdi.MethodWrapper;
-import org.netbeans.modules.debugger.jpda.jdi.ObjectCollectedExceptionWrapper;
-import org.netbeans.modules.debugger.jpda.jdi.ReferenceTypeWrapper;
-import org.netbeans.modules.debugger.jpda.jdi.StackFrameWrapper;
-import org.netbeans.modules.debugger.jpda.jdi.ThreadReferenceWrapper;
-import org.netbeans.modules.debugger.jpda.jdi.VMDisconnectedExceptionWrapper;
-import org.netbeans.modules.debugger.jpda.jdi.event.LocatableEventWrapper;
-import org.netbeans.modules.debugger.jpda.jdi.request.EventRequestManagerWrapper;
-import org.netbeans.modules.debugger.jpda.jdi.request.EventRequestWrapper;
-import org.netbeans.modules.debugger.jpda.models.JPDAClassTypeImpl;
import org.netbeans.modules.debugger.jpda.models.JPDAThreadImpl;
import org.netbeans.modules.debugger.jpda.truffle.access.TruffleAccess;
import org.netbeans.modules.debugger.jpda.truffle.actions.PauseInGraalScriptActionProvider;
-import org.netbeans.modules.debugger.jpda.util.Executor;
import org.netbeans.modules.javascript2.debug.breakpoints.JSLineBreakpoint;
import org.netbeans.spi.debugger.ActionsProvider;
import org.netbeans.spi.debugger.DebuggerServiceRegistration;
-import org.openide.util.Exceptions;
/**
* Initiates guest language debugging, detects Engine in the JVM.
@@ -89,7 +62,8 @@ public class TruffleDebugManager extends DebuggerManagerAdapter {
private static final Logger LOG = Logger.getLogger(TruffleDebugManager.class.getName());
- private static final String SESSION_CREATION_BP_CLASS = "org.graalvm.polyglot.Engine";
+ private static final String ENGINE_CLASS = "org.graalvm.polyglot.Engine";
+ private static final String ENGINE_BUILDER_CLASS = "org.graalvm.polyglot.Engine$Builder";
// Breakpoint on this class triggers search of existing engines
private static final String EXISTING_ENGINES_TRIGGER = "com.oracle.truffle.api.frame.FrameSlot";
@@ -115,7 +89,8 @@ public class TruffleDebugManager extends DebuggerManagerAdapter {
debugManagerLoadBP = MethodBreakpoint.create(SESSION_CREATION_BP_CLASS, SESSION_CREATION_BP_METHOD);
((MethodBreakpoint) debugManagerLoadBP).setBreakpointType(MethodBreakpoint.TYPE_METHOD_EXIT);
*/
- debugManagerLoadBP = ClassLoadUnloadBreakpoint.create(SESSION_CREATION_BP_CLASS, false, ClassLoadUnloadBreakpoint.TYPE_CLASS_LOADED);
+ debugManagerLoadBP = MethodBreakpoint.create(ENGINE_BUILDER_CLASS, "build");
+ ((MethodBreakpoint) debugManagerLoadBP).setBreakpointType(MethodBreakpoint.TYPE_METHOD_ENTRY);
debugManagerLoadBP.setHidden(true);
LOG.log(Level.FINE, "TruffleDebugManager.initBreakpoints(): submitted BP {0}", debugManagerLoadBP);
@@ -171,7 +146,7 @@ public class TruffleDebugManager extends DebuggerManagerAdapter {
@Override
public void breakpointReached(JPDABreakpointEvent event) {
try {
- submitPECreationBP(debugger, event.getReferenceType());
+ handleEngineBuilder(debugger, event);
} finally {
event.resume();
}
@@ -180,16 +155,7 @@ public class TruffleDebugManager extends DebuggerManagerAdapter {
debugManagerLoadBP.addJPDABreakpointListener(bpl);
// Submit creation BPs for existing engine classes:
Runnable submitEngineCreation = () -> {
- List<JPDAClassType> polyglotEngines = new ArrayList<>();
- //polyglotEngines.addAll(debugger.getClassesByName(SESSION_CREATION_BP_CLASS[0]));
- List<JPDAClassType> enginePe = debugger.getClassesByName(SESSION_CREATION_BP_CLASS);
- polyglotEngines.addAll(enginePe);
- for (JPDAClassType pe : polyglotEngines) {
- submitPECreationBP(debugger, ((JPDAClassTypeImpl) pe).getType());
- // TODO: Find possible existing instances of the engine
- // List<ObjectVariable> engines = pe.getInstances(0);
- // We have no suspended thread... :-(
- }
+ List<JPDAClassType> enginePe = debugger.getClassesByName(ENGINE_CLASS);
// Find possible existing instances of the engine
if (!enginePe.isEmpty() && debugger.canGetInstanceInfo()) {
long engineInstances = 0;
@@ -217,60 +183,27 @@ public class TruffleDebugManager extends DebuggerManagerAdapter {
return bpl;
}
- private void submitPECreationBP(final JPDADebugger debugger, ReferenceType type) {
- try {
- List<Method> constructors = ReferenceTypeWrapper.methodsByName(type, "<init>");
- for (Method c : constructors) {
- if (!c.argumentTypeNames().isEmpty()) {
- Location lastLocation = null;
- Location l;
- int i = 0;
- // Search for the last (return) statement:
- while ((l = MethodWrapper.locationOfCodeIndex(c, i)) != null) {
- lastLocation = l;
- i++;
- }
- BreakpointRequest bp = EventRequestManagerWrapper.createBreakpointRequest(lastLocation.virtualMachine().eventRequestManager(), lastLocation);
- EventRequestWrapper.setSuspendPolicy(bp, EventRequest.SUSPEND_EVENT_THREAD);
- ((JPDADebuggerImpl) debugger).getOperator().register(bp, new Executor() {
- @Override
- public boolean exec(Event event) {
- try {
- ThreadReference threadReference = LocatableEventWrapper.thread((LocatableEvent) event);
- JPDAThreadImpl thread = ((JPDADebuggerImpl) debugger).getThread(threadReference);
- StackFrame topFrame = ThreadReferenceWrapper.frame(threadReference, 0);
- List<Value> argumentValues = topFrame.getArgumentValues();
- if (argumentValues.get(0) == null) {
- // An empty constructor used for the builder only.
- return true;
- }
- ObjectReference engine = StackFrameWrapper.thisObject(topFrame);
- haveNewPE(debugger, thread, engine);
- } catch (InternalExceptionWrapper | VMDisconnectedExceptionWrapper |
- ObjectCollectedExceptionWrapper ex) {
- } catch (IllegalThreadStateExceptionWrapper |
- IncompatibleThreadStateException |
- InvalidStackFrameExceptionWrapper ex) {
- Exceptions.printStackTrace(ex);
- }
- return true;
- }
-
- @Override
- public void removed(EventRequest eventRequest) {
- }
-
- });
- try {
- EventRequestWrapper.enable(bp);
- } catch (InvalidRequestStateExceptionWrapper irsx) {
- Exceptions.printStackTrace(irsx);
- }
- }
+ /**
+ * Called from a method entry breakpoint on Engine$Builder.build().
+ * We need to submit a temporary method-exit breakpoint on the build method.
+ * We must not keep the method exit breakpoint active as it causes a significant performance degradation.
+ */
+ private void handleEngineBuilder(final JPDADebugger debugger, JPDABreakpointEvent entryEvent) {
+ MethodBreakpoint builderExitBreakpoint = MethodBreakpoint.create(ENGINE_BUILDER_CLASS, "build");
+ builderExitBreakpoint.setBreakpointType(MethodBreakpoint.TYPE_METHOD_EXIT);
+ builderExitBreakpoint.setThreadFilters(debugger, new JPDAThread[]{entryEvent.getThread()});
+ builderExitBreakpoint.setSuspend(JPDABreakpoint.SUSPEND_EVENT_THREAD);
+ builderExitBreakpoint.setHidden(true);
+ builderExitBreakpoint.addJPDABreakpointListener(exitEvent -> {
+ try {
+ builderExitBreakpoint.disable();
+ DebuggerManager.getDebuggerManager().removeBreakpoint(builderExitBreakpoint);
+ haveNewPE(debugger, (JPDAThreadImpl) exitEvent.getThread(), (ObjectReference) ((JDIVariable) exitEvent.getVariable()).getJDIValue());
+ } finally {
+ exitEvent.resume();
}
- } catch (InternalExceptionWrapper | VMDisconnectedExceptionWrapper |
- ObjectCollectedExceptionWrapper | ClassNotPreparedExceptionWrapper ex) {
- }
+ });
+ DebuggerManager.getDebuggerManager().addBreakpoint(builderExitBreakpoint);
}
private void submitExistingEnginesProbe(final JPDADebugger debugger, List<JPDAClassType> enginePe) {
diff --git a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/access/CurrentPCInfo.java b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/access/CurrentPCInfo.java
index 6814e35..c1dcc60 100644
--- a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/access/CurrentPCInfo.java
+++ b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/access/CurrentPCInfo.java
@@ -31,7 +31,7 @@ import org.netbeans.modules.debugger.jpda.truffle.ast.TruffleNode;
import org.netbeans.modules.debugger.jpda.truffle.frames.TruffleStackFrame;
import org.netbeans.modules.debugger.jpda.truffle.frames.TruffleStackInfo;
import org.netbeans.modules.debugger.jpda.truffle.source.SourcePosition;
-import org.netbeans.modules.debugger.jpda.truffle.vars.TruffleScope;
+import org.netbeans.modules.debugger.jpda.truffle.vars.impl.TruffleScope;
/**
* Container of information about the current program counter.
diff --git a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/access/TruffleAccess.java b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/access/TruffleAccess.java
index 7450372..de1ebc8 100644
--- a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/access/TruffleAccess.java
+++ b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/access/TruffleAccess.java
@@ -66,8 +66,8 @@ import org.netbeans.modules.debugger.jpda.truffle.frames.TruffleStackFrame;
import org.netbeans.modules.debugger.jpda.truffle.frames.TruffleStackInfo;
import org.netbeans.modules.debugger.jpda.truffle.source.Source;
import org.netbeans.modules.debugger.jpda.truffle.source.SourcePosition;
-import org.netbeans.modules.debugger.jpda.truffle.vars.TruffleScope;
-import org.netbeans.modules.debugger.jpda.truffle.vars.TruffleStackVariable;
+import org.netbeans.modules.debugger.jpda.truffle.vars.impl.TruffleScope;
+import org.netbeans.modules.debugger.jpda.truffle.vars.impl.TruffleStackVariable;
import org.netbeans.modules.debugger.jpda.truffle.vars.TruffleVariable;
import org.netbeans.modules.debugger.jpda.util.WeakHashMapActive;
import org.openide.util.Exceptions;
diff --git a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/actions/PauseInGraalScriptActionProvider.java b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/actions/PauseInGraalScriptActionProvider.java
index af7fffa..4dfc2f6 100644
--- a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/actions/PauseInGraalScriptActionProvider.java
+++ b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/actions/PauseInGraalScriptActionProvider.java
@@ -27,6 +27,7 @@ import com.sun.jdi.InvocationException;
import com.sun.jdi.Method;
import com.sun.jdi.ObjectReference;
import com.sun.jdi.ThreadReference;
+import java.awt.GraphicsEnvironment;
import java.lang.ref.WeakReference;
import java.util.Collections;
import java.util.Map;
@@ -62,13 +63,13 @@ import org.openide.util.Lookup;
public class PauseInGraalScriptActionProvider extends JPDADebuggerActionProvider {
private static final Logger LOG = Logger.getLogger(PauseInGraalScriptActionProvider.class.getName());
-
+
public static final String NAME = "pauseInGraalScript"; // NOI18N
private static final String ACCESSOR_SUSPEND_NEXT_EXECUTION = "suspendNextExecution"; // NOI18N
private static final String ACCESSOR_SUSPEND_NEXT_EXECUTION_SIGNAT = "()V";
-
+
private static WeakReference<Action> actionReference = new WeakReference<>(null);
- private static boolean actionState = false;
+ private static final ThreadLocal<Boolean> AVOID_REENTRANT = new ThreadLocal<>();
private boolean suspendState = false;
public PauseInGraalScriptActionProvider (ContextProvider lookupProvider) {
@@ -77,48 +78,42 @@ public class PauseInGraalScriptActionProvider extends JPDADebuggerActionProvider
@Override
protected void checkEnabled(int debuggerState) {
- Action action = actionReference.get();
- if (action != null) {
- ClassObjectReference serviceClass = RemoteServices.getServiceClass(getDebuggerImpl());
- boolean hasServiceClass = serviceClass != null;
- setEnabled(NAME, hasServiceClass);
- if (hasServiceClass) {
- JPDAThread currentThread = debugger.getCurrentThread();
- if (currentThread != null && TruffleAccess.getCurrentPCInfo(currentThread) != null) {
- suspendState = false;
- }
- if (actionState != suspendState) {
- SwingUtilities.invokeLater(() -> {
- actionState = suspendState;
- action.putValue(Action.SELECTED_KEY, actionState);
- });
- }
- } else {
- if (actionState) {
- SwingUtilities.invokeLater(() -> {
- action.putValue(Action.SELECTED_KEY, false);
- actionState = false;
- });
- }
+ if (AVOID_REENTRANT.get() != null) {
+ return;
+ }
+ try {
+ AVOID_REENTRANT.set(true);
+ checkEnabledImpl(debuggerState);
+ } finally {
+ AVOID_REENTRANT.set(null);
+ }
+ }
+
+ private void checkEnabledImpl(int debuggerState) {
+ ClassObjectReference serviceClass = RemoteServices.getServiceClass(getDebuggerImpl());
+ boolean hasServiceClass = serviceClass != null;
+ setEnabled(NAME, hasServiceClass);
+ if (hasServiceClass) {
+ JPDAThread currentThread = debugger.getCurrentThread();
+ if (currentThread != null && TruffleAccess.getCurrentPCInfo(currentThread) != null) {
+ suspendState = false;
}
+ updateActionState(true, suspendState);
+ } else {
+ updateActionState(false, false);
}
}
@Override
public void doAction(Object actionName) {
- Action action = actionReference.get();
- if (action != null) {
- suspendState = !suspendState;
- actionState = suspendState;
- SwingUtilities.invokeLater(() -> {
- action.putValue(Action.SELECTED_KEY, actionState);
- });
- if (suspendState) {
- scheduleSuspend();
- } else {
- cancelSuspend();
- }
+ assert NAME.equals(actionName);
+ suspendState = !suspendState;
+ if (suspendState) {
+ scheduleSuspend();
+ } else {
+ cancelSuspend();
}
+ updateActionState(true, suspendState);
}
@Override
@@ -176,11 +171,23 @@ public class PauseInGraalScriptActionProvider extends JPDADebuggerActionProvider
java.lang.reflect.Method createActionMethod = debuggerActionClass.getDeclaredMethod("createAction", Map.class);
Action action = (Action) createActionMethod.invoke(null, params);
action.putValue(Actions.ACTION_VALUE_TOGGLE, Boolean.TRUE);
- action.putValue(Action.SELECTED_KEY, actionState);
+ action.putValue(Action.SELECTED_KEY, false);
actionReference = new WeakReference<>(action);
return action;
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
+
+ private static void updateActionState(boolean active, boolean suspendState) {
+ if (GraphicsEnvironment.isHeadless()) {
+ return;
+ }
+ Action action = actionReference.get();
+ if (action != null) {
+ SwingUtilities.invokeLater(() -> {
+ action.putValue(Action.SELECTED_KEY, active & suspendState);
+ });
+ }
+ }
}
diff --git a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/actions/RunToCursorActionProvider.java b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/actions/RunToCursorActionProvider.java
index 0506b2f..b85a459 100644
--- a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/actions/RunToCursorActionProvider.java
+++ b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/actions/RunToCursorActionProvider.java
@@ -53,12 +53,14 @@ import org.netbeans.modules.debugger.jpda.jdi.ClassNotPreparedExceptionWrapper;
import org.netbeans.modules.debugger.jpda.jdi.ClassTypeWrapper;
import org.netbeans.modules.debugger.jpda.jdi.InternalExceptionWrapper;
import org.netbeans.modules.debugger.jpda.jdi.ObjectCollectedExceptionWrapper;
+import org.netbeans.modules.debugger.jpda.jdi.UnsupportedOperationExceptionWrapper;
import org.netbeans.modules.debugger.jpda.jdi.VMDisconnectedExceptionWrapper;
import org.netbeans.modules.debugger.jpda.models.JPDAThreadImpl;
+import org.netbeans.modules.debugger.jpda.truffle.PersistentValues;
import org.netbeans.modules.debugger.jpda.truffle.TruffleDebugManager;
import org.netbeans.modules.debugger.jpda.truffle.access.TruffleAccess;
import org.netbeans.modules.debugger.jpda.truffle.access.TruffleStrataProvider;
-import org.netbeans.modules.debugger.jpda.truffle.breakpoints.TruffleBreakpointsHandler;
+import org.netbeans.modules.debugger.jpda.truffle.breakpoints.impl.TruffleBreakpointsHandler;
import org.netbeans.modules.debugger.jpda.truffle.source.Source;
import org.netbeans.spi.debugger.ActionsProvider;
import org.netbeans.spi.debugger.ActionsProviderSupport;
@@ -163,10 +165,11 @@ public class RunToCursorActionProvider extends ActionsProviderSupport {
@Override
public void callMethods(JPDAThread thread) {
ThreadReference tr = ((JPDAThreadImpl) thread).getThreadReference();
- StringReference pathRef = tr.virtualMachine().mirrorOf(uri);
- IntegerValue lineRef = tr.virtualMachine().mirrorOf(line);
- List<? extends Value> args = Arrays.asList(new Value[] { pathRef, lineRef });
+ PersistentValues persistents = new PersistentValues(tr.virtualMachine());
try {
+ StringReference pathRef = persistents.mirrorOf(uri);
+ IntegerValue lineRef = tr.virtualMachine().mirrorOf(line);
+ List<? extends Value> args = Arrays.asList(new Value[] { pathRef, lineRef });
ArrayReference ret = (ArrayReference) ClassTypeWrapper.invokeMethod(
debugAccessor,
tr,
@@ -178,10 +181,12 @@ public class RunToCursorActionProvider extends ActionsProviderSupport {
Throwable ex = new InvocationExceptionTranslated(iex, (JPDADebuggerImpl) debugger).preload((JPDAThreadImpl) thread);
Exceptions.printStackTrace(Exceptions.attachMessage(ex, "Setting one shot breakpoint to "+uri+":"+line));
} catch (InvalidTypeException | ClassNotLoadedException |
- IncompatibleThreadStateException |
+ IncompatibleThreadStateException | UnsupportedOperationExceptionWrapper |
InternalExceptionWrapper | VMDisconnectedExceptionWrapper |
ObjectCollectedExceptionWrapper ex) {
Exceptions.printStackTrace(Exceptions.attachMessage(ex, "Setting one shot breakpoint to "+uri+":"+line));
+ } finally {
+ persistents.collect();
}
}
});
diff --git a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/actions/StepActionProvider.java b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/actions/StepActionProvider.java
index d1f18ae..2ca211a 100644
--- a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/actions/StepActionProvider.java
+++ b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/actions/StepActionProvider.java
@@ -23,6 +23,8 @@ import com.sun.jdi.VirtualMachine;
import com.sun.jdi.request.EventRequestManager;
import com.sun.jdi.request.StepRequest;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
import java.io.InvalidObjectException;
import java.util.ArrayList;
import java.util.Arrays;
@@ -34,14 +36,20 @@ import java.util.Set;
import java.util.logging.Logger;
import org.netbeans.api.debugger.ActionsManager;
+import org.netbeans.api.debugger.DebuggerManager;
import org.netbeans.api.debugger.jpda.JPDADebugger;
+import org.netbeans.api.debugger.jpda.JPDAStep;
import org.netbeans.api.debugger.jpda.JPDAThread;
+import org.netbeans.api.debugger.jpda.MethodBreakpoint;
+import org.netbeans.api.debugger.jpda.event.JPDABreakpointEvent;
+import org.netbeans.api.debugger.jpda.event.JPDABreakpointListener;
import org.netbeans.modules.debugger.jpda.JPDADebuggerImpl;
import org.netbeans.modules.debugger.jpda.actions.JPDADebuggerActionProvider;
import org.netbeans.modules.debugger.jpda.jdi.InternalExceptionWrapper;
import org.netbeans.modules.debugger.jpda.jdi.InvalidRequestStateExceptionWrapper;
import org.netbeans.modules.debugger.jpda.jdi.VMDisconnectedExceptionWrapper;
import org.netbeans.modules.debugger.jpda.jdi.request.EventRequestManagerWrapper;
+import org.netbeans.modules.debugger.jpda.models.JPDAThreadImpl;
import org.netbeans.modules.debugger.jpda.truffle.access.CurrentPCInfo;
import org.netbeans.modules.debugger.jpda.truffle.access.TruffleAccess;
import org.netbeans.modules.debugger.jpda.truffle.access.TruffleStrataProvider;
@@ -65,6 +73,9 @@ public class StepActionProvider extends JPDADebuggerActionProvider {
ActionsManager.ACTION_CONTINUE
})));
+ private static final String STEP2JAVA_CLASS = "com.oracle.truffle.polyglot.HostMethodDesc$SingleMethod$MHBase";
+ private static final String STEP2JAVA_METHOD = "invokeHandle";
+
public StepActionProvider (ContextProvider lookupProvider) {
super (
(JPDADebuggerImpl) lookupProvider.lookupFirst
@@ -108,6 +119,9 @@ public class StepActionProvider extends JPDADebuggerActionProvider {
Exceptions.printStackTrace(ex);
}
killJavaStep(debugger);
+ if (ActionsManager.ACTION_STEP_INTO.equals(action)) {
+ setBreakpoint2Java(currentThread);
+ }
if (stepCmd > 0) {
debugger.resumeCurrentThread();
} else {
@@ -154,5 +168,38 @@ public class StepActionProvider extends JPDADebuggerActionProvider {
public Set getActions() {
return ACTIONS;
}
-
+
+ private void setBreakpoint2Java(JPDAThread currentThread) {
+ MethodBreakpoint stepIntoJavaBreakpoint = MethodBreakpoint.create(STEP2JAVA_CLASS, STEP2JAVA_METHOD);
+ stepIntoJavaBreakpoint.setBreakpointType(MethodBreakpoint.TYPE_METHOD_ENTRY);
+ stepIntoJavaBreakpoint.setThreadFilters(debugger, new JPDAThread[]{currentThread});
+ stepIntoJavaBreakpoint.setHidden(true);
+ stepIntoJavaBreakpoint.addJPDABreakpointListener(new JPDABreakpointListener() {
+ @Override
+ public void breakpointReached(JPDABreakpointEvent event) {
+ stepIntoJavaBreakpoint.removeJPDABreakpointListener(this);
+ JPDAStep step2Java = debugger.createJPDAStep(JPDAStep.STEP_LINE, JPDAStep.STEP_INTO);
+ // Step through the reflection invocation onto a user Java code
+ // Need to add the standard exclusion patterns as we're stepping from an excluded location
+ step2Java.addSteppingFilters(debugger.getSmartSteppingFilter().getExclusionPatterns());
+ // Additional invocation-specific patterns:
+ step2Java.addSteppingFilters("java.lang.invoke.*", "sun.invoke.*", Class.class.getName(), System.class.getName());
+ step2Java.setStepThroughFilters(true);
+ step2Java.addStep(currentThread);
+ event.resume();
+ }
+ });
+ ((JPDAThreadImpl) currentThread).addPropertyChangeListener(JPDAThread.PROP_SUSPENDED, new PropertyChangeListener() {
+ @Override
+ public void propertyChange(PropertyChangeEvent evt) {
+ if ((Boolean) evt.getNewValue()) {
+ // Remove the step breakpoint on any suspend
+ DebuggerManager.getDebuggerManager().removeBreakpoint(stepIntoJavaBreakpoint);
+ ((JPDAThreadImpl) evt.getSource()).removePropertyChangeListener(JPDAThread.PROP_SUSPENDED, this);
+ }
+ }
+ });
+ DebuggerManager.getDebuggerManager().addBreakpoint(stepIntoJavaBreakpoint);
+ }
+
}
diff --git a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/breakpoints/TruffleLineBreakpoint.java b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/breakpoints/TruffleLineBreakpoint.java
index 2a083a7..b74c53c 100644
--- a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/breakpoints/TruffleLineBreakpoint.java
+++ b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/breakpoints/TruffleLineBreakpoint.java
@@ -19,12 +19,76 @@
package org.netbeans.modules.debugger.jpda.truffle.breakpoints;
+import java.beans.PropertyChangeListener;
+import java.net.URL;
+
import org.netbeans.modules.javascript2.debug.EditorLineHandler;
+import org.netbeans.modules.javascript2.debug.EditorLineHandlerFactory;
import org.netbeans.modules.javascript2.debug.breakpoints.JSLineBreakpoint;
+import org.openide.filesystems.FileObject;
+import org.openide.filesystems.URLMapper;
+import org.openide.util.Lookup;
public class TruffleLineBreakpoint extends JSLineBreakpoint {
public TruffleLineBreakpoint(EditorLineHandler lineHandler) {
super(lineHandler);
}
+
+ public TruffleLineBreakpoint(URL url, int lineNumber) {
+ this(getEditorLineHandler(url, lineNumber));
+ }
+
+ private static EditorLineHandler getEditorLineHandler(URL url, int lineNumber) {
+ EditorLineHandler handler;
+ if (Lookup.getDefault().lookup(EditorLineHandlerFactory.class) != null) {
+ handler = EditorLineHandlerFactory.getHandler(url, lineNumber);
+ } else {
+ handler = new FixedLineHandler(url, lineNumber);
+ }
+ return handler;
+ }
+
+ private static final class FixedLineHandler implements EditorLineHandler {
+
+ private final URL url;
+ private int lineNumber;
+
+ FixedLineHandler(URL url, int lineNumber) {
+ this.url = url;
+ this.lineNumber = lineNumber;
+ }
+
+ @Override
+ public FileObject getFileObject() {
+ return URLMapper.findFileObject(url);
+ }
+
+ @Override
+ public URL getURL() {
+ return url;
+ }
+
+ @Override
+ public int getLineNumber() {
+ return lineNumber;
+ }
+
+ @Override
+ public void setLineNumber(int lineNumber) {
+ this.lineNumber = lineNumber;
+ }
+
+ @Override
+ public void dispose() {
+ }
+
+ @Override
+ public void addPropertyChangeListener(PropertyChangeListener pchl) {
+ }
+
+ @Override
+ public void removePropertyChangeListener(PropertyChangeListener pchl) {
+ }
+ }
}
diff --git a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/breakpoints/TruffleBreakpointReader.java b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/breakpoints/impl/TruffleBreakpointReader.java
similarity index 88%
rename from java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/breakpoints/TruffleBreakpointReader.java
rename to java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/breakpoints/impl/TruffleBreakpointReader.java
index 8710469..34efe6c 100644
--- a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/breakpoints/TruffleBreakpointReader.java
+++ b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/breakpoints/impl/TruffleBreakpointReader.java
@@ -17,7 +17,7 @@
* under the License.
*/
-package org.netbeans.modules.debugger.jpda.truffle.breakpoints;
+package org.netbeans.modules.debugger.jpda.truffle.breakpoints.impl;
import java.net.MalformedURLException;
import java.net.URL;
@@ -25,12 +25,14 @@ import java.util.logging.Level;
import java.util.logging.Logger;
import org.netbeans.api.debugger.Breakpoint;
import org.netbeans.api.debugger.Properties;
+import org.netbeans.modules.debugger.jpda.truffle.breakpoints.TruffleLineBreakpoint;
import org.netbeans.modules.debugger.jpda.truffle.source.Source;
import org.netbeans.modules.javascript2.debug.EditorLineHandler;
import org.netbeans.modules.javascript2.debug.EditorLineHandlerFactory;
import org.netbeans.spi.debugger.DebuggerServiceRegistration;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.URLMapper;
+import org.openide.util.Lookup;
/**
* Breakpoints storage.
@@ -64,11 +66,15 @@ public class TruffleBreakpointReader implements Properties.Reader {
return null;
}
} else {
- EditorLineHandler line = EditorLineHandlerFactory.getHandler(fo, lineNumber);
- if (line != null) {
- b = new TruffleLineBreakpoint(line);
+ if (Lookup.getDefault().lookup(EditorLineHandlerFactory.class) != null) {
+ EditorLineHandler line = EditorLineHandlerFactory.getHandler(fo, lineNumber);
+ if (line != null) {
+ b = new TruffleLineBreakpoint(line);
+ } else {
+ return null;
+ }
} else {
- return null;
+ b = new TruffleLineBreakpoint(url, lineNumber);
}
}
} catch (MalformedURLException ex) {
diff --git a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/breakpoints/TruffleBreakpointsHandler.java b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/breakpoints/impl/TruffleBreakpointsHandler.java
similarity index 89%
rename from java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/breakpoints/TruffleBreakpointsHandler.java
rename to java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/breakpoints/impl/TruffleBreakpointsHandler.java
index f658577..6cdb45c 100644
--- a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/breakpoints/TruffleBreakpointsHandler.java
+++ b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/breakpoints/impl/TruffleBreakpointsHandler.java
@@ -17,7 +17,7 @@
* under the License.
*/
-package org.netbeans.modules.debugger.jpda.truffle.breakpoints;
+package org.netbeans.modules.debugger.jpda.truffle.breakpoints.impl;
import com.sun.jdi.ArrayReference;
import com.sun.jdi.ClassNotLoadedException;
@@ -35,7 +35,9 @@ import com.sun.jdi.VirtualMachine;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
+import java.io.IOException;
import java.net.URI;
+import java.net.URL;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
@@ -50,18 +52,30 @@ import org.netbeans.api.debugger.Breakpoint;
import org.netbeans.api.debugger.DebuggerManager;
import org.netbeans.api.debugger.jpda.JPDADebugger;
import org.netbeans.api.debugger.jpda.JPDAThread;
+import org.netbeans.api.java.queries.BinaryForSourceQuery;
+import org.netbeans.api.project.Project;
+import org.netbeans.api.project.ProjectManager;
+import org.netbeans.api.project.ProjectUtils;
+import org.netbeans.api.project.SourceGroup;
+import org.netbeans.api.project.Sources;
import org.netbeans.modules.debugger.jpda.JPDADebuggerImpl;
import org.netbeans.modules.debugger.jpda.jdi.ClassNotPreparedExceptionWrapper;
import org.netbeans.modules.debugger.jpda.jdi.ClassTypeWrapper;
import org.netbeans.modules.debugger.jpda.jdi.InternalExceptionWrapper;
import org.netbeans.modules.debugger.jpda.jdi.ObjectCollectedExceptionWrapper;
import org.netbeans.modules.debugger.jpda.jdi.ObjectReferenceWrapper;
+import org.netbeans.modules.debugger.jpda.jdi.UnsupportedOperationExceptionWrapper;
import org.netbeans.modules.debugger.jpda.jdi.VMDisconnectedExceptionWrapper;
import org.netbeans.modules.debugger.jpda.models.JPDAThreadImpl;
+import org.netbeans.modules.debugger.jpda.truffle.PersistentValues;
import org.netbeans.modules.debugger.jpda.truffle.access.TruffleAccess;
import org.netbeans.modules.debugger.jpda.truffle.source.Source;
+import org.netbeans.modules.debugger.jpda.truffle.source.SourceBinaryTranslator;
import org.netbeans.modules.javascript2.debug.breakpoints.JSLineBreakpoint;
+import org.netbeans.spi.java.queries.BinaryForSourceQueryImplementation;
import org.openide.filesystems.FileObject;
+import org.openide.filesystems.FileUtil;
+import org.openide.filesystems.URLMapper;
import org.openide.util.Exceptions;
import org.openide.util.Mutex;
@@ -122,7 +136,7 @@ public class TruffleBreakpointsHandler {
}
URI uri = Source.getTruffleInternalURI(fileObject);
if (uri == null) {
- uri = fileObject.toURI();
+ uri = SourceBinaryTranslator.source2Binary(fileObject);
}
ObjectReference bpImpl;
if (bp.isEnabled()) {
@@ -145,7 +159,7 @@ public class TruffleBreakpointsHandler {
}
}
}
-
+
private static int getIgnoreCount(JSLineBreakpoint bp) {
int ignoreCount = 0;
if (Breakpoint.HIT_COUNT_FILTERING_STYLE.GREATER.equals(bp.getHitCountFilteringStyle())) {
@@ -160,6 +174,7 @@ public class TruffleBreakpointsHandler {
assert t.isMethodInvoking();
ThreadReference tr = t.getThreadReference();
VirtualMachine vm = tr.virtualMachine();
+ PersistentValues persistents = new PersistentValues(vm);
try {
Method setLineBreakpointMethod = ClassTypeWrapper.concreteMethodByName(
accessorClass,
@@ -168,10 +183,10 @@ public class TruffleBreakpointsHandler {
if (setLineBreakpointMethod == null) {
throw new IllegalStateException("Method "+ACCESSOR_SET_LINE_BREAKPOINT+" with signature:\n"+ACCESSOR_SET_LINE_BREAKPOINT_MGR_SIGNAT+"\nis not present in accessor class "+accessorClass);
}
- Value uriRef = vm.mirrorOf(uri.toString());
+ Value uriRef = persistents.mirrorOf(uri.toString());
IntegerValue lineRef = vm.mirrorOf(line);
IntegerValue icRef = vm.mirrorOf(ignoreCount);
- StringReference conditionRef = (condition != null) ? vm.mirrorOf(condition) : null;
+ StringReference conditionRef = (condition != null) ? persistents.mirrorOf(condition) : null;
List<? extends Value> args = Arrays.asList(new Value[] { debugManager, uriRef, lineRef, icRef, conditionRef });
ObjectReference ret = (ObjectReference) ClassTypeWrapper.invokeMethod(
accessorClass,
@@ -183,9 +198,11 @@ public class TruffleBreakpointsHandler {
} catch (VMDisconnectedExceptionWrapper | InternalExceptionWrapper |
ClassNotLoadedException | ClassNotPreparedExceptionWrapper |
IncompatibleThreadStateException | InvalidTypeException |
- ObjectCollectedExceptionWrapper ex) {
+ UnsupportedOperationExceptionWrapper | ObjectCollectedExceptionWrapper ex) {
Exceptions.printStackTrace(Exceptions.attachMessage(ex, "Setting breakpoint to "+uri+":"+line));
return null;
+ } finally {
+ persistents.collect();
}
}
@@ -199,7 +216,7 @@ public class TruffleBreakpointsHandler {
if (tiuri != null) {
uri = tiuri;
} else {
- uri = fileObject.toURI();
+ uri = SourceBinaryTranslator.source2Binary(fileObject);
}
final int line = bp.getLineNumber();
final int ignoreCount = getIgnoreCount(bp);
@@ -219,24 +236,28 @@ public class TruffleBreakpointsHandler {
public void callMethods(JPDAThread thread) throws InvocationException {
ThreadReference tr = ((JPDAThreadImpl) thread).getThreadReference();
VirtualMachine vm = tr.virtualMachine();
- StringReference uriRef = vm.mirrorOf(uri.toString());
- IntegerValue lineRef = vm.mirrorOf(line);
- IntegerValue icRef = vm.mirrorOf(ignoreCount);
- StringReference conditionRef = (condition != null) ? vm.mirrorOf(condition) : null;
- List<? extends Value> args = Arrays.asList(new Value[] { uriRef, lineRef, icRef, conditionRef });
+ PersistentValues persistents = new PersistentValues(vm);
try {
+ StringReference uriRef = persistents.mirrorOf(uri.toString());
+ IntegerValue lineRef = vm.mirrorOf(line);
+ IntegerValue icRef = vm.mirrorOf(ignoreCount);
+ StringReference conditionRef = (condition != null) ? persistents.mirrorOf(condition) : null;
+ List<? extends Value> args = Arrays.asList(new Value[] { uriRef, lineRef, icRef, conditionRef });
ArrayReference ret = (ArrayReference) ClassTypeWrapper.invokeMethod(
accessorClass,
tr,
setLineBreakpointMethod,
args,
ObjectReference.INVOKE_SINGLE_THREADED);
+ ret.disableCollection();
bpRef[0] = ret;
} catch (InvalidTypeException | ClassNotLoadedException |
- IncompatibleThreadStateException |
+ IncompatibleThreadStateException | UnsupportedOperationExceptionWrapper |
InternalExceptionWrapper | VMDisconnectedExceptionWrapper |
ObjectCollectedExceptionWrapper ex) {
Exceptions.printStackTrace(Exceptions.attachMessage(ex, "Setting breakpoint to "+uri+":"+line));
+ } finally {
+ persistents.collect();
}
}
});
@@ -254,6 +275,7 @@ public class TruffleBreakpointsHandler {
breakpoints.add((ObjectReference) v);
}
}
+ bpArray.enableCollection();
}
if (!breakpoints.isEmpty()) {
synchronized (breakpointsMap) {
@@ -418,6 +440,7 @@ public class TruffleBreakpointsHandler {
if (vm == null) {
return ;
}
+ PersistentValues persistents = new PersistentValues(vm);
switch (propertyName) {
case JSLineBreakpoint.PROP_ENABLED:
method = TruffleBPMethods.setEnabled;
@@ -426,7 +449,7 @@ public class TruffleBreakpointsHandler {
case JSLineBreakpoint.PROP_CONDITION:
method = TruffleBPMethods.setCondition;
String condition = jsbp.getCondition();
- StringReference conditionRef = (condition != null) ? vm.mirrorOf(condition) : null;
+ StringReference conditionRef = (condition != null) ? persistents.mirrorOf0(condition) : null;
args = Collections.singletonList(conditionRef);
break;
case Breakpoint.PROP_HIT_COUNT_FILTER:
@@ -439,7 +462,11 @@ public class TruffleBreakpointsHandler {
((JPDADebuggerImpl) debugger).getRequestProcessor().post(new Runnable() {
@Override
public void run() {
- setBreakpointProperty(jsbp, method, args);
+ try {
+ setBreakpointProperty(jsbp, method, args);
+ } finally {
+ persistents.collect();
+ }
}
});
}
diff --git a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/frames/TruffleStackFrame.java b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/frames/TruffleStackFrame.java
index 6ef5d69..ac74193 100644
--- a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/frames/TruffleStackFrame.java
+++ b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/frames/TruffleStackFrame.java
@@ -35,7 +35,7 @@ import org.netbeans.modules.debugger.jpda.truffle.access.CurrentPCInfo;
import org.netbeans.modules.debugger.jpda.truffle.access.TruffleAccess;
import org.netbeans.modules.debugger.jpda.truffle.source.Source;
import org.netbeans.modules.debugger.jpda.truffle.source.SourcePosition;
-import org.netbeans.modules.debugger.jpda.truffle.vars.TruffleScope;
+import org.netbeans.modules.debugger.jpda.truffle.vars.impl.TruffleScope;
import org.openide.util.Exceptions;
/**
diff --git a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/source/Source.java b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/source/Source.java
index 74c59ed..426642f 100644
--- a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/source/Source.java
+++ b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/source/Source.java
@@ -64,6 +64,8 @@ public final class Source {
} catch (IOException ex) {
Exceptions.printStackTrace(ex);
}
+ } else {
+ uri = SourceBinaryTranslator.binary2Source(uri);
}
if (url == null) {
try {
diff --git a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/source/SourceBinaryTranslator.java b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/source/SourceBinaryTranslator.java
new file mode 100644
index 0000000..1ab8656
--- /dev/null
+++ b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/source/SourceBinaryTranslator.java
@@ -0,0 +1,126 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.netbeans.modules.debugger.jpda.truffle.source;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URL;
+import org.netbeans.api.java.classpath.ClassPath;
+import org.netbeans.api.java.project.JavaProjectConstants;
+import org.netbeans.api.java.queries.BinaryForSourceQuery;
+import org.netbeans.api.project.FileOwnerQuery;
+import org.netbeans.api.project.Project;
+import org.netbeans.api.project.ProjectManager;
+import org.netbeans.api.project.ProjectUtils;
+import org.netbeans.api.project.SourceGroup;
+import org.netbeans.api.project.Sources;
+import org.netbeans.spi.java.queries.BinaryForSourceQueryImplementation;
+import org.netbeans.spi.java.queries.SourceForBinaryQueryImplementation;
+import org.openide.filesystems.FileObject;
+import org.openide.filesystems.FileUtil;
+import org.openide.filesystems.URLMapper;
+
+public final class SourceBinaryTranslator {
+
+ private static final String[] SOURCE_IDS = new String[] {JavaProjectConstants.SOURCES_TYPE_RESOURCES, JavaProjectConstants.SOURCES_TYPE_JAVA, JavaProjectConstants.SOURCES_TYPE_MODULES};
+
+ /**
+ * Returns a file from binary location, that corresponds to the provided one.
+ * If none is found, the provided file's URI is returned.
+ */
+ public static URI source2Binary(FileObject fileObject) {
+ Project project = FileOwnerQuery.getOwner(fileObject);
+ if (project != null) {
+ BinaryForSourceQueryImplementation binaryForSource = project.getLookup().lookup(BinaryForSourceQueryImplementation.class);
+ if (binaryForSource != null) {
+ Sources sources = ProjectUtils.getSources(project);
+ for (String sourceId : SOURCE_IDS) {
+ SourceGroup[] sourceGroups = sources.getSourceGroups(sourceId);
+ for (SourceGroup sourceGroup : sourceGroups) {
+ FileObject sourceRoot = sourceGroup.getRootFolder();
+ String relativePath = FileUtil.getRelativePath(sourceRoot, fileObject);
+ if (relativePath != null) {
+ BinaryForSourceQuery.Result binaryRoots = binaryForSource.findBinaryRoots(sourceRoot.toURL());
+ if (binaryRoots != null) {
+ URL[] roots = binaryRoots.getRoots();
+ for (URL root : roots) {
+ FileObject rootFo = URLMapper.findFileObject(root);
+ if (rootFo != null) {
+ FileObject binaryFo = rootFo.getFileObject(relativePath);
+ if (binaryFo != null && binaryFo.getSize() == fileObject.getSize()) {
+ return binaryFo.toURI();
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return fileObject.toURI();
+ }
+
+
+ /**
+ * Returns a file from source location, that corresponds to the provided one.
+ * If none is found, the provided file's URI is returned.
+ */
+ public static URI binary2Source(URI uri) {
+ FileObject fileObject;
+ try {
+ fileObject = URLMapper.findFileObject(uri.toURL());
+ } catch (MalformedURLException ex) {
+ return uri;
+ }
+ if (fileObject != null) {
+ Project project = FileOwnerQuery.getOwner(fileObject);
+ if (project != null) {
+ BinaryForSourceQueryImplementation binaryForSource = project.getLookup().lookup(BinaryForSourceQueryImplementation.class);
+ if (binaryForSource != null) {
+ Sources sources = ProjectUtils.getSources(project);
+ for (String sourceId : SOURCE_IDS) {
+ SourceGroup[] sourceGroups = sources.getSourceGroups(sourceId);
+ for (SourceGroup sourceGroup : sourceGroups) {
+ FileObject sourceRoot = sourceGroup.getRootFolder();
+ BinaryForSourceQuery.Result binaryRoots = binaryForSource.findBinaryRoots(sourceRoot.toURL());
+ if (binaryRoots != null) {
+ URL[] roots = binaryRoots.getRoots();
+ for (URL root : roots) {
+ FileObject rootFo = URLMapper.findFileObject(root);
+ if (rootFo != null) {
+ String relativePath = FileUtil.getRelativePath(rootFo, fileObject);
+ if (relativePath != null) {
+ FileObject sourceFo = sourceRoot.getFileObject(relativePath);
+ if (sourceFo != null && sourceFo.getSize() == fileObject.getSize()) {
+ return sourceFo.toURI();
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return uri;
+ }
+}
diff --git a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/TruffleVariable.java b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/TruffleVariable.java
index 3674c42..e096eb4 100644
--- a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/TruffleVariable.java
+++ b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/TruffleVariable.java
@@ -21,8 +21,10 @@ package org.netbeans.modules.debugger.jpda.truffle.vars;
import org.netbeans.api.debugger.jpda.JPDADebugger;
import org.netbeans.api.debugger.jpda.ObjectVariable;
+import org.netbeans.api.debugger.jpda.Variable;
import org.netbeans.modules.debugger.jpda.truffle.LanguageName;
import org.netbeans.modules.debugger.jpda.truffle.source.SourcePosition;
+import org.netbeans.modules.debugger.jpda.truffle.vars.impl.TruffleVariableImpl;
/**
* Representation of <code>DebugValue</code>.
@@ -43,6 +45,8 @@ public interface TruffleVariable {
Object getValue();
+ String getDisplayValue();
+
boolean hasValueSource();
SourcePosition getValueSource();
@@ -56,4 +60,8 @@ public interface TruffleVariable {
Object[] getChildren();
ObjectVariable setValue(JPDADebugger debugger, String newExpression);
+
+ public static TruffleVariable get(Variable var) {
+ return TruffleVariableImpl.get(var);
+ }
}
diff --git a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/TruffleEvaluator.java b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/impl/TruffleEvaluator.java
similarity index 97%
rename from java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/TruffleEvaluator.java
rename to java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/impl/TruffleEvaluator.java
index f62ddc8..0775584 100644
--- a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/TruffleEvaluator.java
+++ b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/impl/TruffleEvaluator.java
@@ -17,7 +17,7 @@
* under the License.
*/
-package org.netbeans.modules.debugger.jpda.truffle.vars;
+package org.netbeans.modules.debugger.jpda.truffle.vars.impl;
import org.netbeans.api.debugger.jpda.CallStackFrame;
import org.netbeans.api.debugger.jpda.InvalidExpressionException;
diff --git a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/TruffleExpression.java b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/impl/TruffleExpression.java
similarity index 94%
copy from java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/TruffleExpression.java
copy to java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/impl/TruffleExpression.java
index 62e9c8a..2af97d8 100644
--- a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/TruffleExpression.java
+++ b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/impl/TruffleExpression.java
@@ -17,7 +17,7 @@
* under the License.
*/
-package org.netbeans.modules.debugger.jpda.truffle.vars;
+package org.netbeans.modules.debugger.jpda.truffle.vars.impl;
public final class TruffleExpression {
diff --git a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/TruffleScope.java b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/impl/TruffleScope.java
similarity index 95%
rename from java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/TruffleScope.java
rename to java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/impl/TruffleScope.java
index 42370ce..d787c66 100644
--- a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/TruffleScope.java
+++ b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/impl/TruffleScope.java
@@ -17,11 +17,12 @@
* under the License.
*/
-package org.netbeans.modules.debugger.jpda.truffle.vars;
+package org.netbeans.modules.debugger.jpda.truffle.vars.impl;
import org.netbeans.api.debugger.jpda.JPDADebugger;
import org.netbeans.api.debugger.jpda.ObjectVariable;
import org.netbeans.modules.debugger.jpda.truffle.access.TruffleAccess;
+import org.netbeans.modules.debugger.jpda.truffle.vars.TruffleVariable;
/**
* Representation of DebugScope.
diff --git a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/TruffleStackVariable.java b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/impl/TruffleStackVariable.java
similarity index 95%
rename from java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/TruffleStackVariable.java
rename to java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/impl/TruffleStackVariable.java
index 62903ba..910720b 100644
--- a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/TruffleStackVariable.java
+++ b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/impl/TruffleStackVariable.java
@@ -17,13 +17,14 @@
* under the License.
*/
-package org.netbeans.modules.debugger.jpda.truffle.vars;
+package org.netbeans.modules.debugger.jpda.truffle.vars.impl;
import java.util.function.Supplier;
import org.netbeans.api.debugger.jpda.JPDADebugger;
import org.netbeans.api.debugger.jpda.ObjectVariable;
import org.netbeans.modules.debugger.jpda.truffle.LanguageName;
import org.netbeans.modules.debugger.jpda.truffle.source.SourcePosition;
+import org.netbeans.modules.debugger.jpda.truffle.vars.TruffleVariable;
public class TruffleStackVariable implements TruffleVariable {
@@ -101,6 +102,11 @@ public class TruffleStackVariable implements TruffleVariable {
}
@Override
+ public String getDisplayValue() {
+ return valueStr;
+ }
+
+ @Override
public ObjectVariable setValue(JPDADebugger debugger, String newExpression) {
if (this.valueStr.equals(newExpression)) {
return null;
diff --git a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/TruffleVariableImpl.java b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/impl/TruffleVariableImpl.java
similarity index 98%
rename from java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/TruffleVariableImpl.java
rename to java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/impl/TruffleVariableImpl.java
index 3ec8ad4..163a3bd 100644
--- a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/TruffleVariableImpl.java
+++ b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/impl/TruffleVariableImpl.java
@@ -17,7 +17,7 @@
* under the License.
*/
-package org.netbeans.modules.debugger.jpda.truffle.vars;
+package org.netbeans.modules.debugger.jpda.truffle.vars.impl;
import java.io.InvalidObjectException;
import org.netbeans.api.debugger.jpda.Field;
@@ -30,6 +30,7 @@ import org.netbeans.modules.debugger.jpda.truffle.LanguageName;
import org.netbeans.modules.debugger.jpda.truffle.access.CurrentPCInfo;
import org.netbeans.modules.debugger.jpda.truffle.access.TruffleAccess;
import org.netbeans.modules.debugger.jpda.truffle.source.SourcePosition;
+import org.netbeans.modules.debugger.jpda.truffle.vars.TruffleVariable;
import org.openide.util.Exceptions;
public class TruffleVariableImpl implements TruffleVariable {
diff --git a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/models/TruffleLocalVariablesTreeModel.java b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/models/TruffleLocalVariablesTreeModel.java
index aa7d518..81c304d 100644
--- a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/models/TruffleLocalVariablesTreeModel.java
+++ b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/models/TruffleLocalVariablesTreeModel.java
@@ -26,7 +26,7 @@ import org.netbeans.modules.debugger.jpda.truffle.access.CurrentPCInfo;
import org.netbeans.modules.debugger.jpda.truffle.access.TruffleAccess;
import org.netbeans.modules.debugger.jpda.truffle.access.TruffleStrataProvider;
import org.netbeans.modules.debugger.jpda.truffle.frames.TruffleStackFrame;
-import org.netbeans.modules.debugger.jpda.truffle.vars.TruffleScope;
+import org.netbeans.modules.debugger.jpda.truffle.vars.impl.TruffleScope;
import org.netbeans.modules.debugger.jpda.truffle.vars.TruffleVariable;
import org.netbeans.spi.debugger.ContextProvider;
import org.netbeans.spi.debugger.DebuggerServiceRegistration;
diff --git a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/models/TruffleVariablesNodeModel.java b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/models/TruffleVariablesNodeModel.java
index a0d7266..1731ba1 100644
--- a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/models/TruffleVariablesNodeModel.java
+++ b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/models/TruffleVariablesNodeModel.java
@@ -31,7 +31,7 @@ import org.netbeans.api.debugger.jpda.Super;
import org.netbeans.api.debugger.jpda.This;
import org.netbeans.api.debugger.jpda.Variable;
import org.netbeans.modules.debugger.jpda.truffle.access.TruffleStrataProvider;
-import org.netbeans.modules.debugger.jpda.truffle.vars.TruffleScope;
+import org.netbeans.modules.debugger.jpda.truffle.vars.impl.TruffleScope;
import org.netbeans.modules.debugger.jpda.truffle.vars.TruffleVariable;
import org.netbeans.spi.debugger.DebuggerServiceRegistration;
import org.netbeans.spi.debugger.DebuggerServiceRegistrations;
diff --git a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/models/TruffleVariablesTableModel.java b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/models/TruffleVariablesTableModel.java
index edb8f61..d776869 100644
--- a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/models/TruffleVariablesTableModel.java
+++ b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/models/TruffleVariablesTableModel.java
@@ -32,9 +32,9 @@ import org.netbeans.modules.debugger.jpda.truffle.access.CurrentPCInfo;
import org.netbeans.modules.debugger.jpda.truffle.access.TruffleAccess;
import org.netbeans.modules.debugger.jpda.truffle.access.TruffleStrataProvider;
import org.netbeans.modules.debugger.jpda.truffle.frames.TruffleStackFrame;
-import org.netbeans.modules.debugger.jpda.truffle.vars.TruffleScope;
+import org.netbeans.modules.debugger.jpda.truffle.vars.impl.TruffleScope;
import org.netbeans.modules.debugger.jpda.truffle.vars.TruffleVariable;
-import org.netbeans.modules.debugger.jpda.truffle.vars.TruffleVariableImpl;
+import org.netbeans.modules.debugger.jpda.truffle.vars.impl.TruffleVariableImpl;
import org.netbeans.spi.debugger.ContextProvider;
import org.netbeans.spi.debugger.DebuggerServiceRegistration;
import org.netbeans.spi.debugger.DebuggerServiceRegistrations;
diff --git a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/models/TruffleVariablesTreeModel.java b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/models/TruffleVariablesTreeModel.java
index 66c135c..a8ef2b2 100644
--- a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/models/TruffleVariablesTreeModel.java
+++ b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/models/TruffleVariablesTreeModel.java
@@ -25,9 +25,9 @@ import java.util.concurrent.CopyOnWriteArrayList;
import org.netbeans.api.debugger.jpda.JPDADebugger;
import org.netbeans.api.debugger.jpda.Variable;
import org.netbeans.modules.debugger.jpda.truffle.access.TruffleStrataProvider;
-import org.netbeans.modules.debugger.jpda.truffle.vars.TruffleScope;
+import org.netbeans.modules.debugger.jpda.truffle.vars.impl.TruffleScope;
import org.netbeans.modules.debugger.jpda.truffle.vars.TruffleVariable;
-import org.netbeans.modules.debugger.jpda.truffle.vars.TruffleVariableImpl;
+import org.netbeans.modules.debugger.jpda.truffle.vars.impl.TruffleVariableImpl;
import org.netbeans.spi.debugger.ContextProvider;
import org.netbeans.spi.debugger.DebuggerServiceRegistration;
import org.netbeans.spi.debugger.DebuggerServiceRegistrations;
diff --git a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/tooltip/ToolTipAnnotation.java b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/tooltip/ToolTipAnnotation.java
index 8a89c1c..314f3d6 100644
--- a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/tooltip/ToolTipAnnotation.java
+++ b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/tooltip/ToolTipAnnotation.java
@@ -38,7 +38,7 @@ import org.netbeans.api.debugger.jpda.ObjectVariable;
import org.netbeans.api.debugger.jpda.Variable;
import org.netbeans.modules.debugger.jpda.truffle.access.TruffleEval;
import org.netbeans.modules.debugger.jpda.truffle.access.TruffleStrataProvider;
-import org.netbeans.modules.debugger.jpda.truffle.vars.TruffleVariableImpl;
+import org.netbeans.modules.debugger.jpda.truffle.vars.impl.TruffleVariableImpl;
import org.netbeans.spi.debugger.ui.EditorContextDispatcher;
import org.openide.cookies.EditorCookie;
import org.openide.loaders.DataObject;
diff --git a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/TruffleExpression.java b/java/debugger.jpda.truffle/truffle-backend/org/netbeans/modules/debugger/jpda/backend/truffle/AgentClassLoader.java
similarity index 52%
rename from java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/TruffleExpression.java
rename to java/debugger.jpda.truffle/truffle-backend/org/netbeans/modules/debugger/jpda/backend/truffle/AgentClassLoader.java
index 62e9c8a..c9a4a13 100644
--- a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/TruffleExpression.java
+++ b/java/debugger.jpda.truffle/truffle-backend/org/netbeans/modules/debugger/jpda/backend/truffle/AgentClassLoader.java
@@ -16,22 +16,25 @@
* specific language governing permissions and limitations
* under the License.
*/
+package org.netbeans.modules.debugger.jpda.backend.truffle;
-package org.netbeans.modules.debugger.jpda.truffle.vars;
+/**
+ * The classes of Truffle debugging backend are loaded in this class loader,
+ * to be isolated from the guest application.
+ * <p>
+ * This class loader is exported to Truffle
+ * (by com.oracle.truffle.polyglot.LanguageCache$Loader.exportTruffle())
+ * to be able to access Truffle module code on JDK 9+.
+ */
+public final class AgentClassLoader extends ClassLoader {
-public final class TruffleExpression {
-
- private final String expr;
-
- public static TruffleExpression parse (String expr) {
- return new TruffleExpression(expr);
- }
-
- private TruffleExpression(String expr) {
- this.expr = expr;
+ public AgentClassLoader() throws ClassNotFoundException {
+ super(getTruffleClassLoader());
}
-
- public String getExpression() {
- return expr;
+
+ private static ClassLoader getTruffleClassLoader() throws ClassNotFoundException {
+ Class truffleClass = Class.forName("com.oracle.truffle.api.Truffle");
+ return truffleClass.getClassLoader();
}
+
}
diff --git a/java/debugger.jpda.truffle/truffle-backend/org/netbeans/modules/debugger/jpda/backend/truffle/JPDATruffleAccessor.java b/java/debugger.jpda.truffle/truffle-backend/org/netbeans/modules/debugger/jpda/backend/truffle/JPDATruffleAccessor.java
index af6d364..d30c94a 100644
--- a/java/debugger.jpda.truffle/truffle-backend/org/netbeans/modules/debugger/jpda/backend/truffle/JPDATruffleAccessor.java
+++ b/java/debugger.jpda.truffle/truffle-backend/org/netbeans/modules/debugger/jpda/backend/truffle/JPDATruffleAccessor.java
@@ -78,7 +78,10 @@ public class JPDATruffleAccessor extends Object {
*/
//private static int stepCmd = 0;
- public JPDATruffleAccessor() {}
+ public JPDATruffleAccessor() {
+ // JDI needs to know about String class in this class loader.
+ new String("Initialize String class");
+ }
static Thread startAccessLoop() {
if (!accessLoopRunning) {
diff --git a/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/JPDAStepImpl.java b/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/JPDAStepImpl.java
index d5de421..e762f6f 100644
--- a/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/JPDAStepImpl.java
+++ b/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/JPDAStepImpl.java
@@ -127,6 +127,41 @@ public class JPDAStepImpl extends JPDAStep implements Executor {
p = Properties.getDefault().getProperties("debugger.options.JPDA"); // NOI18N
}
+ private String[] applyExclusionPatterns(StepRequest stepRequest) throws InternalExceptionWrapper, VMDisconnectedExceptionWrapper {
+ String[] exclusionPatterns;
+ String[] stepFilters = getSteppingFilters();
+ if (ignoreStepFilters || steppingFromFilteredLocation) {
+ exclusionPatterns = stepFilters;
+ } else {
+ exclusionPatterns = debugger.getSmartSteppingFilter().getExclusionPatterns();
+ if (stepFilters != null) {
+ int epl = exclusionPatterns.length;
+ exclusionPatterns = Arrays.copyOf(exclusionPatterns, epl + stepFilters.length);
+ System.arraycopy(stepFilters, 0, exclusionPatterns, epl, stepFilters.length);
+ }
+ }
+ if (exclusionPatterns != null) {
+ for (int i = 0; i < exclusionPatterns.length; i++) {
+ StepRequestWrapper.addClassExclusionFilter(stepRequest, exclusionPatterns [i]);
+ logger.finer(" add pattern: "+exclusionPatterns[i]);
+ }
+ } else {
+ exclusionPatterns = new String[]{};
+ }
+ return exclusionPatterns;
+ }
+
+ private String[] getCurrentExclusionPatterns() {
+ String[] exclusionPatterns = debugger.getSmartSteppingFilter().getExclusionPatterns();
+ String[] stepFilters = getSteppingFilters();
+ if (stepFilters != null) {
+ int epl = exclusionPatterns.length;
+ exclusionPatterns = Arrays.copyOf(exclusionPatterns, epl + stepFilters.length);
+ System.arraycopy(stepFilters, 0, exclusionPatterns, epl, stepFilters.length);
+ }
+ return exclusionPatterns;
+ }
+
@Override
public void addStep(JPDAThread tr) {
JPDADebuggerImpl debuggerImpl = (JPDADebuggerImpl) debugger;
@@ -191,28 +226,11 @@ public class JPDAStepImpl extends JPDAStep implements Executor {
getDepth()
);
//stepRequest.addCountFilter(1); - works bad with exclusion filters!
- String[] exclusionPatterns;
- if (ignoreStepFilters || steppingFromFilteredLocation) {
- exclusionPatterns = null;
- } else {
- exclusionPatterns = debuggerImpl.getSmartSteppingFilter().getExclusionPatterns();
- for (int i = 0; i < exclusionPatterns.length; i++) {
- StepRequestWrapper.addClassExclusionFilter(stepRequest, exclusionPatterns [i]);
- logger.finer(" add pattern: "+exclusionPatterns[i]);
- }
- }
+ String[] exclusionPatterns = applyExclusionPatterns(stepRequest);
debuggerImpl.getOperator().register(stepRequest, this);
EventRequestWrapper.setSuspendPolicy(stepRequest, debugger.getSuspend());
- boolean useStepFilters = p.getBoolean("UseStepFilters", true);
- boolean stepThrough = useStepFilters && p.getBoolean("StepThroughFilters", false);
- if (!stepThrough && exclusionPatterns != null && exclusionPatterns.length > 0) {
- StepPatternDepth spd = new StepPatternDepth();
- spd.exclusionPatterns = exclusionPatterns;
- spd.stackDepth = tr.getStackDepth();
- stepPatternDepth = spd;
- } else {
- stepPatternDepth = null;
- }
+ boolean stepThrough = isStepThroughFilters();
+ stepPatternDepth = new StepPatternDepth(tr.getStackDepth(), exclusionPatterns, stepThrough);
logger.fine("Set stepPatternDepth to "+stepPatternDepth);
try {
@@ -583,13 +601,12 @@ public class JPDAStepImpl extends JPDAStep implements Executor {
tr.addLastOperation(lastOperation);
}
logger.fine("Have stepPatternDepth : "+stepPatternDepth);
- int stepDepthDiff = 0;
- if (stepPatternDepth != null) {
+ int sd = tr.getStackDepth();
+ int stepDepthDiff = (stepPatternDepth != null) ? sd - stepPatternDepth.stackDepth : 0;
+ if (stepPatternDepth != null && !stepPatternDepth.isStepThrough && stepPatternDepth.exclusionPatterns != null && stepPatternDepth.exclusionPatterns.length >= 0) {
StepPatternDepth newStepPatternDepth = null;
try {
- int sd = tr.getStackDepth();
logger.fine("Current stack depth = "+sd);
- stepDepthDiff = sd - stepPatternDepth.stackDepth;
if (stepDepthDiff > 1) {
// There are some (possibly filtered) stack frames in between.
// StepThroughFilters is false, therefore we should step out if we can not stop here:
@@ -616,16 +633,14 @@ public class JPDAStepImpl extends JPDAStep implements Executor {
StepRequest.STEP_OUT
);
EventRequestWrapper.addCountFilter(stepRequest, 1);
- String[] exclusionPatterns = debuggerImpl.getSmartSteppingFilter().getExclusionPatterns();
+ String[] exclusionPatterns = getCurrentExclusionPatterns();
// JDI is inconsistent!!! Step into steps *through* filters, but step out does *NOT*
//for (int i = 0; i < exclusionPatterns.length; i++) {
//StepRequestWrapper.addClassExclusionFilter(stepRequest, exclusionPatterns [i]);
//}
if (sd > (stepPatternDepth.stackDepth + 2)) {
// There's still something perhaps filterable in beteen
- newStepPatternDepth = new StepPatternDepth();
- newStepPatternDepth.exclusionPatterns = exclusionPatterns;
- newStepPatternDepth.stackDepth = stepPatternDepth.stackDepth;
+ newStepPatternDepth = new StepPatternDepth(stepPatternDepth.stackDepth, exclusionPatterns, stepPatternDepth.isStepThrough);
}
debuggerImpl.getOperator ().register (stepRequest, this);
@@ -832,7 +847,7 @@ public class JPDAStepImpl extends JPDAStep implements Executor {
JPDADebuggerImpl debuggerImpl = (JPDADebuggerImpl) debugger;
// 2) init info about current state
boolean useStepFilters = p.getBoolean("UseStepFilters", true);
- boolean stepThrough = useStepFilters && p.getBoolean("StepThroughFilters", false);
+ boolean stepThrough = isStepThroughFilters();
try {
ThreadReference tr = LocatableEventWrapper.thread (event);
JPDAThreadImpl t = debuggerImpl.getThread (tr);
@@ -887,7 +902,7 @@ public class JPDAStepImpl extends JPDAStep implements Executor {
stop = debuggerImpl.stopHere(t);
}
if (stop.isStop() && !steppingFromFilteredLocation) {
- String[] exclusionPatterns = debuggerImpl.getSmartSteppingFilter().getExclusionPatterns();
+ String[] exclusionPatterns = getCurrentExclusionPatterns();
String className = ReferenceTypeWrapper.name(LocationWrapper.declaringType(loc));
for (String pattern : exclusionPatterns) {
if (match(className, pattern)) {
@@ -932,27 +947,10 @@ public class JPDAStepImpl extends JPDAStep implements Executor {
doStepDepth
);
//EventRequestWrapper.addCountFilter(stepRequest, 1);
- String[] exclusionPatterns;
- if (ignoreStepFilters || steppingFromFilteredLocation) {
- exclusionPatterns = null;
- } else {
- exclusionPatterns = debuggerImpl.getSmartSteppingFilter().getExclusionPatterns();
- if (doStepDepth != StepRequest.STEP_OUT) {
- for (int i = 0; i < exclusionPatterns.length; i++) {
- StepRequestWrapper.addClassExclusionFilter(stepRequest, exclusionPatterns [i]);
- }
- }
- }
+ String[] exclusionPatterns = applyExclusionPatterns(stepRequest);
debuggerImpl.getOperator ().register (stepRequest, this);
EventRequestWrapper.setSuspendPolicy (stepRequest, debugger.getSuspend ());
- if (!stepThrough && exclusionPatterns != null && exclusionPatterns.length > 0) {
- StepPatternDepth spd = new StepPatternDepth();
- spd.exclusionPatterns = exclusionPatterns;
- spd.stackDepth = t.getStackDepth();
- stepPatternDepth = spd;
- } else {
- stepPatternDepth = null;
- }
+ stepPatternDepth = new StepPatternDepth(t.getStackDepth(), exclusionPatterns, stepThrough);
logger.fine("Set stepPatternDepth to "+stepPatternDepth);
try {
EventRequestWrapper.enable (stepRequest);
@@ -1019,24 +1017,8 @@ public class JPDAStepImpl extends JPDAStep implements Executor {
logger.throwing(getClass().getName(), "shouldNotStopHere", ex);
}
}
- String[] exclusionPatterns;
- if (steppingFromFilteredLocation) {
- exclusionPatterns = null;
- } else {
- exclusionPatterns = debuggerImpl.getSmartSteppingFilter().getExclusionPatterns();
- for (int i = 0; i < exclusionPatterns.length; i++) {
- StepRequestWrapper.addClassExclusionFilter(stepRequest, exclusionPatterns [i]);
- logger.finer(" add pattern: "+exclusionPatterns[i]);
- }
- }
- if (!stepThrough && exclusionPatterns != null && exclusionPatterns.length > 0) {
- StepPatternDepth spd = new StepPatternDepth();
- spd.exclusionPatterns = exclusionPatterns;
- spd.stackDepth = t.getStackDepth();
- stepPatternDepth = spd;
- } else {
- stepPatternDepth = null;
- }
+ String[] exclusionPatterns = applyExclusionPatterns(stepRequest);
+ stepPatternDepth = new StepPatternDepth(t.getStackDepth(), exclusionPatterns, stepThrough);
logger.fine("Set stepPatternDepth to "+stepPatternDepth);
debuggerImpl.getOperator ().register (stepRequest, this);
@@ -1232,8 +1214,15 @@ public class JPDAStepImpl extends JPDAStep implements Executor {
private static final class StepPatternDepth {
- String[] exclusionPatterns;
- int stackDepth;
+ final String[] exclusionPatterns;
+ final int stackDepth;
+ final boolean isStepThrough;
+
+ StepPatternDepth(int stackDepth, String[] exclusionPatterns, boolean isStepThrough) {
+ this.stackDepth = stackDepth;
+ this.exclusionPatterns = exclusionPatterns;
+ this.isStepThrough = isStepThrough;
+ }
private boolean isFiltered(String className) {
for (int i = 0; i < exclusionPatterns.length; i++) {
diff --git a/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/breakpoints/LineBreakpointImpl.java b/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/breakpoints/LineBreakpointImpl.java
index 98ca2da..0a92290 100644
--- a/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/breakpoints/LineBreakpointImpl.java
+++ b/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/breakpoints/LineBreakpointImpl.java
@@ -44,6 +44,8 @@ import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
@@ -242,7 +244,7 @@ public class LineBreakpointImpl extends ClassBasedBreakpoint {
if (!isInSources) {
String relativePath = EditorContextBridge.getRelativePath(className);
String classURL = getDebugger().getEngineContext().getURL(relativePath, true);
- if (classURL != null && !classURL.equals(breakpoint.getURL())) {
+ if (classURL != null && !areURLEqual(classURL, breakpoint.getURL())) {
// Silently ignore breakpoints from other sources that resolve to a different URL.
logger.log(Level.FINE,
"LineBreakpoint {0} NOT submitted, because it's URL ''{1}'' differes from class ''{2}'' URL ''{3}''.",
@@ -293,6 +295,17 @@ public class LineBreakpointImpl extends ClassBasedBreakpoint {
}
}
+ private static boolean areURLEqual(String url1, String url2) {
+ if (url1.equals(url2)) {
+ return true;
+ }
+ try {
+ return new URI(url1).equals(new URI(url2));
+ } catch (URISyntaxException ex) {
+ return false;
+ }
+ }
+
private void setInvalid(String reason) {
logger.warning(
"Unable to submit line breakpoint to "+getBreakpoint().getURL()+
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@netbeans.apache.org
For additional commands, e-mail: commits-help@netbeans.apache.org
For further information about the NetBeans mailing lists, visit:
https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists