Skip to content

Commit

Permalink
Merge pull request #7972 from cz6ace/NETBEANS-7069_nashorn-15
Browse files Browse the repository at this point in the history
[NETBEANS-7069] Support Nashorn 15.x for JDK >= 15
  • Loading branch information
matthiasblaesing authored Dec 30, 2024
2 parents 35b31ef + 9a5a9d7 commit 5151af3
Show file tree
Hide file tree
Showing 12 changed files with 213 additions and 106 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,10 @@ public class FirstSourceURLProvider extends SourcePathProvider {

private static final String[] NO_SOURCE_ROOTS = new String[]{};

private static final String pathPrefix = "jdk/nashorn/internal/scripts/"; // NOI18N
// prefix for Nashorn built in JDK
private static final String pathPrefixJdk = "jdk/nashorn/internal/scripts/"; // NOI18N
// prefix for external Nashorn
private static final String pathPrefixExt = "org/openjdk/nashorn/internal/scripts/"; // NOI18N

private final ContextProvider contextProvider;
private SourcePathProvider sourcePath;
Expand All @@ -56,19 +59,33 @@ public class FirstSourceURLProvider extends SourcePathProvider {
public FirstSourceURLProvider(ContextProvider contextProvider) {
this.contextProvider = contextProvider;
}

/**
* Returns relative path Nashorn scripts. Either from JDK or from External
* @param relativePath
* @return relative path or null if does match
*/
private String getRelativePath(String relativePath) {
if (relativePath.startsWith(pathPrefixJdk)) {
return relativePath.substring(pathPrefixJdk.length());
} else if (relativePath.startsWith(pathPrefixExt)) {
return relativePath.substring(pathPrefixExt.length());
}
return null;
}

@Override
public String getURL(String relativePath, boolean global) {
if (relativePath.startsWith(pathPrefix)) {
relativePath = relativePath.substring(pathPrefix.length());
String foundRelativePath = getRelativePath(relativePath);
if (foundRelativePath != null) {
synchronized (rootDirsLock) {
if (rootDirs == null) {
sourcePath = getSourcePathProvider();
sourcePath.addPropertyChangeListener(new SourcePathListener());
rootDirs = computeModuleRoots();
}
for (FileObject root : rootDirs) {
FileObject fo = root.getFileObject(relativePath);
FileObject fo = root.getFileObject(foundRelativePath);
if (fo != null) {
return fo.toURL().toExternalForm();
}
Expand All @@ -78,9 +95,17 @@ public String getURL(String relativePath, boolean global) {
return null;
}

/**
* @param clazz
* @return true if and only if the clazz belongs to Nashorh script (JDK or External)
*/
private boolean isNashornScript(JPDAClassType clazz) {
return clazz.getName().startsWith(JSUtils.NASHORN_SCRIPT_JDK) || clazz.getName().startsWith(JSUtils.NASHORN_SCRIPT_EXT);
}

public String getURL(JPDAClassType clazz, String stratum) {
if (!(stratum == null || JSUtils.JS_STRATUM.equals(stratum)) ||
!clazz.getName().startsWith(JSUtils.NASHORN_SCRIPT)) {
!isNashornScript(clazz)) {
return null;
}
Source source = Source.getSource(clazz);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,12 @@ public class JSUtils {
public static final String JS_MIME_TYPE = "text/javascript"; // NOI18N
public static final String JS_STRATUM = "JS"; // NOI18N

public static final String NASHORN_SCRIPT = "jdk.nashorn.internal.scripts.Script$"; // NOI18N
// Script class for Nashorn built in JDK
public static final String NASHORN_SCRIPT_JDK = "jdk.nashorn.internal.scripts.Script$"; // NOI18N
// avoid API type removed warning, but do not use this constant, use explicitly _JDK or _EXT suffixes
public static final String NASHORN_SCRIPT = NASHORN_SCRIPT_JDK;
// Script class for external Nashorn
public static final String NASHORN_SCRIPT_EXT = "org.openjdk.nashorn.internal.scripts.Script$"; // NOI18N

public static final String VAR_THIS = ":this"; // NOI18N
public static final String VAR_SCOPE = ":scope"; // NOI18N
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@
@LazyActionsManagerListener.Registration(path="netbeans-JPDASession/Java")
public class StepIntoJSHandler extends LazyActionsManagerListener implements PropertyChangeListener {

private static final String SCRIPT_ACCESS_CLASS = "jdk.nashorn.internal.runtime.ScriptFunctionData"; // NOI18N
private static final String SCRIPT_ACCESS_CLASS_JDK = "jdk.nashorn.internal.runtime.ScriptFunctionData"; // NOI18N
private static final String SCRIPT_ACCESS_CLASS_EXT = "org.openjdk.nashorn.internal.runtime.ScriptFunctionData"; // NOI18N
private static final String[] SCRIPT_ACCESS_METHODS = { "invoke", "construct" }; // NOI18N
// New notifyInvoke API:
private static final String SCRIPT_NOTIFY_INVOKE_METHOD = "notifyInvoke"; // NOI18N
Expand All @@ -83,20 +84,25 @@ public StepIntoJSHandler(ContextProvider lookupProvider) {
debugger.addPropertyChangeListener(JPDADebugger.PROP_CURRENT_CALL_STACK_FRAME, new CurrentSFTracker());
ScriptBPListener sbl = new ScriptBPListener();
int mbn = SCRIPT_ACCESS_METHODS.length;
scriptAccessBPs = new MethodBreakpoint[mbn];
for (int i = 0; i < mbn; i++) {
String method = SCRIPT_ACCESS_METHODS[i];
MethodBreakpoint mb = MethodBreakpoint.create(SCRIPT_ACCESS_CLASS, method);
mb.setHidden(true);
mb.setSuspend(debugger.getSuspend());
mb.setSession(debugger);
mb.disable();
mb.addJPDABreakpointListener(sbl);
DebuggerManager.getDebuggerManager().addBreakpoint(mb);
scriptAccessBPs[i] = mb;
scriptAccessBPs = new MethodBreakpoint[mbn * 2]; // JDK + External Nashorn
for (int jdk=0; jdk < 2; jdk++) {
boolean legacyJdk = (jdk == 0);
for (int i = 0; i < mbn; i++) {
String method = SCRIPT_ACCESS_METHODS[i];
MethodBreakpoint mb = MethodBreakpoint.create(legacyJdk ? SCRIPT_ACCESS_CLASS_JDK : SCRIPT_ACCESS_CLASS_EXT, method);
mb.setHidden(true);
mb.setSuspend(debugger.getSuspend());
mb.setSession(debugger);
mb.disable();
mb.addJPDABreakpointListener(sbl);
DebuggerManager.getDebuggerManager().addBreakpoint(mb);
scriptAccessBPs[i + jdk*mbn] = mb;
}
}
ScriptInvokeBPListener sibl = new ScriptInvokeBPListener();
notifyInvokeBP = MethodBreakpoint.create(DebuggerSupport.DEBUGGER_SUPPORT_CLASS,
// try which Nashorn debugger is available
String debugSupportClass = !debugger.getClassesByName(DebuggerSupport.DEBUGGER_SUPPORT_CLASS_JDK).isEmpty() ? DebuggerSupport.DEBUGGER_SUPPORT_CLASS_JDK : DebuggerSupport.DEBUGGER_SUPPORT_CLASS_EXT;
notifyInvokeBP = MethodBreakpoint.create(debugSupportClass,
SCRIPT_NOTIFY_INVOKE_METHOD);
notifyInvokeBP.setMethodSignature(SCRIPT_NOTIFY_INVOKE_METHOD_SIG);
notifyInvokeBP.setHidden(true);
Expand All @@ -110,7 +116,7 @@ public StepIntoJSHandler(ContextProvider lookupProvider) {
public void propertyChange(PropertyChangeEvent evt) {
if (Breakpoint.VALIDITY.VALID.equals(notifyInvokeBP.getValidity())) {
// notifyInvoke is available we can remove the script access breakpoints
logger.log(Level.FINE, "{0} is valid => we can disable breakpoints on "+SCRIPT_ACCESS_CLASS, notifyInvokeBP);
logger.log(Level.FINE, "{0} is valid => we can disable breakpoints on "+SCRIPT_ACCESS_CLASS_JDK + "/" + SCRIPT_ACCESS_CLASS_EXT, notifyInvokeBP);
for (MethodBreakpoint mb : scriptAccessBPs) {
logger.log(Level.FINE, "{0} disable", mb);
mb.disable();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
import org.netbeans.modules.debugger.jpda.js.JSUtils;
import org.netbeans.modules.debugger.jpda.js.source.ObservableSet;
import org.netbeans.modules.debugger.jpda.js.source.Source;
import org.netbeans.modules.debugger.jpda.js.vars.DebuggerSupport;
import org.netbeans.modules.javascript2.debug.breakpoints.JSLineBreakpoint;
import org.netbeans.spi.debugger.DebuggerServiceRegistration;
import org.openide.util.Exceptions;
Expand All @@ -81,23 +82,26 @@
@DebuggerServiceRegistration(types=LazyDebuggerManagerListener.class)
public class JSJavaBreakpointsManager extends DebuggerManagerAdapter {

private static final String NASHORN_CONTEXT_CLASS = "jdk.nashorn.internal.runtime.Context"; // NOI18N
private static final String NASHORN_CONTEXT_CLASS_JDK = "jdk.nashorn.internal.runtime.Context"; // NOI18N
private static final String NASHORN_CONTEXT_CLASS_EXT = "org.openjdk.nashorn.internal.runtime.Context"; // NOI18N
private static final String NASHORN_CONTEXT_SOURCE_BIND_METHOD = "cacheClass"; // NOI18N

private static final String NASHORN_SCRIPT_RUNTIME_CLASS = "jdk.nashorn.internal.runtime.ScriptRuntime"; // NOI18N
private static final String NASHORN_SCRIPT_RUNTIME_CLASS_JDK = "jdk.nashorn.internal.runtime.ScriptRuntime"; // NOI18N
private static final String NASHORN_SCRIPT_RUNTIME_CLASS_EXT = "org.openjdk.nashorn.internal.runtime.ScriptRuntime"; // NOI18N
private static final String NASHORN_SCRIPT_RUNTIME_DEBUGGER_METHOD = "DEBUGGER"; // NOI18N

private static final String NASHORN_FUNCTION_NODE_CLASS = "jdk.nashorn.internal.ir.FunctionNode"; // NOI18N
private static final String NASHORN_FUNCTION_NODE_CLASS_JDK = "jdk.nashorn.internal.ir.FunctionNode"; // NOI18N
private static final String NASHORN_FUNCTION_NODE_CLASS_EXT = "org.openjdk.nashorn.internal.ir.FunctionNode"; // NOI18N
private static final String NASHORN_FUNCTION_NODE_SET_CLASS = "setRootClass"; // NOI18N

private static final Logger LOG = Logger.getLogger(JSJavaBreakpointsManager.class.getName());

private final Map<JPDADebugger, ScriptsHandler> scriptHandlers = new HashMap<>();
private final Map<URLEquality, Set<JSLineBreakpoint>> breakpointsByURL = new HashMap<>();
private ClassLoadUnloadBreakpoint scriptBP;
private MethodBreakpoint sourceBindBP;
private MethodBreakpoint functionClassBP;
private MethodBreakpoint debuggerBP;
private final BreakpointsSet breakpointsLegacyJdk = new BreakpointsSet();
private final BreakpointsSet breakpointsNashornExt = new BreakpointsSet();
// separate sets of breakpoints for Legacy JDK Nashorn and external Nashorn
private BreakpointsSet[] breakpointSets = new BreakpointsSet[] { breakpointsLegacyJdk, breakpointsNashornExt };
private final Object sourceBreakpointsInitLock = new Object();

public JSJavaBreakpointsManager() {
Expand All @@ -106,29 +110,36 @@ public JSJavaBreakpointsManager() {
@Override
public Breakpoint[] initBreakpoints() {
initSourceBreakpoints();
return new Breakpoint[] { scriptBP, sourceBindBP, functionClassBP, debuggerBP };
return new Breakpoint[] {
breakpointsLegacyJdk.scriptBP, breakpointsLegacyJdk.sourceBindBP, breakpointsLegacyJdk.functionClassBP, breakpointsLegacyJdk.debuggerBP,
breakpointsNashornExt.scriptBP, breakpointsNashornExt.sourceBindBP, breakpointsNashornExt.functionClassBP, breakpointsNashornExt.debuggerBP
};
}

private void initSourceBreakpoints() {
synchronized (sourceBreakpointsInitLock) {
if (scriptBP == null) {
scriptBP = ClassLoadUnloadBreakpoint.create(JSUtils.NASHORN_SCRIPT+"*",
false,
ClassLoadUnloadBreakpoint.TYPE_CLASS_LOADED);
scriptBP.setHidden(true);
scriptBP.setSuspend(EventRequest.SUSPEND_NONE);
if (breakpointsLegacyJdk.scriptBP == null) {
for (BreakpointsSet set : breakpointSets) {
boolean jdk = (set == breakpointsLegacyJdk);

sourceBindBP = MethodBreakpoint.create(NASHORN_CONTEXT_CLASS, NASHORN_CONTEXT_SOURCE_BIND_METHOD);
sourceBindBP.setHidden(true);
sourceBindBP.setSuspend(EventRequest.SUSPEND_EVENT_THREAD);

functionClassBP = MethodBreakpoint.create(NASHORN_FUNCTION_NODE_CLASS, NASHORN_FUNCTION_NODE_SET_CLASS);
functionClassBP.setHidden(true);
functionClassBP.setSuspend(EventRequest.SUSPEND_EVENT_THREAD);

debuggerBP = MethodBreakpoint.create(NASHORN_SCRIPT_RUNTIME_CLASS, NASHORN_SCRIPT_RUNTIME_DEBUGGER_METHOD);
debuggerBP.setHidden(true);
debuggerBP.setSuspend(EventRequest.SUSPEND_EVENT_THREAD);
set.scriptBP = ClassLoadUnloadBreakpoint.create((jdk ? JSUtils.NASHORN_SCRIPT_JDK : JSUtils.NASHORN_SCRIPT_EXT)+"*",
false,
ClassLoadUnloadBreakpoint.TYPE_CLASS_LOADED);
set.scriptBP.setHidden(true);
set.scriptBP.setSuspend(EventRequest.SUSPEND_NONE);

set.sourceBindBP = MethodBreakpoint.create(jdk ? NASHORN_CONTEXT_CLASS_JDK : NASHORN_CONTEXT_CLASS_EXT, NASHORN_CONTEXT_SOURCE_BIND_METHOD);
set.sourceBindBP.setHidden(true);
set.sourceBindBP.setSuspend(EventRequest.SUSPEND_EVENT_THREAD);

set.functionClassBP = MethodBreakpoint.create(jdk ? NASHORN_FUNCTION_NODE_CLASS_JDK : NASHORN_FUNCTION_NODE_CLASS_EXT, NASHORN_FUNCTION_NODE_SET_CLASS);
set.functionClassBP.setHidden(true);
set.functionClassBP.setSuspend(EventRequest.SUSPEND_EVENT_THREAD);

set.debuggerBP = MethodBreakpoint.create(jdk ? NASHORN_SCRIPT_RUNTIME_CLASS_JDK : NASHORN_SCRIPT_RUNTIME_CLASS_EXT, NASHORN_SCRIPT_RUNTIME_DEBUGGER_METHOD);
set.debuggerBP.setHidden(true);
set.debuggerBP.setSuspend(EventRequest.SUSPEND_EVENT_THREAD);
}
}
}
}
Expand Down Expand Up @@ -200,10 +211,14 @@ public void engineAdded(DebuggerEngine engine) {
}
initSourceBreakpoints();
ScriptsHandler sh = new ScriptsHandler(debugger);
scriptBP.addJPDABreakpointListener(sh);
sourceBindBP.addJPDABreakpointListener(sh);
functionClassBP.addJPDABreakpointListener(sh);
debuggerBP.addJPDABreakpointListener(sh);

for (BreakpointsSet set : breakpointSets) {
set.scriptBP.addJPDABreakpointListener(sh);
set.sourceBindBP.addJPDABreakpointListener(sh);
set.functionClassBP.addJPDABreakpointListener(sh);
set.debuggerBP.addJPDABreakpointListener(sh);
}

synchronized (scriptHandlers) {
scriptHandlers.put(debugger, sh);
}
Expand All @@ -220,15 +235,24 @@ public void engineRemoved(DebuggerEngine engine) {
sh = scriptHandlers.remove(debugger);
}
if (sh != null) {
scriptBP.removeJPDABreakpointListener(sh);
sourceBindBP.removeJPDABreakpointListener(sh);
functionClassBP.removeJPDABreakpointListener(sh);
debuggerBP.removeJPDABreakpointListener(sh);
scriptBP.enable();
for (BreakpointsSet set : breakpointSets) {
set.scriptBP.removeJPDABreakpointListener(sh);
set.sourceBindBP.removeJPDABreakpointListener(sh);
set.functionClassBP.removeJPDABreakpointListener(sh);
set.debuggerBP.removeJPDABreakpointListener(sh);
set.scriptBP.enable();
}
sh.destroy();
}
}


private final class BreakpointsSet {
ClassLoadUnloadBreakpoint scriptBP;
MethodBreakpoint sourceBindBP;
MethodBreakpoint functionClassBP;
MethodBreakpoint debuggerBP;
}

private final class ScriptsHandler implements JPDABreakpointListener {

private final JPDADebugger debugger;
Expand Down Expand Up @@ -261,7 +285,7 @@ public void breakpointReached(JPDABreakpointEvent event) {
return ;
}
Object eventSource = event.getSource();
if (scriptBP == eventSource) {
if (breakpointsNashornExt.scriptBP == eventSource || breakpointsLegacyJdk.scriptBP == eventSource) {
// A new script class is loaded.
Variable scriptClass = event.getVariable();
if (!(scriptClass instanceof ClassVariable)) {
Expand All @@ -287,7 +311,7 @@ public void breakpointReached(JPDABreakpointEvent event) {
scriptAccessBreakpoints.put(scriptMethodBP, scriptType);
}
}
} else if (sourceBindBP == eventSource) {
} else if (breakpointsNashornExt.sourceBindBP == eventSource || breakpointsLegacyJdk.sourceBindBP == eventSource) {
Variable sourceVar = null;
Variable scriptClass = null;
try {
Expand Down Expand Up @@ -326,10 +350,11 @@ public void breakpointReached(JPDABreakpointEvent event) {
}
if (!isSourceBind) {
isSourceBind = true;
scriptBP.disable();
breakpointsNashornExt.scriptBP.disable();
breakpointsLegacyJdk.scriptBP.disable();
}
}
} else if (functionClassBP == eventSource) {
} else if (breakpointsNashornExt.functionClassBP == eventSource || breakpointsLegacyJdk.functionClassBP == eventSource) {
Variable rootClass = null;
Variable sourceVar = null;
try {
Expand Down Expand Up @@ -366,7 +391,7 @@ public void breakpointReached(JPDABreakpointEvent event) {
source.addFunctionClass((ClassVariable) rootClass);
}
}
} else if (debuggerBP == eventSource) {
} else if (breakpointsNashornExt.debuggerBP == eventSource || breakpointsLegacyJdk.debuggerBP == eventSource) {
JPDAStep step = debugger.createJPDAStep(JPDAStep.STEP_LINE, JPDAStep.STEP_INTO);
step.addStep(event.getThread());
} else {
Expand Down Expand Up @@ -398,11 +423,12 @@ public void propertyChange(PropertyChangeEvent evt) {
});
return ;
}
List<JPDAClassType> classesByName = debugger.getClassesByName(NASHORN_CONTEXT_CLASS);
List<JPDAClassType> classesByName = DebuggerSupport.getSupportDebuggerClasses(debugger);
if (classesByName.isEmpty()) {
return ;
}
JPDAClassType contextClass = classesByName.get(0);
boolean jdk = DebuggerSupport.isLegacyNashorn(contextClass);
List<ObjectVariable> contextInstances = contextClass.getInstances(0);
if (contextInstances.isEmpty()) {
return ;
Expand All @@ -415,7 +441,7 @@ public void propertyChange(PropertyChangeEvent evt) {
}

// We need to suspend the app to be able to invoke methods:
final MethodBreakpoint inNashorn = MethodBreakpoint.create(NASHORN_FUNCTION_NODE_CLASS, "*");
final MethodBreakpoint inNashorn = MethodBreakpoint.create(jdk ? NASHORN_FUNCTION_NODE_CLASS_JDK : NASHORN_FUNCTION_NODE_CLASS_EXT, "*");
final AtomicBoolean retrieved = new AtomicBoolean(false);
inNashorn.addJPDABreakpointListener(new JPDABreakpointListener() {
@Override
Expand Down
Loading

0 comments on commit 5151af3

Please sign in to comment.