View Javadoc
1   /*
2    * MIT License
3    * Copyright (c) 2006-2025 JMockit developers
4    * See LICENSE file for full license text.
5    */
6   package mockit.internal.startup;
7   
8   import static java.lang.reflect.Modifier.PUBLIC;
9   import static java.lang.reflect.Modifier.STATIC;
10  import static java.lang.reflect.Modifier.isPublic;
11  
12  import edu.umd.cs.findbugs.annotations.NonNull;
13  import edu.umd.cs.findbugs.annotations.Nullable;
14  
15  import java.lang.instrument.ClassFileTransformer;
16  import java.lang.instrument.Instrumentation;
17  import java.security.ProtectionDomain;
18  import java.security.Provider;
19  
20  import mockit.asm.classes.ClassReader;
21  import mockit.asm.classes.ClassVisitor;
22  import mockit.asm.classes.ClassWriter;
23  import mockit.asm.classes.WrappingClassVisitor;
24  import mockit.asm.jvmConstants.Access;
25  import mockit.internal.ClassLoadingBridge;
26  import mockit.internal.expectations.mocking.MockedBridge;
27  import mockit.internal.faking.FakeBridge;
28  import mockit.internal.faking.FakeMethodBridge;
29  
30  final class ClassLoadingBridgeFields {
31      private ClassLoadingBridgeFields() {
32      }
33  
34      static void createSyntheticFieldsInJREClassToHoldClassLoadingBridges(@NonNull Instrumentation instrumentation) {
35          FieldAdditionTransformer fieldAdditionTransformer = new FieldAdditionTransformer(instrumentation);
36          instrumentation.addTransformer(fieldAdditionTransformer);
37  
38          // Loads some JRE classes expected to not be loaded yet.
39          NegativeArraySizeException.class.getName();
40          String hostClassName = fieldAdditionTransformer.hostClassName;
41  
42          if (hostClassName == null) {
43              Provider.class.getName();
44              hostClassName = fieldAdditionTransformer.hostClassName;
45          }
46  
47          ClassLoadingBridge.hostJREClassName = hostClassName;
48      }
49  
50      private static final class FieldAdditionTransformer implements ClassFileTransformer {
51          private static final int FIELD_ACCESS = PUBLIC + STATIC + Access.SYNTHETIC;
52          @NonNull
53          private final Instrumentation instrumentation;
54          String hostClassName;
55  
56          FieldAdditionTransformer(@NonNull Instrumentation instrumentation) {
57              this.instrumentation = instrumentation;
58          }
59  
60          @Nullable
61          @Override
62          public byte[] transform(@Nullable ClassLoader loader, @NonNull String className,
63                  @Nullable Class<?> classBeingRedefined, @Nullable ProtectionDomain protectionDomain,
64                  @NonNull byte[] classfileBuffer) {
65              if (loader == null && hostClassName == null) { // adds the fields to the first public JRE class to be loaded
66                  ClassReader cr = new ClassReader(classfileBuffer);
67  
68                  if (isPublic(cr.getAccess())) {
69                      instrumentation.removeTransformer(this);
70                      hostClassName = className;
71                      return getModifiedJREClassWithAddedFields(cr);
72                  }
73              }
74  
75              return null;
76          }
77  
78          @NonNull
79          private static byte[] getModifiedJREClassWithAddedFields(@NonNull ClassReader classReader) {
80              ClassWriter cw = new ClassWriter(classReader);
81  
82              ClassVisitor cv = new WrappingClassVisitor(cw) {
83                  @Override
84                  public void visitEnd() {
85                      addField(MockedBridge.MB);
86                      addField(FakeBridge.MB);
87                      addField(FakeMethodBridge.MB);
88                  }
89  
90                  private void addField(@NonNull ClassLoadingBridge mb) {
91                      cw.visitField(FIELD_ACCESS, mb.id, "Ljava/lang/reflect/InvocationHandler;", null, null);
92                  }
93              };
94  
95              classReader.accept(cv);
96              return cw.toByteArray();
97          }
98      }
99  }