Skip to content

Commit

Permalink
Merge pull request #43448 from HindujaB/java21-fix
Browse files Browse the repository at this point in the history
[Java21] Fix failing debugger for java 21
  • Loading branch information
warunalakshitha authored Oct 8, 2024
2 parents 6b69ca8 + 7bd7966 commit aafc07e
Show file tree
Hide file tree
Showing 18 changed files with 136 additions and 87 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/pull_request_ubuntu_build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ jobs:
run: |
export DISPLAY=':99.0'
/usr/bin/Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &
./gradlew build -x jballerina-debugger-integration-test:test -Pnative.test --max-workers=2 --scan --no-daemon
./gradlew build -Pnative.test --max-workers=2 --scan --no-daemon
- name: Generate Jacoco report
if: github.event_name == 'pull_request'
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/pull_request_windows_build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,5 +65,5 @@ jobs:
env:
packageUser: ${{ github.actor }}
packagePAT: ${{ secrets.GITHUB_TOKEN }}
run: ./gradlew.bat build --continue -x :ballerina-lang:test -x :jballerina-integration-test:test -x jballerina-debugger-integration-test:test -x javadoc --stacktrace -scan --console=plain --no-daemon --no-parallel
run: ./gradlew.bat build --continue -x :ballerina-lang:test -x :jballerina-integration-test:test -x javadoc --stacktrace -scan --console=plain --no-daemon --no-parallel

Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package io.ballerina.runtime.internal;

import io.ballerina.runtime.api.Module;
import io.ballerina.runtime.internal.values.ValueCreator;

/**
* This class represents the Ballerina runtime that is created using a classloader for internal purposes.
Expand All @@ -37,4 +38,10 @@ Class<?> loadClass(String className) throws ClassNotFoundException {
String name = getFullQualifiedClassName(rootModule, className);
return Class.forName(name, true, classLoader);
}

@Override
public void stop() {
super.stop();
ValueCreator.removeValueCreator(rootModule);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@ public static ValueCreator getValueCreator(String key) {
return runtimeValueCreators.get(key);
}

public static void removeValueCreator(Module rootModule) {
String key = getLookupKey(rootModule, false);
runtimeValueCreators.remove(key);
}

public Object call(Strand strand, String funcName, Object... args) throws BError {
throw new ErrorValue(StringUtils.fromString("No such method: " + funcName));
}
Expand Down
3 changes: 2 additions & 1 deletion bvm/ballerina-runtime/src/main/java/module-info.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@
io.ballerina.lang.table, io.ballerina.lang.value, io.ballerina.lang.xml, ballerina.debug.adapter.core,
io.ballerina.cli, io.ballerina.lang.integer, io.ballerina.lang.bool, io.ballerina.lang.decimal,
io.ballerina.lang.floatingpoint, io.ballerina.lang.internal, io.ballerina.lang.function,
io.ballerina.lang.regexp, io.ballerina.runtime.profiler, io.ballerina.shell;
io.ballerina.lang.regexp, io.ballerina.runtime.profiler, io.ballerina.shell,
org.ballerinalang.debugadapter.runtime;
exports io.ballerina.runtime.internal.commons to io.ballerina.lang.value;
exports io.ballerina.runtime.internal.launch to io.ballerina.testerina.runtime, io.ballerina.packerina,
ballerina.test.listener, io.ballerina.cli, org.ballerinalang.debugadapter.runtime;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,9 @@
*/
// TODO move this class to a separate Java package. e.g. io.ballerina.projects.platform.jballerina
public enum JvmTarget implements CompilerBackend.TargetPlatform {
JAVA_17("java17"),
JAVA_21("java21"),
JAVA_17("java17"),
JAVA_11("java11");
// TODO need to move java21 to the top when the central issue #2792 is fixed

private final String code;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -951,6 +951,10 @@ Map<Integer, ThreadReferenceProxyImpl> getAllThreads() {
threadsMap.put((int) threadReference.uniqueID(), new ThreadReferenceProxyImpl(context.getDebuggeeVM(),
threadReference));
}
for (ThreadReference threadReference: eventProcessor.getVirtualThreads()) {
threadsMap.put((int) threadReference.uniqueID(), new ThreadReferenceProxyImpl(context.getDebuggeeVM(),
threadReference));
}
return threadsMap;
}

Expand Down Expand Up @@ -1103,8 +1107,9 @@ private void attachToRemoteVM(String hostName, int portName) throws IOException,
VirtualMachine attachedVm = executionManager.attach(hostName, portName);
context.setDebuggeeVM(new VirtualMachineProxyImpl(attachedVm));
EventRequestManager erm = context.getEventManager();
ClassPrepareRequest classPrepareRequest = erm.createClassPrepareRequest();
classPrepareRequest.enable();
erm.createClassPrepareRequest().enable();
erm.createThreadStartRequest().enable();
erm.createThreadDeathRequest().enable();
eventProcessor.startListening();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,16 @@

