28
28
import static com .oracle .svm .jvmtiagentbase .Support .check ;
29
29
import static com .oracle .svm .jvmtiagentbase .Support .jvmtiFunctions ;
30
30
import static com .oracle .svm .jvmtiagentbase .jvmti .JvmtiEvent .JVMTI_EVENT_CLASS_FILE_LOAD_HOOK ;
31
-
31
+ import static java .lang .classfile .ClassFile .ACC_PUBLIC ;
32
+
33
+ import java .io .Serial ;
34
+ import java .lang .classfile .ClassBuilder ;
35
+ import java .lang .classfile .ClassElement ;
36
+ import java .lang .classfile .ClassFile ;
37
+ import java .lang .classfile .ClassModel ;
38
+ import java .lang .classfile .ClassTransform ;
39
+ import java .lang .classfile .MethodModel ;
40
+ import java .lang .constant .ConstantDescs ;
32
41
import java .util .ArrayList ;
33
42
import java .util .List ;
34
43
import java .util .Map ;
65
74
import com .oracle .svm .jvmtiagentbase .jvmti .JvmtiEventCallbacks ;
66
75
import com .oracle .svm .jvmtiagentbase .jvmti .JvmtiEventMode ;
67
76
import com .oracle .svm .jvmtiagentbase .jvmti .JvmtiInterface ;
68
- import com .oracle .svm .shaded .org .objectweb .asm .ClassReader ;
69
- import com .oracle .svm .shaded .org .objectweb .asm .ClassWriter ;
70
77
71
78
/**
72
79
* JVMTI agent that provides diagnostics information that helps resolve native-image build failures.
@@ -380,25 +387,13 @@ private static void onClassFileLoadHook(@SuppressWarnings("unused") JvmtiEnv jvm
380
387
newClassDataLen .write (newClassDataLength );
381
388
}
382
389
383
- static final int ASM8 = 8 << 16 ;
384
- static final int ASM_TARGET_VERSION = ASM8 ;
385
-
386
390
private byte [] maybeInstrumentClassWithClinit (String clazzName , byte [] clazzData ) {
387
- if (clazzName != null && !advisor .shouldTraceClassInitialization (clazzName .replace ('/' , '.' ))) {
388
- return null ;
389
- }
390
-
391
391
try {
392
- ClassReader reader = new ClassReader (clazzData );
393
- ClassWriter writer = new ClassWriter (reader , 0 );
394
- ClinitGenerationVisitor visitor = new ClinitGenerationVisitor (ASM_TARGET_VERSION , writer );
395
- reader .accept (visitor , 0 );
396
-
397
- if (!visitor .didGeneration ()) {
398
- return null ;
392
+ TracingAdvisor advisor = JvmtiAgentBase .<NativeImageDiagnosticsAgentJNIHandleSet , NativeImageDiagnosticsAgent > singleton ().advisor ;
393
+ if (advisor .shouldTraceClassInitialization (clazzName .replace ("/" , "." ))) {
394
+ return instrumentClassWithClinit (clazzData );
399
395
}
400
-
401
- return writer .toByteArray ();
396
+ return null ;
402
397
} catch (Throwable e ) {
403
398
String targetClazzName = clazzName != null ? clazzName : "<unknown class>" ;
404
399
System .err .println ("[native-image-diagnostics-agent] Failed to instrument class " + targetClazzName + ": " );
@@ -407,6 +402,48 @@ private byte[] maybeInstrumentClassWithClinit(String clazzName, byte[] clazzData
407
402
}
408
403
}
409
404
405
+ /**
406
+ * Instruments the given class data with a synthetic <clinit> method if missing. Returns null if
407
+ * no changes are made, otherwise the modified classfile bytes.
408
+ */
409
+ public byte [] instrumentClassWithClinit (byte [] classData ) {
410
+ class ClinitAlreadyExistsException extends RuntimeException {
411
+ @ Serial private static final long serialVersionUID = 1L ;
412
+ }
413
+ try {
414
+ ClassModel cm = ClassFile .of ().parse (classData );
415
+ return ClassFile .of ().transformClass (cm , new ClassTransform () {
416
+ /**
417
+ * Copies over all elements from the original class.
418
+ */
419
+ @ Override
420
+ public void accept (ClassBuilder clb , ClassElement ce ) {
421
+ if (ce instanceof MethodModel mm && ConstantDescs .CLASS_INIT_NAME .equals ((mm .methodName ().stringValue ()))) {
422
+ // already has a <clinit> method
423
+ throw new ClinitAlreadyExistsException ();
424
+ }
425
+ clb .with (ce );
426
+ }
427
+
428
+ /**
429
+ * Add an empty <clinit> method to the class.
430
+ */
431
+ @ Override
432
+ public void atEnd (ClassBuilder clb ) {
433
+ clb .withMethodBody (
434
+ ConstantDescs .CLASS_INIT_NAME ,
435
+ ConstantDescs .MTD_void ,
436
+ ACC_PUBLIC | ClassFile .ACC_STATIC ,
437
+ cob -> {
438
+ cob .return_ ();
439
+ });
440
+ }
441
+ });
442
+ } catch (ClinitAlreadyExistsException e ) {
443
+ return null ;
444
+ }
445
+ }
446
+
410
447
@ CEntryPoint
411
448
@ CEntryPointOptions (prologue = AgentIsolate .Prologue .class )
412
449
@ SuppressWarnings ("unused" )
0 commit comments