Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[NETBEANS-7069] Support Nashorn 15.x for JDK >= 15 #7972

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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,7 @@
@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 = "org.openjdk.nashorn.internal.runtime.ScriptFunctionData"; // NOI18N
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I'm not mistaken, this also need to be duplicated so that both in-jdk and external nashorn are supported.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch, you are correct, I missed this. Need to apply for both Nashorns too.

private static final String[] SCRIPT_ACCESS_METHODS = { "invoke", "construct" }; // NOI18N
// New notifyInvoke API:
private static final String SCRIPT_NOTIFY_INVOKE_METHOD = "notifyInvoke"; // NOI18N
Expand Down Expand Up @@ -96,7 +96,9 @@ public StepIntoJSHandler(ContextProvider lookupProvider) {
scriptAccessBPs[i] = 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 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,25 @@
@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();
private BreakpointsSet activeSet = breakpointsLegacyJdk;
private final Object sourceBreakpointsInitLock = new Object();

public JSJavaBreakpointsManager() {
Expand All @@ -106,29 +109,37 @@ 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 (int i=0; i < 2; i++) {
BreakpointsSet set = (i == 0) ? breakpointsLegacyJdk : breakpointsNashornExt;
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,18 @@ public void engineAdded(DebuggerEngine engine) {
}
initSourceBreakpoints();
ScriptsHandler sh = new ScriptsHandler(debugger);
scriptBP.addJPDABreakpointListener(sh);
sourceBindBP.addJPDABreakpointListener(sh);
functionClassBP.addJPDABreakpointListener(sh);
debuggerBP.addJPDABreakpointListener(sh);
List<JPDAClassType> classesByName = DebuggerSupport.getSupportDebuggerClasses(debugger);
if (classesByName.isEmpty()) {
return ;
}
JPDAClassType contextClass = classesByName.get(0);
boolean legacyJdk = DebuggerSupport.isLegacyNashorn(contextClass);
activeSet = legacyJdk ? breakpointsLegacyJdk : breakpointsNashornExt;

activeSet.scriptBP.addJPDABreakpointListener(sh);
activeSet.sourceBindBP.addJPDABreakpointListener(sh);
activeSet.functionClassBP.addJPDABreakpointListener(sh);
activeSet.debuggerBP.addJPDABreakpointListener(sh);
synchronized (scriptHandlers) {
scriptHandlers.put(debugger, sh);
}
Expand All @@ -220,15 +239,22 @@ 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();
activeSet.scriptBP.removeJPDABreakpointListener(sh);
activeSet.sourceBindBP.removeJPDABreakpointListener(sh);
activeSet.functionClassBP.removeJPDABreakpointListener(sh);
activeSet.debuggerBP.removeJPDABreakpointListener(sh);
activeSet.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 +287,7 @@ public void breakpointReached(JPDABreakpointEvent event) {
return ;
}
Object eventSource = event.getSource();
if (scriptBP == eventSource) {
if (activeSet.scriptBP == eventSource) {
// A new script class is loaded.
Variable scriptClass = event.getVariable();
if (!(scriptClass instanceof ClassVariable)) {
Expand All @@ -287,7 +313,7 @@ public void breakpointReached(JPDABreakpointEvent event) {
scriptAccessBreakpoints.put(scriptMethodBP, scriptType);
}
}
} else if (sourceBindBP == eventSource) {
} else if (activeSet.sourceBindBP == eventSource) {
Variable sourceVar = null;
Variable scriptClass = null;
try {
Expand Down Expand Up @@ -326,10 +352,10 @@ public void breakpointReached(JPDABreakpointEvent event) {
}
if (!isSourceBind) {
isSourceBind = true;
scriptBP.disable();
activeSet.scriptBP.disable();
}
}
} else if (functionClassBP == eventSource) {
} else if (activeSet.functionClassBP == eventSource) {
Variable rootClass = null;
Variable sourceVar = null;
try {
Expand Down Expand Up @@ -366,7 +392,7 @@ public void breakpointReached(JPDABreakpointEvent event) {
source.addFunctionClass((ClassVariable) rootClass);
}
}
} else if (debuggerBP == eventSource) {
} else if (activeSet.debuggerBP == eventSource) {
JPDAStep step = debugger.createJPDAStep(JPDAStep.STEP_LINE, JPDAStep.STEP_INTO);
step.addStep(event.getThread());
} else {
Expand Down Expand Up @@ -398,11 +424,12 @@ public void propertyChange(PropertyChangeEvent evt) {
});
return ;
}
List<JPDAClassType> classesByName = debugger.getClassesByName(NASHORN_CONTEXT_CLASS);
List<JPDAClassType> classesByName = debugger.getClassesByName((activeSet == breakpointsLegacyJdk) ? NASHORN_CONTEXT_CLASS_JDK : NASHORN_CONTEXT_CLASS_EXT);
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 +442,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
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ public final class Source {

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

private static final String SOURCE_CLASS = "jdk.nashorn.internal.runtime.Source"; // NOI18N
private static final String SOURCE_CLASS_JDK = "jdk.nashorn.internal.runtime.Source"; // NOI18N
private static final String SOURCE_CLASS_EXT = "org.openjdk.nashorn.internal.runtime.Source"; // NOI18N
private static final String SOURCE_FIELD = "source"; // NOI18N

private static final String SOURCE_VAR_NAME = "name"; // NOI18N
Expand Down Expand Up @@ -227,7 +228,7 @@ private static ObjectVariable getSourceVar(JPDADebugger debugger, JPDAClassType
for (Field sf : staticFields) {
if (sf instanceof ObjectVariable &&
SOURCE_FIELD.equals(sf.getName()) &&
SOURCE_CLASS.equals(sf.getType())) {
(SOURCE_CLASS_JDK.equals(sf.getType()) || SOURCE_CLASS_EXT.equals(sf.getType()))) {

return (ObjectVariable) sf;
}
Expand Down
Loading