import com.sun.jdi.AbsentInformationException;
import com.sun.jdi.Location;
import com.sun.jdi.ThreadReference;
import com.sun.jdi.VMDisconnectedException;
import com.sun.jdi.event.BreakpointEvent;
import com.sun.jdi.event.ClassPrepareEvent;
import com.sun.jdi.event.Event;
import com.sun.jdi.event.EventIterator;
import com.sun.jdi.event.EventSet;
import com.sun.jdi.event.StepEvent;
import com.sun.jdi.event.ThreadDeathEvent;
import com.sun.jdi.event.ThreadStartEvent;
import com.sun.jdi.event.VMDeathEvent;
import com.sun.jdi.event.VMDisconnectEvent;
import com.sun.jdi.request.EventRequest;
Expand All @@ -42,6 +45,7 @@
import java.util.LinkedHashMap;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CopyOnWriteArrayList;

import static org.ballerinalang.debugadapter.BreakpointProcessor.DynamicBreakpointMode;
import static org.ballerinalang.debugadapter.JBallerinaDebugServer.isBalStackFrame;
Expand All @@ -56,6 +60,7 @@ public class JDIEventProcessor {
private final BreakpointProcessor breakpointProcessor;
private boolean isRemoteVmAttached = false;
private final List<EventRequest> stepRequests = new ArrayList<>();
private static final List<ThreadReference> virtualThreads = new CopyOnWriteArrayList<>();
private static final Logger LOGGER = LoggerFactory.getLogger(JDIEventProcessor.class);

JDIEventProcessor(ExecutionContext context) {
Expand All @@ -71,6 +76,10 @@ List<EventRequest> getStepRequests() {
return stepRequests;
}

List<ThreadReference> getVirtualThreads() {
return virtualThreads;
}

/**
* Asynchronously listens and processes the incoming JDI events.
*/
Expand Down Expand Up @@ -121,6 +130,16 @@ private void processEvent(EventSet eventSet, Event event) {
|| event instanceof VMDeathEvent
|| event instanceof VMDisconnectedException) {
isRemoteVmAttached = false;
} else if (event instanceof ThreadStartEvent threadStartEvent) {
ThreadReference thread = threadStartEvent.thread();
if (thread.isVirtual()) {
virtualThreads.add(thread);
}
eventSet.resume();
} else if (event instanceof ThreadDeathEvent threadDeathEvent) {
ThreadReference thread = threadDeathEvent.thread();
virtualThreads.remove(thread);
eventSet.resume();
} else {
eventSet.resume();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
import static org.ballerinalang.debugadapter.evaluation.EvaluationException.createEvaluationException;
import static org.ballerinalang.debugadapter.evaluation.EvaluationExceptionKind.FUNCTION_EXECUTION_ERROR;
import static org.ballerinalang.debugadapter.evaluation.utils.EvaluationUtils.B_DEBUGGER_RUNTIME_CLASS;
import static org.ballerinalang.debugadapter.evaluation.utils.EvaluationUtils.B_SCHEDULER_CLASS;
import static org.ballerinalang.debugadapter.evaluation.utils.EvaluationUtils.INVOKE_FUNCTION_ASYNC;
import static org.ballerinalang.debugadapter.evaluation.utils.EvaluationUtils.JAVA_LANG_CLASSLOADER;
import static org.ballerinalang.debugadapter.evaluation.utils.EvaluationUtils.JAVA_OBJECT_ARRAY_CLASS;
Expand Down Expand Up @@ -58,7 +57,6 @@ protected Value invoke() throws EvaluationException {
}
List<String> argTypeList = new ArrayList<>();
argTypeList.add(JAVA_LANG_CLASSLOADER);
argTypeList.add(B_SCHEDULER_CLASS);
argTypeList.add(JAVA_STRING_CLASS);
argTypeList.add(JAVA_STRING_CLASS);
argTypeList.add(JAVA_OBJECT_ARRAY_CLASS);
Expand All @@ -67,7 +65,6 @@ protected Value invoke() throws EvaluationException {

List<Value> scheduleMethodArgs = new ArrayList<>();
scheduleMethodArgs.add(context.getDebuggeeClassLoader());
scheduleMethodArgs.add(null);
scheduleMethodArgs.add(EvaluationUtils.getAsJString(context, classRef.name()));
scheduleMethodArgs.add(EvaluationUtils.getAsJString(context, methodRef.name()));
scheduleMethodArgs.addAll(getMethodArgs(this));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@
org = "ballerina"
name = "debugger_helpers"
version = "1.0.0"

[[platform.java21.dependency]]
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@
import io.ballerina.runtime.api.values.BValue;
import io.ballerina.runtime.api.values.BXml;
import io.ballerina.runtime.api.values.BXmlSequence;
import io.ballerina.runtime.internal.configurable.providers.ConfigDetails;
import io.ballerina.runtime.internal.launch.LaunchUtils;
import io.ballerina.runtime.internal.BalRuntime;
import io.ballerina.runtime.internal.ClassloaderRuntime;
import io.ballerina.runtime.internal.scheduling.Scheduler;
import io.ballerina.runtime.internal.scheduling.Strand;
import io.ballerina.runtime.internal.types.BAnnotatableType;
Expand All @@ -55,13 +55,11 @@
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

Expand Down Expand Up @@ -106,7 +104,7 @@ public class DebuggerRuntime {
public static Object invokeObjectMethod(BObject bObject, String methodName, Object... args) {
try {
final Object[] paramValues = args[0] instanceof Strand ? Arrays.copyOfRange(args, 1, args.length) : args;
final Strand strand = args[0] instanceof Strand s ? s : Scheduler.getStrand();
final Strand strand = args[0] instanceof Strand s ? s : Scheduler.getStrand();
return ((ObjectValue) bObject).call(strand, methodName, paramValues);
} catch (Exception e) {
throw ErrorCreator.createError(StringUtils.fromString("invocation failed: " + e.getMessage()));
Expand All @@ -130,12 +128,12 @@ public static Object invokeFunction(ClassLoader classLoader, String className, S
try {
return method.invoke(null, paramValues);
} catch (IllegalAccessException | InvocationTargetException e) {
throw ErrorCreator.createError(StringUtils.fromString(
"'" + methodName + "' function invocation failed: " + e.getMessage()));
throw ErrorCreator.createError(StringUtils.fromString("'" + methodName +
"' function invocation failed: " + e.getMessage()));
}
} catch (Exception e) {
throw ErrorCreator.createError(StringUtils.fromString(
"'" + methodName + "' function invocation failed: " + e.getMessage()));
throw ErrorCreator.createError(StringUtils.fromString("'" + methodName +
"' function invocation failed: " + e.getMessage()));
}
}

Expand All @@ -149,8 +147,8 @@ public static Object invokeFunction(ClassLoader classLoader, String className, S
* @param fieldValues field values
* @return Ballerina object instance
*/
public static Object createObjectValue(String pkgOrg, String pkgName, String pkgVersion, String objectTypeName,
Object... fieldValues) {
public static Object createObjectValue(String pkgOrg, String pkgName, String pkgVersion,
String objectTypeName, Object... fieldValues) {
Module packageId = new Module(pkgOrg, pkgName, pkgVersion);
return ValueCreator.createObjectValue(packageId, objectTypeName, fieldValues);
}
Expand Down Expand Up @@ -195,8 +193,9 @@ public static Object createErrorValue(Object message, Object cause, Object... de
}

ErrorType bErrorType = createErrorType(TypeConstants.ERROR, PredefinedTypes.TYPE_ERROR.getPackage());
BMap<BString, Object> errorDetailsMap = ValueCreator.createMapValue((MapType) PredefinedTypes.TYPE_ERROR_DETAIL,
errorDetailEntries.toArray(errorDetailEntries.toArray(new BMapInitialValueEntry[0])));
BMap<BString, Object> errorDetailsMap = ValueCreator.createMapValue((MapType)
PredefinedTypes.TYPE_ERROR_DETAIL, errorDetailEntries.toArray(
errorDetailEntries.toArray(new BMapInitialValueEntry[0])));
return ErrorCreator.createError(bErrorType, (StringValue) message, (ErrorValue) cause, errorDetailsMap);
}

Expand All @@ -209,28 +208,23 @@ public static Object createErrorValue(Object message, Object cause, Object... de
*/
public static Object getAnnotationValue(Object typedescValue, String annotationName) {
if (!(typedescValue instanceof TypedescValue)) {
return ErrorCreator.createError(StringUtils.fromString("Incompatible types: expected 'typedesc`, " +
"found '" + typedescValue.toString() + "'."));
return ErrorCreator.createError(StringUtils.fromString("Incompatible types: expected 'typedesc`, "
+ "found '" + typedescValue.toString() + "'."));
}
Type type = ((TypedescValue) typedescValue).getDescribingType();
if (type instanceof BAnnotatableType) {
return ((BAnnotatableType) type).getAnnotations().entrySet()
.stream()
.filter(annotationEntry -> annotationEntry.getKey().getValue().endsWith(annotationName))
.findFirst()
.map(Map.Entry::getValue)
.orElse(null);
return ((BAnnotatableType) type).getAnnotations().entrySet().stream().filter(annotationEntry ->
annotationEntry.getKey().getValue().endsWith(annotationName)).findFirst()
.map(Map.Entry::getValue).orElse(null);
}

return ErrorCreator.createError(StringUtils.fromString("type: '" + TypeUtils.getType(type.getEmptyValue())
+ "' does not support annotation access."));
+ "' does not support annotation access."));
}

private static Method getMethod(String functionName, Class<?> funcClass) throws NoSuchMethodException {
Method declaredMethod = Arrays.stream(funcClass.getDeclaredMethods())
.filter(method -> functionName.equals(method.getName()))
.findAny()
.orElse(null);
Method declaredMethod = Arrays.stream(funcClass.getDeclaredMethods()).filter(method ->
functionName.equals(method.getName())).findAny().orElse(null);

if (declaredMethod != null) {
return declaredMethod;
Expand Down Expand Up @@ -324,9 +318,8 @@ private static BString[] processXMLNamePattern(String xmlNamePattern) {
xmlNamePattern = stepParts[stepParts.length - 1];
}

return Arrays.stream(xmlNamePattern.split(XML_NAME_PATTERN_SEPARATOR))
.map(entry -> StringUtils.fromString(entry.trim()))
.toArray(BString[]::new);
return Arrays.stream(xmlNamePattern.split(XML_NAME_PATTERN_SEPARATOR)).map(entry ->
StringUtils.fromString(entry.trim())).toArray(BString[]::new);
}

/**
Expand All @@ -341,11 +334,6 @@ private static BString[] processXMLNamePattern(String xmlNamePattern) {
public static Object classloadAndInvokeFunction(String executablePath, String mainClass, String functionName,
Object... userArgs) {
try {
// Need to pass the strand (or null) as the first argument for the generated function.
List<Object> functionArgs = new ArrayList<>();
functionArgs.add(null);
functionArgs.addAll(Arrays.asList(userArgs));

URL pathUrl = Paths.get(executablePath).toUri().toURL();
URLClassLoader classLoader = AccessController.doPrivileged((PrivilegedAction<URLClassLoader>) () ->
new URLClassLoader(new URL[]{pathUrl}, ClassLoader.getSystemClassLoader()));
Expand All @@ -355,26 +343,35 @@ public static Object classloadAndInvokeFunction(String executablePath, String ma
String packageOrg = mainClassNameParts[0];
String packageName = mainClassNameParts[1];
String packageVersion = mainClassNameParts[2];
String packageNameSpace = String.join(".", packageOrg, packageName, packageVersion);

Module module = new Module(packageOrg, packageName, packageVersion, false);
return invokeBalRuntimeMethod(functionName, module, classLoader, userArgs);
} catch (Exception e) {
return e.getMessage();
}
}

// Initialize configurations
ConfigDetails configurationDetails = LaunchUtils.getConfigurationDetails();
invokeMethodDirectly(classLoader, String.join(".", packageNameSpace, CONFIGURE_INIT_CLASS_NAME),
CONFIGURE_INIT_METHOD_NAME, new Class[]{Map.class, String[].class, Path[].class, String.class},
new Object[]{new HashMap<>(), new String[]{}, configurationDetails.paths,
configurationDetails.configContent});
private static Object invokeBalRuntimeMethod(String functionName, Module module, ClassLoader classLoader,
Object[] paramValues) {
BalRuntime runtime = new ClassloaderRuntime(module, classLoader);
Object result;
try {
// Initialize the module
invokeFunction(classLoader, String.join(".", packageNameSpace, MODULE_INIT_CLASS_NAME),
MODULE_INIT_METHOD_NAME, new Object[1]);
runtime.init();
// Start the module
invokeFunction(classLoader, String.join(".", packageNameSpace, MODULE_INIT_CLASS_NAME),
MODULE_START_METHOD_NAME, new Object[1]);
// Run the actual method
return invokeFunction(classLoader, mainClass, functionName, functionArgs.toArray());
} catch (Exception e) {
return e.getMessage();
runtime.start();
// Then call run method
result = runtime.call(module, functionName, paramValues);
} catch (Throwable throwable) {
throw ErrorCreator.createError(StringUtils.fromString("'" + functionName + "' function " +
"invocation failed : " + throwable.getMessage()));
} finally {
try {
runtime.stop();
} catch (BError ignored) {
// stop errors are ignored
}
}
return result;
}

/**
Expand Down
Loading

0 comments on commit aafc07e

Please sign in to comment.