Skip to content
Merged
Show file tree
Hide file tree
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
Expand Up @@ -1194,22 +1194,21 @@ private static boolean methodTypeFromDescriptor(JNIEnvironment jni, JNIObjectHan
return true;
}

/**
* This method should be intercepted when we are predefining a lambda class. This is the only
* spot in the lambda-class creation pipeline where we can get lambda-class bytecode so the
* class can be predefined. We do not want to predefine all lambda classes, but only the ones
* that are actually created at runtime, so we have a method that checks wheter the lambda
* should be predefined or not.
*/
private static boolean onMethodHandleClassFileInit(JNIEnvironment jni, JNIObjectHandle thread, @SuppressWarnings("unused") Breakpoint bp, InterceptedState state) {
private record LambdaClassNameAndBytecode(String lambdaClassName, byte[] lambdaClassBytecode) {
}

private static LambdaClassNameAndBytecode getLambdaClassNameAndBytecodeFromThread(JNIEnvironment jni, JNIObjectHandle thread, int bytecodeArgumentIndex) {
LambdaClassNameAndBytecode emptyLambdaClassNameAndBytecode = new LambdaClassNameAndBytecode(null, null);

String className = Support.fromJniString(jni, getObjectArgument(thread, 1));
assert className != null;

if (LambdaUtils.isLambdaClassName(className)) {
if (shouldIgnoreLambdaClassForPredefinition(jni)) {
return true;
return emptyLambdaClassNameAndBytecode;
}

JNIObjectHandle bytesArray = getObjectArgument(thread, 3);
JNIObjectHandle bytesArray = getObjectArgument(thread, bytecodeArgumentIndex);
int length = jniFunctions().getGetArrayLength().invoke(jni, bytesArray);
byte[] data = new byte[length];

Expand All @@ -1222,9 +1221,29 @@ private static boolean onMethodHandleClassFileInit(JNIEnvironment jni, JNIObject
}

className += Digest.digest(data);
tracer.traceCall("classloading", "onMethodHandleClassFileInit", null, null, null, null, state.getFullStackTraceOrNull(), className, data);
return new LambdaClassNameAndBytecode(className, data);
}
}

return emptyLambdaClassNameAndBytecode;
}

/**
* This method should be intercepted on JDK 24 or later when we are predefining a lambda class.
* We do not want to predefine all lambda classes, but only the ones that are actually created
* at runtime, so we have a method that checks whether the lambda should be predefined or not.
*/
private static boolean makeHiddenClassDefiner(JNIEnvironment jni, JNIObjectHandle thread, @SuppressWarnings("unused") Breakpoint bp, InterceptedState state) {
LambdaClassNameAndBytecode lambdaClassNameAndBytecode = getLambdaClassNameAndBytecodeFromThread(jni, thread, 2);
return lambdaPredefinition(state, lambdaClassNameAndBytecode.lambdaClassName(), lambdaClassNameAndBytecode.lambdaClassBytecode());
}

private static boolean lambdaPredefinition(InterceptedState state, String className, byte[] data) {
if (className == null) {
return false;
}

tracer.traceCall("classloading", "lambdaPredefinition", null, null, null, null, state.getFullStackTraceOrNull(), className, data);
return true;
}

Expand Down Expand Up @@ -1923,7 +1942,8 @@ private static boolean allocateInstance(JNIEnvironment jni, JNIObjectHandle thre
};

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

private static BreakpointSpecification brk(String className, String methodName, String signature, BreakpointHandler handler) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ void processEntry(EconomicMap<String, Object> entry, ConfigurationSet configurat

String function = (String) entry.get("function");
List<?> args = (List<?>) entry.get("args");
if ("onClassFileLoadHook".equals(function) || "onMethodHandleClassFileInit".equals(function)) {
if ("onClassFileLoadHook".equals(function) || "lambdaPredefinition".equals(function)) {
expectSize(args, 2);
String nameInfo = (String) args.get(0);
byte[] classData = asBinary(args.get(1));
Expand Down