Skip to content

Commit 1f6d38f

Browse files
liachasotona
authored andcommittedMay 3, 2024
8294978: Convert 5 test/jdk/jdk/jfr tests from ASM library to Classfile API
Reviewed-by: asotona
1 parent c60474b commit 1f6d38f

File tree

5 files changed

+176
-211
lines changed

5 files changed

+176
-211
lines changed
 

‎test/jdk/jdk/jfr/event/compiler/TestCompilerInlining.java

+67-61
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -23,7 +23,6 @@
2323

2424
package jdk.jfr.event.compiler;
2525

26-
import jdk.internal.org.objectweb.asm.*;
2726
import jdk.jfr.Recording;
2827
import jdk.jfr.consumer.RecordedEvent;
2928
import jdk.jfr.consumer.RecordedMethod;
@@ -35,13 +34,24 @@
3534
import jdk.test.whitebox.WhiteBox;
3635

3736
import java.io.IOException;
37+
import java.lang.classfile.ClassModel;
38+
import java.lang.classfile.ClassFile;
39+
import java.lang.classfile.Instruction;
40+
import java.lang.classfile.instruction.InvokeInstruction;
41+
import java.lang.constant.ClassDesc;
42+
import java.lang.constant.MethodTypeDesc;
3843
import java.lang.reflect.Constructor;
3944
import java.lang.reflect.Executable;
4045
import java.lang.reflect.Method;
4146
import java.util.*;
4247
import java.util.stream.IntStream;
48+
import java.util.stream.Stream;
4349

