Skip to content

[GR-62994] Consolidate logic for JDWP thread enters/exit of the truffle context. #11370

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

Merged
merged 1 commit into from
Jun 10, 2025
Merged
Changes from all commits
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
@@ -115,6 +115,7 @@ public void run() {

private static class JDWPReceiver implements Runnable {

private static final Object NOT_ENTERED_MARKER = new Object();
private DebuggerController.SetupState setupState;
private final DebuggerController controller;
private RequestedJDWPEvents requestedJDWPEvents;
@@ -199,11 +200,17 @@ public void run() {
setupState = null;
latch.countDown();
}
// Now, begin processing packets when they start to flow from the debugger
// Now, begin processing packets when they start to flow from the debugger.
// Make sure this thread is entered in the context
try {
while (!Thread.currentThread().isInterrupted() && !controller.isClosing()) {
Object previous = NOT_ENTERED_MARKER;
try {
processPacket(Packet.fromByteArray(debuggerConnection.connection.readPacket()));
// get the packet outside the Truffle context, because it's a blocking IO
// operation
Packet packet = Packet.fromByteArray(debuggerConnection.connection.readPacket());
previous = controller.enterTruffleContext();
processPacket(packet);
} catch (IOException e) {
if (!debuggerConnection.isOpen()) {
// when the socket is closed, we're done
@@ -214,6 +221,10 @@ public void run() {
}
} catch (ConnectionClosedException e) {
break;
} finally {
if (previous != NOT_ENTERED_MARKER) {
controller.leaveTruffleContext(previous);
}
}
}
} finally {
@@ -718,4 +729,4 @@ void handleReply(Packet packet, CommandResult result) {
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -706,17 +706,13 @@ public VMEventListener getEventListener() {
}

public Object enterTruffleContext() {
if (truffleContext != null) {
return truffleContext.enter(null);
}
return null;
assert truffleContext != null;
return truffleContext.enter(null);
}

public void leaveTruffleContext(Object previous) {
if (truffleContext != null) {
// pass null as previous since we know the jdwp thread only ever enters one context
truffleContext.leave(null, previous);
}
assert truffleContext != null;
truffleContext.leave(null, previous);
}

@Override
Original file line number Diff line number Diff line change
@@ -403,9 +403,7 @@ static CommandResult createReply(Packet packet, DebuggerController controller) {
// ensure redefinition atomicity by suspending all
// guest threads during the redefine transaction
Object[] allGuestThreads = controller.getVisibleGuestThreads();
Object prev = null;
try {
prev = controller.enterTruffleContext();
for (Object guestThread : allGuestThreads) {
controller.suspend(guestThread);
}
@@ -420,7 +418,6 @@ static CommandResult createReply(Packet packet, DebuggerController controller) {
for (Object guestThread : allGuestThreads) {
controller.resume(guestThread);
}
controller.leaveTruffleContext(prev);
}
return new CommandResult(reply);
}
Original file line number Diff line number Diff line change
@@ -275,20 +275,18 @@ public Object allocateInstance(KlassRef klass) {

@Override
public void steppingInProgress(Thread t, boolean value) {
performInContext(() -> {
context.getLanguage().getThreadLocalStateFor(t).setSteppingInProgress(value);
return null;
});
context.getLanguage().getThreadLocalStateFor(t).setSteppingInProgress(value);
}

@Override
public boolean isSteppingInProgress(Thread t) {
Object previous = null;
try {
previous = controller.enterTruffleContext();
return context.getLanguage().getThreadLocalStateFor(t).isSteppingInProgress();
} finally {
controller.leaveTruffleContext(previous);
EspressoThreadLocalState state = context.getLanguage().getThreadLocalStateFor(t);
// Here, the thread local state can be null for threads having been unregistered already.
// This is OK, and we can safely return false in such cases.
if (state != null) {
return state.isSteppingInProgress();
} else {
return false;
}
}

@@ -304,13 +302,13 @@ public Object[] getAllGuestThreads() {
}
result.add(activeThread);
}
return result.toArray(new StaticObject[result.size()]);
return result.toArray(StaticObject.EMPTY_ARRAY);
}

@Override
public String getStringValue(Object object) {
if (object instanceof StaticObject staticObject) {
return performInContext(() -> (String) UNCACHED.toDisplayString(staticObject, false));
return (String) UNCACHED.toDisplayString(staticObject, false);
}
return object.toString();
}
@@ -422,13 +420,12 @@ public int getArrayLength(Object array) {
StaticObject staticObject = (StaticObject) array;
EspressoLanguage language = context.getLanguage();
if (staticObject.isForeignObject()) {
long arrayLength = performInContext(() -> {
try {
return UNCACHED.getArraySize(staticObject.rawForeignObject(language));
} catch (UnsupportedMessageException e) {
return (long) -1;
}
});
long arrayLength;
try {
arrayLength = UNCACHED.getArraySize(staticObject.rawForeignObject(language));
} catch (UnsupportedMessageException e) {
return -1;
}
if (arrayLength > Integer.MAX_VALUE) {
return -1;
}
@@ -486,19 +483,17 @@ public Object getArrayValue(Object array, int index) {
Klass componentType = ((ArrayKlass) arrayRef.getKlass()).getComponentType();
Meta meta = componentType.getMeta();
if (arrayRef.isForeignObject()) {
return performInContext(() -> {
Object value = null;
try {
value = UNCACHED.readArrayElement(arrayRef.rawForeignObject(arrayRef.getKlass().getLanguage()), index);
return ToEspressoNode.getUncachedToEspresso(componentType, meta).execute(value);
} catch (UnsupportedMessageException e) {
throw EspressoError.shouldNotReachHere("readArrayElement on a non-array foreign object", e);
} catch (InvalidArrayIndexException e) {
throw meta.throwExceptionWithMessage(meta.java_lang_ArrayIndexOutOfBoundsException, e.getMessage());
} catch (UnsupportedTypeException e) {
throw meta.throwExceptionWithMessage(meta.java_lang_ClassCastException, "%s cannot be cast to %s", value, componentType.getTypeAsString());
}
});
Object value = null;
try {
value = UNCACHED.readArrayElement(arrayRef.rawForeignObject(arrayRef.getKlass().getLanguage()), index);
return ToEspressoNode.getUncachedToEspresso(componentType, meta).execute(value);
} catch (UnsupportedMessageException e) {
throw EspressoError.shouldNotReachHere("readArrayElement on a non-array foreign object", e);
} catch (InvalidArrayIndexException e) {
throw meta.throwExceptionWithMessage(meta.java_lang_ArrayIndexOutOfBoundsException, e.getMessage());
} catch (UnsupportedTypeException e) {
throw meta.throwExceptionWithMessage(meta.java_lang_ClassCastException, "%s cannot be cast to %s", value, componentType.getTypeAsString());
}
} else if (componentType.isPrimitive()) {
// primitive array type needs wrapping
Object boxedArray = getUnboxedArray(array);
@@ -520,18 +515,15 @@ public void setArrayValue(Object array, int index, Object value) {
} else {
unWrappedValue = value;
}
performInContext(() -> {
try {
UNCACHED.writeArrayElement(arrayRef.rawForeignObject(arrayRef.getKlass().getLanguage()), index, unWrappedValue);
return null;
} catch (UnsupportedMessageException e) {
throw EspressoError.shouldNotReachHere("writeArrayElement on a non-array foreign object", e);
} catch (UnsupportedTypeException e) {
throw meta.throwExceptionWithMessage(meta.java_lang_ClassCastException, "%s cannot be cast to %s", value, componentType.getTypeAsString());
} catch (InvalidArrayIndexException e) {
throw meta.throwExceptionWithMessage(meta.java_lang_ArrayIndexOutOfBoundsException, e.getMessage());
}
});
try {
UNCACHED.writeArrayElement(arrayRef.rawForeignObject(arrayRef.getKlass().getLanguage()), index, unWrappedValue);
} catch (UnsupportedMessageException e) {
throw EspressoError.shouldNotReachHere("writeArrayElement on a non-array foreign object", e);
} catch (UnsupportedTypeException e) {
throw meta.throwExceptionWithMessage(meta.java_lang_ClassCastException, "%s cannot be cast to %s", value, componentType.getTypeAsString());
} catch (InvalidArrayIndexException e) {
throw meta.throwExceptionWithMessage(meta.java_lang_ArrayIndexOutOfBoundsException, e.getMessage());
}
} else if (componentType.isPrimitive()) {
// primitive array type needs wrapping
Object boxedArray = getUnboxedArray(array);
@@ -618,18 +610,12 @@ public boolean isInstanceOf(Object object, KlassRef klass) {

@Override
public void stopThread(Object guestThread, Object guestThrowable) {
performInContext(() -> {
context.getThreadAccess().stop((StaticObject) guestThread, (StaticObject) guestThrowable);
return null;
});
context.getThreadAccess().stop((StaticObject) guestThread, (StaticObject) guestThrowable);
}

@Override
public void interruptThread(Object thread) {
performInContext(() -> {
context.interruptThread((StaticObject) thread);
return null;
});
context.interruptThread((StaticObject) thread);
}

@Override
@@ -639,10 +625,7 @@ public boolean systemExitImplemented() {

@Override
public void exit(int exitCode) {
performInContext(() -> {
context.truffleExit(null, exitCode);
return null;
});
context.truffleExit(null, exitCode);
}

@Override
@@ -842,19 +825,4 @@ public ModuleRef[] getAllModulesRefs() {
public synchronized int redefineClasses(List<RedefineInfo> redefineInfos) {
return context.getClassRedefinition().redefineClasses(redefineInfos, false, true);
}

private <R> R performInContext(InContextAction<R> action) {
Object previous = null;
try {
previous = controller.enterTruffleContext();
return action.call();
} finally {
controller.leaveTruffleContext(previous);
}
}

@FunctionalInterface
private interface InContextAction<R> {
R call();
}
}