Skip to content

Commit c06c144

Browse files
committed
Adapt NI agent for the new JKD release
1 parent f8a5bef commit c06c144

File tree

2 files changed

+47
-13
lines changed

2 files changed

+47
-13
lines changed

substratevm/src/com.oracle.svm.agent/src/com/oracle/svm/agent/BreakpointInterceptor.java

Lines changed: 46 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1194,22 +1194,21 @@ private static boolean methodTypeFromDescriptor(JNIEnvironment jni, JNIObjectHan
11941194
return true;
11951195
}
11961196

1197-
/**
1198-
* This method should be intercepted when we are predefining a lambda class. This is the only
1199-
* spot in the lambda-class creation pipeline where we can get lambda-class bytecode so the
1200-
* class can be predefined. We do not want to predefine all lambda classes, but only the ones
1201-
* that are actually created at runtime, so we have a method that checks wheter the lambda
1202-
* should be predefined or not.
1203-
*/
1204-
private static boolean onMethodHandleClassFileInit(JNIEnvironment jni, JNIObjectHandle thread, @SuppressWarnings("unused") Breakpoint bp, InterceptedState state) {
1197+
private record LambdaClassNameAndBytecode(String lambdaClassName, byte[] lambdaClassBytecode) {
1198+
}
1199+
1200+
private static LambdaClassNameAndBytecode getLambdaClassNameAndBytecodeFromThread(JNIEnvironment jni, JNIObjectHandle thread, int bytecodeArgumentIndex) {
1201+
LambdaClassNameAndBytecode emptyLambdaClassNameAndBytecode = new LambdaClassNameAndBytecode(null, null);
1202+
12051203
String className = Support.fromJniString(jni, getObjectArgument(thread, 1));
1204+
assert className != null;
12061205

12071206
if (LambdaUtils.isLambdaClassName(className)) {
12081207
if (shouldIgnoreLambdaClassForPredefinition(jni)) {
1209-
return true;
1208+
return emptyLambdaClassNameAndBytecode;
12101209
}
12111210

1212-
JNIObjectHandle bytesArray = getObjectArgument(thread, 3);
1211+
JNIObjectHandle bytesArray = getObjectArgument(thread, bytecodeArgumentIndex);
12131212
int length = jniFunctions().getGetArrayLength().invoke(jni, bytesArray);
12141213
byte[] data = new byte[length];
12151214

@@ -1222,9 +1221,41 @@ private static boolean onMethodHandleClassFileInit(JNIEnvironment jni, JNIObject
12221221
}
12231222

12241223
className += Digest.digest(data);
1225-
tracer.traceCall("classloading", "onMethodHandleClassFileInit", null, null, null, null, state.getFullStackTraceOrNull(), className, data);
1224+
return new LambdaClassNameAndBytecode(className, data);
12261225
}
12271226
}
1227+
1228+
return emptyLambdaClassNameAndBytecode;
1229+
}
1230+
1231+
/**
1232+
* This method should be intercepted before JDK 24 when we are predefining a lambda class. This
1233+
* is the only spot in the lambda-class creation pipeline where we can get lambda-class bytecode
1234+
* so the class can be predefined. We do not want to predefine all lambda classes, but only the
1235+
* ones that are actually created at runtime, so we have a method that checks whether the lambda
1236+
* should be predefined or not.
1237+
*/
1238+
private static boolean onMethodHandleClassFileInit(JNIEnvironment jni, JNIObjectHandle thread, @SuppressWarnings("unused") Breakpoint bp, InterceptedState state) {
1239+
LambdaClassNameAndBytecode lambdaClassNameAndBytecode = getLambdaClassNameAndBytecodeFromThread(jni, thread, 3);
1240+
return lambdaPredefinition(state, lambdaClassNameAndBytecode.lambdaClassName(), lambdaClassNameAndBytecode.lambdaClassBytecode());
1241+
}
1242+
1243+
/**
1244+
* This method should be intercepted on JDK 24 or later when we are predefining a lambda class.
1245+
* We do not want to predefine all lambda classes, but only the ones that are actually created
1246+
* at runtime, so we have a method that checks whether the lambda should be predefined or not.
1247+
*/
1248+
private static boolean makeHiddenClassDefiner(JNIEnvironment jni, JNIObjectHandle thread, @SuppressWarnings("unused") Breakpoint bp, InterceptedState state) {
1249+
LambdaClassNameAndBytecode lambdaClassNameAndBytecode = getLambdaClassNameAndBytecodeFromThread(jni, thread, 2);
1250+
return lambdaPredefinition(state, lambdaClassNameAndBytecode.lambdaClassName(), lambdaClassNameAndBytecode.lambdaClassBytecode());
1251+
}
1252+
1253+
private static boolean lambdaPredefinition(InterceptedState state, String className, byte[] data) {
1254+
if (className == null) {
1255+
return false;
1256+
}
1257+
1258+
tracer.traceCall("classloading", "lambdaPredefinition", null, null, null, null, state.getFullStackTraceOrNull(), className, data);
12281259
return true;
12291260
}
12301261

@@ -1923,7 +1954,10 @@ private static boolean allocateInstance(JNIEnvironment jni, JNIObjectHandle thre
19231954
};
19241955

19251956
private static final BreakpointSpecification[] CLASS_PREDEFINITION_BREAKPOINT_SPECIFICATIONS = {
1926-
optionalBrk("java/lang/invoke/MethodHandles$Lookup$ClassFile", "<init>", "(Ljava/lang/String;I[B)V", BreakpointInterceptor::onMethodHandleClassFileInit),
1957+
optionalBrk("java/lang/invoke/MethodHandles$Lookup$ClassFile", "<init>", "(Ljava/lang/String;I[B)V",
1958+
BreakpointInterceptor::onMethodHandleClassFileInit),
1959+
optionalBrk("java/lang/invoke/MethodHandles$Lookup", "makeHiddenClassDefiner",
1960+
"(Ljava/lang/String;[BZLjdk/internal/util/ClassFileDumper;I)Ljava/lang/invoke/MethodHandles$Lookup$ClassDefiner;", BreakpointInterceptor::makeHiddenClassDefiner)
19271961
};
19281962

19291963
private static BreakpointSpecification brk(String className, String methodName, String signature, BreakpointHandler handler) {

substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/trace/ClassLoadingProcessor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ void processEntry(EconomicMap<String, Object> entry, ConfigurationSet configurat
4242

4343
String function = (String) entry.get("function");
4444
List<?> args = (List<?>) entry.get("args");
45-
if ("onClassFileLoadHook".equals(function) || "onMethodHandleClassFileInit".equals(function)) {
45+
if ("onClassFileLoadHook".equals(function) || "lambdaPredefinition".equals(function)) {
4646
expectSize(args, 2);
4747
String nameInfo = (String) args.get(0);
4848
byte[] classData = asBinary(args.get(1));

0 commit comments

Comments
 (0)