44-
/**
50+
import static java.lang.constant.ConstantDescs.CD_Object;
51+
import static java.lang.constant.ConstantDescs.CD_void;
52+
import static java.lang.constant.ConstantDescs.INIT_NAME;
53+
54+
/*
4555
* @test CompilerInliningTest
4656
* @bug 8073607
4757
* @key jfr
@@ -50,8 +60,8 @@
5060
*
5161
* @requires vm.opt.Inline == true | vm.opt.Inline == null
5262
* @library /test/lib
53-
* @modules java.base/jdk.internal.org.objectweb.asm
54-
* jdk.jfr
63+
* @modules jdk.jfr
64+
* @enablePreview
5565
*
5666
* @build jdk.test.whitebox.WhiteBox
5767
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
@@ -64,7 +74,7 @@ public class TestCompilerInlining {
6474
private static final int LEVEL_SIMPLE = 1;
6575
private static final int LEVEL_FULL_OPTIMIZATION = 4;
6676
private static final Executable ENTRY_POINT = getConstructor(TestCase.class);
67-
private static final String TEST_CASE_CLASS_NAME = TestCase.class.getName().replace('.', '/');
77+
private static final ClassDesc CD_TestCase = TestCase.class.describeConstable().orElseThrow();
6878

6979
public static void main(String[] args) throws Exception {
7080
InlineCalls inlineCalls = new InlineCalls(TestCase.class);
@@ -100,8 +110,8 @@ private static void testLevel(Map<Call, Boolean> expectedResult, int level) thro
100110
MethodDesc caller = methodToMethodDesc(callerObject);
101111
MethodDesc callee = ciMethodToMethodDesc(calleeObject);
102112
// only TestCase.* -> TestCase.* OR TestCase.* -> Object.<init> are tested/filtered
103-
if (caller.className.equals(TEST_CASE_CLASS_NAME) && (callee.className.equals(TEST_CASE_CLASS_NAME)
104-
|| (callee.className.equals("java/lang/Object") && callee.methodName.equals("<init>")))) {
113+
if (caller.className.equals(CD_TestCase) && (callee.className.equals(CD_TestCase)
114+
|| (callee.className.equals(CD_Object) && callee.methodName.equals(INIT_NAME)))) {
105115
System.out.println(event);
106116
boolean succeeded = (boolean) event.getValue("succeeded");
107117
int bci = Events.assertField(event, "bci").atLeast(0).getValue();
@@ -132,17 +142,17 @@ private static int[] determineAvailableLevels() {
132142
}
133143

134144
private static MethodDesc methodToMethodDesc(RecordedMethod method) {
135-
String internalClassName = method.getType().getName().replace('.', '/');
145+
ClassDesc classDesc = ClassDesc.of(method.getType().getName());
136146
String methodName = method.getValue("name");
137-
String methodDescriptor = method.getValue("descriptor");
138-
return new MethodDesc(internalClassName, methodName, methodDescriptor);
147+
MethodTypeDesc methodDescriptor = MethodTypeDesc.ofDescriptor(method.getValue("descriptor"));
148+
return new MethodDesc(classDesc, methodName, methodDescriptor);
139149
}
140150

141151
private static MethodDesc ciMethodToMethodDesc(RecordedObject ciMethod) {
142-
String internalClassName = ciMethod.getValue("type");
152+
ClassDesc classDesc = ClassDesc.ofInternalName(ciMethod.getValue("type"));
143153
String methodName = ciMethod.getValue("name");
144-
String methodDescriptor = ciMethod.getValue("descriptor");
145-
return new MethodDesc(internalClassName, methodName, methodDescriptor);
154+
MethodTypeDesc methodDescriptor = MethodTypeDesc.ofDescriptor(ciMethod.getValue("descriptor"));
155+
return new MethodDesc(classDesc, methodName, methodDescriptor);
146156
}
147157

148158
private static Method getMethod(Class<?> aClass, String name, Class<?>... params) {
@@ -246,35 +256,33 @@ public String toString() {
246256
* data structure for method description
247257
*/
248258
class MethodDesc {
249-
public final String className;
259+
public final ClassDesc className;
250260
public final String methodName;
251-
public final String descriptor;
252-
253-
public MethodDesc(Class<?> aClass, String methodName, String descriptor) {
254-
this(aClass.getName().replace('.', '/'), methodName, descriptor);
255-
}
261+
public final MethodTypeDesc descriptor;
256262

257-
public MethodDesc(String className, String methodName, String descriptor) {
263+
public MethodDesc(ClassDesc className, String methodName, MethodTypeDesc descriptor) {
258264
Objects.requireNonNull(className);
259265
Objects.requireNonNull(methodName);
260266
Objects.requireNonNull(descriptor);
261-
this.className = className.replace('.', '/');
267+
this.className = className;
262268
this.methodName = methodName;
263269
this.descriptor = descriptor;
264270
}
265271

266272
public MethodDesc(Executable executable) {
267-
Class<?> aClass = executable.getDeclaringClass();
268-
className = Type.getInternalName(aClass).replace('.', '/');
273+
className = executable.getDeclaringClass().describeConstable().orElseThrow();
274+
ClassDesc retType;
269275

270-
if (executable instanceof Constructor<?>) {
271-
methodName = "<init>";
272-
descriptor = Type.getConstructorDescriptor((Constructor<?>) executable);
273-
} else {
276+
if (executable instanceof Method method) {
274277
methodName = executable.getName();
275-
descriptor = Type.getMethodDescriptor((Method) executable);
278+
retType = method.getReturnType().describeConstable().orElseThrow();
279+
} else {
280+
methodName = INIT_NAME;
281+
retType = CD_void;
276282
}
277283

284+
descriptor = MethodTypeDesc.of(retType, Stream.of(executable.getParameterTypes())
285+
.map(c -> c.describeConstable().orElseThrow()).toArray(ClassDesc[]::new));
278286
}
279287

280288
@Override
@@ -361,43 +369,41 @@ public void forceInline(Executable executable) {
361369

362370
private static Collection<Call> getCalls(Class<?> aClass) {
363371
List<Call> calls = new ArrayList<>();
364-
ClassWriter cw;
365-
ClassReader cr;
372+
ClassModel clm;
366373
try {
367-
cr = new ClassReader(aClass.getName());
374+
var stream = ClassLoader.getSystemResourceAsStream(aClass.getName()
375+
.replace('.', '/') + ".class");
376+
if (stream == null) {
377+
throw new IOException("Cannot find class file for " + aClass.getName());
378+
}
379+
clm = ClassFile.of().parse(stream.readAllBytes());
368380
} catch (IOException e) {
369381
throw new Error("TESTBUG : unexpected IOE during class reading", e);
370382
}
371-
cw = new ClassWriter(cr, 0);
372-
ClassVisitor cv = new ClassVisitor(Opcodes.ASM7, cw) {
373-
@Override
374-
public MethodVisitor visitMethod(int access, String name, String desc, String descriptor, String[] exceptions) {
375-
System.out.println("Method: " +name);
376-
MethodVisitor mv = super.visitMethod(access, name, desc, descriptor, exceptions);
377-
return new CallTracer(aClass, name, desc, mv, calls);
378-
}
379-
};
380-
cr.accept(cv, 0);
381383

384+
clm.methods().forEach(mm -> {
385+
System.out.println("Method: " + mm.methodName().stringValue());
386+
mm.code().ifPresent(com -> {
387+
MethodDesc caller = new MethodDesc(
388+
clm.thisClass().asSymbol(),
389+
mm.methodName().stringValue(),
390+
mm.methodTypeSymbol()
391+
);
392+
int offset = 0;
393+
for (var ce : com.elements()) {
394+
if (ce instanceof Instruction ins) {
395+
if (ins instanceof InvokeInstruction inv) {
396+
calls.add(new Call(caller, new MethodDesc(
397+
inv.owner().asSymbol(),
398+
inv.name().stringValue(),
399+
inv.typeSymbol()
400+
), offset));
401+
}
402+
offset += ins.sizeInBytes();
403+
}
404+
}
405+
});
406+
});
382407
return calls;
383408
}
384-
385-
private static class CallTracer extends MethodVisitor {
386-
private final MethodDesc caller;
387-
private Collection<Call> calls;
388-
389-
public CallTracer(Class<?> aClass, String name, String desc, MethodVisitor mv, Collection<Call> calls) {
390-
super(Opcodes.ASM7, mv);
391-
caller = new MethodDesc(aClass.getName(), name, desc);
392-
this.calls = calls;
393-
}
394-
395-
@Override
396-
public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
397-
Label label = new Label();
398-
visitLabel(label);
399-
super.visitMethodInsn(opcode, owner, name, desc, itf);
400-
calls.add(new Call(caller, new MethodDesc(owner, name, desc), label.getOffset()));
401-
}
402-
}
403409
}

‎test/jdk/jdk/jfr/event/io/TestInstrumentation.java

+72-85
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -23,6 +23,14 @@
2323

2424
package jdk.jfr.event.io;
2525

26+
import java.lang.classfile.ClassFile;
27+
import java.lang.classfile.CodeBuilder;
28+
import java.lang.classfile.CodeElement;
29+
import java.lang.classfile.CodeTransform;
30+
import java.lang.classfile.MethodModel;
31+
import java.lang.classfile.MethodTransform;
32+
import java.lang.constant.ClassDesc;
33+
import java.lang.constant.MethodTypeDesc;
2634
import java.util.Arrays;
2735
import java.util.Set;
2836
import java.util.HashSet;
@@ -31,27 +39,27 @@
3139
import java.lang.instrument.ClassFileTransformer;
3240
import java.lang.instrument.Instrumentation;
3341
import java.lang.instrument.IllegalClassFormatException;
42+
import java.util.stream.Collectors;
43+
import java.util.stream.Stream;
3444

35-
import jdk.internal.org.objectweb.asm.ClassReader;
36-
import jdk.internal.org.objectweb.asm.ClassVisitor;
37-
import jdk.internal.org.objectweb.asm.MethodVisitor;
38-
import jdk.internal.org.objectweb.asm.ClassWriter;
39-
import jdk.internal.org.objectweb.asm.Opcodes;
40-
import jdk.internal.org.objectweb.asm.Type;
4145
import jdk.test.lib.process.OutputAnalyzer;
4246
import jdk.test.lib.process.ProcessTools;
4347

48+
import static java.lang.constant.ConstantDescs.CD_String;
49+
import static java.lang.constant.ConstantDescs.CD_void;
50+
4451
/*
4552
* @test
4653
* @summary Test that will instrument the same classes that JFR will also instrument.
4754
* @key jfr
4855
* @requires vm.hasJFR
4956
*
5057
* @library /test/lib /test/jdk
51-
* @modules java.base/jdk.internal.org.objectweb.asm
52-
* java.instrument
58+
* @modules java.instrument
5359
* jdk.jartool/sun.tools.jar
5460
* jdk.jfr
61+
* @enablePreview
62+
* @comment update --enable-preview in launchTest() too
5563
*
5664
* @run main/othervm jdk.jfr.event.io.TestInstrumentation
5765
*/
@@ -90,7 +98,7 @@ public class TestInstrumentation implements ClassFileTransformer {
9098
private static TestInstrumentation testTransformer = null;
9199

92100
// All methods that will be instrumented.
93-
private static final String[] instrMethodKeys = {
101+
private static final Set<MethodKey> instrMethodKeys = Stream.of(
94102
"java/io/RandomAccessFile::seek::(J)V",
95103
"java/io/RandomAccessFile::read::()I",
96104
"java/io/RandomAccessFile::read::([B)I",
@@ -116,31 +124,24 @@ public class TestInstrumentation implements ClassFileTransformer {
116124
"java/nio/channels/SocketChannel::read::([Ljava/nio/ByteBuffer;)J",
117125
"java/nio/channels/SocketChannel::write::([Ljava/nio/ByteBuffer;)J",
118126
"sun/nio/ch/FileChannelImpl::read::(Ljava/nio/ByteBuffer;)I",
119-
"sun/nio/ch/FileChannelImpl::write::(Ljava/nio/ByteBuffer;)I",
120-
};
121-
122-
private static String getInstrMethodKey(String className, String methodName, String signature) {
123-
// This key is used to identify a class and method. It is sent to callback(key)
124-
return className + "::" + methodName + "::" + signature;
125-
}
126-
127-
private static String getClassFromMethodKey(String methodKey) {
128-
return methodKey.split("::")[0];
129-
}
127+
"sun/nio/ch/FileChannelImpl::write::(Ljava/nio/ByteBuffer;)I"
128+
).map(s -> {
129+
String[] a = s.split("::");
130+
return new MethodKey(a[0], a[1], a[2]);
131+
}).collect(Collectors.toUnmodifiableSet());
130132

131133
// Set of all classes targeted for instrumentation.
132-
private static Set<String> instrClassesTarget = null;
134+
private static Set<ClassDesc> instrClassesTarget = null;
133135

134136
// Set of all classes where instrumentation has been completed.
135-
private static Set<String> instrClassesDone = null;
137+
private static Set<ClassDesc> instrClassesDone = null;
136138

137139
static {
138140
// Split class names from InstrMethodKeys.
139-
instrClassesTarget = new HashSet<String>();
140-
instrClassesDone = new HashSet<String>();
141-
for (String s : instrMethodKeys) {
142-
String className = getClassFromMethodKey(s);
143-
instrClassesTarget.add(className);
141+
instrClassesTarget = new HashSet<>();
142+
instrClassesDone = new HashSet<>();
143+
for (MethodKey key : instrMethodKeys) {
144+
instrClassesTarget.add(key.owner());
144145
}
145146
}
146147

@@ -164,9 +165,10 @@ public static void main(String[] args) throws Throwable {
164165
runAllTests(TransformStatus.Transformed);
165166

166167
// Retransform all classes and then repeat tests
167-
Set<Class<?>> classes = new HashSet<Class<?>>();
168-
for (String className : instrClassesTarget) {
169-
Class<?> clazz = Class.forName(className.replaceAll("/", "."));
168+
Set<Class<?>> classes = new HashSet<>();
169+
for (ClassDesc className : instrClassesTarget) {
170+
var desc = className.descriptorString();
171+
Class<?> clazz = Class.forName(desc.substring(1, desc.length() - 1).replace('/', '.'));
170172
classes.add(clazz);
171173
log("Will retransform " + clazz.getName());
172174
}
@@ -197,10 +199,10 @@ public static void runAllTests(TransformStatus status) throws Throwable {
197199

198200
// Verify that all expected callbacks have been called.
199201
Set<String> callbackKeys = InstrumentationCallback.getKeysCopy();
200-
for (String key : instrMethodKeys) {
201-
boolean gotCallback = callbackKeys.contains(key);
202+
for (MethodKey key : instrMethodKeys) {
203+
boolean gotCallback = callbackKeys.contains(key.toString());
202204
boolean expectsCallback = isClassInstrumented(status, key);
203-
String msg = String.format("key:%s, expects:%b", key, expectsCallback);
205+
String msg = String.format("status:%s, key:%s, expects:%b", status, key, expectsCallback);
204206
if (gotCallback != expectsCallback) {
205207
throw new Exception("Wrong callback() for " + msg);
206208
} else {
@@ -214,14 +216,14 @@ public static void runAllTests(TransformStatus status) throws Throwable {
214216
}
215217
}
216218

217-
private static boolean isClassInstrumented(TransformStatus status, String key) throws Throwable {
219+
private static boolean isClassInstrumented(TransformStatus status, MethodKey key) throws Throwable {
218220
switch (status) {
219221
case Retransformed:
220222
return true;
221223
case Removed:
222224
return false;
223225
case Transformed:
224-
String className = getClassFromMethodKey(key);
226+
var className = key.owner();
225227
return instrClassesDone.contains(className);
226228
}
227229
throw new Exception("Test error: Unknown TransformStatus: " + status);
@@ -279,7 +281,7 @@ private static void launchTest() throws Throwable {
279281

280282
String[] args = {
281283
"-Xbootclasspath/a:" + testClassDir + "InstrumentationCallback.jar",
282-
"--add-exports", "java.base/jdk.internal.org.objectweb.asm=ALL-UNNAMED",
284+
"--enable-preview",
283285
"-classpath", classpath,
284286
"-javaagent:" + testClassDir + "TestInstrumentation.jar",
285287
"jdk.jfr.event.io.TestInstrumentation$TestMain" };
@@ -305,67 +307,52 @@ public byte[] transform(
305307
ClassLoader classLoader, String className, Class<?> classBeingRedefined,
306308
ProtectionDomain pd, byte[] bytes) throws IllegalClassFormatException {
307309
// Check if this class should be instrumented.
308-
if (!instrClassesTarget.contains(className)) {
310+
ClassDesc target = ClassDesc.ofInternalName(className);
311+
if (!instrClassesTarget.contains(target)) {
309312
return null;
310313
}
311314

312315
boolean isRedefinition = classBeingRedefined != null;
313316
log("instrument class(" + className + ") " + (isRedefinition ? "redef" : "load"));
314317

315-
ClassReader reader = new ClassReader(bytes);
316-
ClassWriter writer = new ClassWriter(
317-
reader, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
318-
CallbackClassVisitor classVisitor = new CallbackClassVisitor(writer);
319-
reader.accept(classVisitor, 0);
320-
instrClassesDone.add(className);
321-
return writer.toByteArray();
322-
}
323-
324-
private static class CallbackClassVisitor extends ClassVisitor {
325-
private String className;
326-
327-
public CallbackClassVisitor(ClassVisitor cv) {
328-
super(Opcodes.ASM7, cv);
329-
}
330-
331-
@Override
332-
public void visit(
333-
int version, int access, String name, String signature,
334-
String superName, String[] interfaces) {
335-
cv.visit(version, access, name, signature, superName, interfaces);
336-
className = name;
337-
}
318+
instrClassesDone.add(target);
319+
var cf = ClassFile.of();
320+
return cf.transform(cf.parse(bytes), (clb, ce) -> {
321+
MethodKey key;
322+
if (ce instanceof MethodModel mm && instrMethodKeys.contains(key = new MethodKey(
323+
target, mm.methodName().stringValue(), mm.methodTypeSymbol()))) {
324+
clb.transformMethod(mm, MethodTransform.transformingCode(new CodeTransform() {
325+
private static final MethodTypeDesc MTD_callback = MethodTypeDesc.of(CD_void, CD_String);
326+
private static final ClassDesc CD_InstrumentationCallback = InstrumentationCallback.class
327+
.describeConstable().orElseThrow();
328+
329+
@Override
330+
public void atStart(CodeBuilder cb) {
331+
cb.loadConstant(key.toString());
332+
cb.invokestatic(CD_InstrumentationCallback, "callback", MTD_callback);
333+
log("instrumented " + key);
334+
}
338335

339-
@Override
340-
public MethodVisitor visitMethod(
341-
int access, String methodName, String desc, String signature, String[] exceptions) {
342-
String methodKey = getInstrMethodKey(className, methodName, desc);
343-
boolean isInstrumentedMethod = Arrays.asList(instrMethodKeys).contains(methodKey);
344-
MethodVisitor mv = cv.visitMethod(access, methodName, desc, signature, exceptions);
345-
if (isInstrumentedMethod && mv != null) {
346-
mv = new CallbackMethodVisitor(mv, methodKey);
347-
log("instrumented " + methodKey);
336+
@Override
337+
public void accept(CodeBuilder cb, CodeElement ce) {
338+
cb.with(ce);
339+
}
340+
}));
341+
} else {
342+
clb.with(ce);
348343
}
349-
return mv;
350-
}
344+
});
351345
}
352346

353-
public static class CallbackMethodVisitor extends MethodVisitor {
354-
private String logMessage;
355-
356-
public CallbackMethodVisitor(MethodVisitor mv, String logMessage) {
357-
super(Opcodes.ASM7, mv);
358-
this.logMessage = logMessage;
347+
public record MethodKey(ClassDesc owner, String name, MethodTypeDesc desc) {
348+
public MethodKey(String className, String methodName, String signature) {
349+
this(ClassDesc.ofInternalName(className), methodName, MethodTypeDesc.ofDescriptor(signature));
359350
}
360351

361352
@Override
362-
public void visitCode() {
363-
mv.visitCode();
364-
String methodDescr = Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(String.class));
365-
String className = InstrumentationCallback.class.getName().replace('.', '/');
366-
mv.visitLdcInsn(logMessage);
367-
mv.visitMethodInsn(Opcodes.INVOKESTATIC, className, "callback", methodDescr);
353+
public String toString() {
354+
var ownerDesc = owner.descriptorString();
355+
return ownerDesc.substring(1, ownerDesc.length() - 1) + "::" + name + "::" + desc.descriptorString();
368356
}
369357
}
370-
371358
}
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -22,34 +22,37 @@
2222
*/
2323
package jdk.jfr.javaagent;
2424

25+
import java.lang.classfile.ClassFile;
26+
import java.lang.classfile.CodeBuilder;
27+
import java.lang.classfile.CodeElement;
28+
import java.lang.classfile.CodeTransform;
29+
import java.lang.classfile.MethodModel;
30+
import java.lang.classfile.MethodTransform;
31+
import java.lang.constant.ClassDesc;
2532
import java.lang.instrument.ClassFileTransformer;
2633
import java.lang.instrument.IllegalClassFormatException;
2734
import java.lang.instrument.Instrumentation;
2835
import java.nio.file.Path;
2936
import java.nio.file.Paths;
3037
import java.security.ProtectionDomain;
3138

32-
import jdk.internal.org.objectweb.asm.ClassReader;
33-
import jdk.internal.org.objectweb.asm.ClassVisitor;
34-
import jdk.internal.org.objectweb.asm.ClassWriter;
35-
import jdk.internal.org.objectweb.asm.MethodVisitor;
36-
import jdk.internal.org.objectweb.asm.Opcodes;
37-
import jdk.internal.org.objectweb.asm.Type;
38-
3939
import jdk.jfr.Event;
4040
import jdk.jfr.Recording;
4141
import jdk.jfr.consumer.RecordingFile;
4242
import jdk.test.lib.Asserts;
4343

44+
import static java.lang.constant.ConstantDescs.INIT_NAME;
45+
import static java.lang.constant.ConstantDescs.MTD_void;
46+
4447
/*
4548
* @test
4649
* @summary Verify that a subclass of the JFR Event class
4750
* can be successfully instrumented.
4851
* @key jfr
4952
* @requires vm.hasJFR
5053
* @library /test/lib
51-
* @modules java.base/jdk.internal.org.objectweb.asm
52-
* jdk.jartool/sun.tools.jar
54+
* @modules jdk.jartool/sun.tools.jar
55+
* @enablePreview
5356
* @build jdk.jfr.javaagent.InstrumentationEventCallback
5457
* jdk.jfr.javaagent.TestEventInstrumentation
5558
* @run driver jdk.test.lib.util.JavaAgentBuilder
@@ -99,6 +102,9 @@ public static void premain(String args, Instrumentation inst) throws Exception {
99102
}
100103

101104
static class Transformer implements ClassFileTransformer {
105+
private static final ClassDesc CD_InstrumentationEventCallback = InstrumentationEventCallback.class
106+
.describeConstable().orElseThrow();
107+
102108
public byte[] transform(ClassLoader classLoader, String className,
103109
Class<?> classBeingRedefined, ProtectionDomain pd,
104110
byte[] bytes) throws IllegalClassFormatException {
@@ -109,63 +115,31 @@ public byte[] transform(ClassLoader classLoader, String className,
109115
return null;
110116
}
111117

112-
ClassReader reader = new ClassReader(bytes);
113-
ClassWriter writer = new ClassWriter(reader, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
114-
CallbackClassVisitor classVisitor = new CallbackClassVisitor(writer);
115-
116-
// visit the reader's class by the classVisitor
117-
reader.accept(classVisitor, 0);
118-
result = writer.toByteArray();
118+
var cf = ClassFile.of();
119+
result = cf.transform(cf.parse(bytes), (clb, ce) -> {
120+
if (ce instanceof MethodModel mm && mm.methodName().equalsString(INIT_NAME)) {
121+
clb.transformMethod(mm, MethodTransform.transformingCode(new CodeTransform() {
122+
@Override
123+
public void atStart(CodeBuilder cb) {
124+
cb.invokestatic(CD_InstrumentationEventCallback, "callback", MTD_void);
125+
log("instrumented <init> in class " + className);
126+
}
127+
128+
@Override
129+
public void accept(CodeBuilder cb, CodeElement ce) {
130+
cb.accept(ce);
131+
}
132+
}));
133+
} else {
134+
clb.with(ce);
135+
}
136+
});
119137
} catch (Exception e) {
120138
log("Exception occured in transform(): " + e.getMessage());
121139
e.printStackTrace(System.out);
122140
transformException = e;
123141
}
124142
return result;
125143
}
126-
127-
private static class CallbackClassVisitor extends ClassVisitor {
128-
private String className;
129-
130-
public CallbackClassVisitor(ClassVisitor cv) {
131-
super(Opcodes.ASM7, cv);
132-
}
133-
134-
@Override
135-
public void visit(int version, int access, String name, String signature,
136-
String superName, String[] interfaces) {
137-
// visit the header of the class - called per class header visit
138-
cv.visit(version, access, name, signature, superName, interfaces);
139-
className = name;
140-
}
141-
142-
@Override
143-
public MethodVisitor visitMethod(
144-
int access, String methodName, String desc,
145-
String signature, String[] exceptions) {
146-
// called for each method in a class
147-
boolean isInstrumentedMethod = methodName.contains("<init>");
148-
MethodVisitor mv = cv.visitMethod(access, methodName, desc, signature, exceptions);
149-
if (isInstrumentedMethod) {
150-
mv = new CallbackMethodVisitor(mv);
151-
log("instrumented <init> in class " + className);
152-
}
153-
return mv;
154-
}
155-
}
156-
157-
public static class CallbackMethodVisitor extends MethodVisitor {
158-
public CallbackMethodVisitor(MethodVisitor mv) {
159-
super(Opcodes.ASM7, mv);
160-
}
161-
162-
@Override
163-
public void visitCode() {
164-
mv.visitCode();
165-
String methodDescr = Type.getMethodDescriptor(Type.VOID_TYPE, Type.VOID_TYPE);
166-
String className = InstrumentationEventCallback.class.getName().replace('.', '/');
167-
mv.visitMethodInsn(Opcodes.INVOKESTATIC, className, "callback", "()V", false);
168-
}
169-
}
170144
}
171145
}

‎test/jdk/jdk/jfr/jvm/TestLargeJavaEvent512k.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -47,7 +47,6 @@
4747
* @requires vm.hasJFR
4848
* @library /test/lib
4949
* @modules jdk.jfr/jdk.jfr.internal
50-
* java.base/jdk.internal.org.objectweb.asm
5150
* @run main/othervm jdk.jfr.jvm.TestLargeJavaEvent512k
5251
*/
5352
public class TestLargeJavaEvent512k {

‎test/jdk/jdk/jfr/jvm/TestLargeJavaEvent64k.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -47,7 +47,6 @@
4747
* @requires vm.hasJFR
4848
* @library /test/lib
4949
* @modules jdk.jfr/jdk.jfr.internal
50-
* java.base/jdk.internal.org.objectweb.asm
5150
* @run main/othervm jdk.jfr.jvm.TestLargeJavaEvent64k
5251
*/
5352
public class TestLargeJavaEvent64k {

0 commit comments

Comments
 (0)
Please sign in to comment.