1313import io .opentelemetry .javaagent .extension .instrumentation .TypeInstrumentation ;
1414import io .opentelemetry .javaagent .extension .instrumentation .TypeTransformer ;
1515import io .opentelemetry .javaagent .extension .instrumentation .internal .AsmApi ;
16+ import net .bytebuddy .ClassFileVersion ;
1617import net .bytebuddy .asm .AsmVisitorWrapper ;
1718import net .bytebuddy .description .field .FieldDescription ;
1819import net .bytebuddy .description .field .FieldList ;
@@ -72,6 +73,7 @@ public ClassVisitor wrap(
7273
7374 private static class ClassLoaderClassVisitor extends ClassVisitor implements Opcodes {
7475 private String internalClassName ;
76+ private boolean frames ;
7577
7678 ClassLoaderClassVisitor (ClassVisitor classVisitor ) {
7779 super (AsmApi .VERSION , classVisitor );
@@ -87,160 +89,173 @@ public void visit(
8789 String [] interfaces ) {
8890 super .visit (version , access , name , signature , superName , interfaces );
8991 internalClassName = name ;
92+ frames = ClassFileVersion .ofMinorMajor (version ).isAtLeast (ClassFileVersion .JAVA_V6 );
9093 }
9194
9295 @ Override
9396 public MethodVisitor visitMethod (
9497 int access , String name , String descriptor , String signature , String [] exceptions ) {
9598 MethodVisitor mv = super .visitMethod (access , name , descriptor , signature , exceptions );
96- if ("loadClass" .equals (name )
97- && ("(Ljava/lang/String;)Ljava/lang/Class;" .equals (descriptor )
98- || "(Ljava/lang/String;Z)Ljava/lang/Class;" .equals (descriptor ))) {
99-
100- int argumentCount = Type .getArgumentTypes (descriptor ).length ;
101- return new MethodVisitor (api , mv ) {
102- @ Override
103- public void visitCode () {
104- super .visitCode ();
105-
106- // inserts the following at the start of the loadClass method:
107- /*
108- InjectedClassHelper.HelperClassInfo helperClassInfo = InjectedClassHelper.getHelperClassInfo(this, name);
109- if (helperClassInfo != null) {
110- Class<?> clazz = findLoadedClass(name);
111- if (clazz != null) {
112- return clazz;
113- }
114- try {
115- byte[] bytes = helperClassInfo.getClassBytes();
116- return defineClass(name, bytes, 0, bytes.length, helperClassInfo.getProtectionDomain());
117- } catch (LinkageError error) {
118- clazz = findLoadedClass(name);
119- if (clazz != null) {
120- return clazz;
121- }
122- throw error;
123- }
124- }
125- */
126-
127- Label startTry = new Label ();
128- Label endTry = new Label ();
129- Label handler = new Label ();
130- mv .visitTryCatchBlock (startTry , endTry , handler , "java/lang/LinkageError" );
131- // InjectedClassHelper.HelperClassInfo helperClassInfo =
132- // InjectedClassHelper.getHelperClassInfo(this, name);
133- mv .visitVarInsn (ALOAD , 0 );
134- mv .visitVarInsn (ALOAD , 1 );
135- mv .visitMethodInsn (
136- INVOKESTATIC ,
137- Type .getInternalName (InjectedClassHelper .class ),
138- "getHelperClassInfo" ,
139- "(Ljava/lang/ClassLoader;Ljava/lang/String;)"
140- + Type .getDescriptor (HelperClassInfo .class ),
141- false );
142- mv .visitVarInsn (ASTORE , argumentCount + 1 ); // store helperClassInfo
143- mv .visitVarInsn (ALOAD , argumentCount + 1 );
144- Label notHelperClass = new Label ();
145- mv .visitJumpInsn (IFNULL , notHelperClass );
146-
147- // getHelperClassInfo returned non-null
148- // Class<?> clazz = findLoadedClass(name);
149- mv .visitVarInsn (ALOAD , 0 );
150- mv .visitVarInsn (ALOAD , 1 );
151- mv .visitMethodInsn (
152- INVOKEVIRTUAL ,
153- internalClassName ,
154- "findLoadedClass" ,
155- "(Ljava/lang/String;)Ljava/lang/Class;" ,
156- false );
157- mv .visitVarInsn (ASTORE , argumentCount + 2 ); // store clazz
158- mv .visitVarInsn (ALOAD , argumentCount + 2 );
159- mv .visitJumpInsn (IFNULL , startTry );
160-
161- // findLoadedClass returned non-null
162- // return clazz
163- mv .visitVarInsn (ALOAD , argumentCount + 2 );
164- mv .visitInsn (ARETURN );
165-
166- mv .visitLabel (startTry );
99+ boolean loadClassMethod =
100+ "loadClass" .equals (name )
101+ && ("(Ljava/lang/String;)Ljava/lang/Class;" .equals (descriptor )
102+ || "(Ljava/lang/String;Z)Ljava/lang/Class;" .equals (descriptor ));
103+ if (!loadClassMethod ) {
104+ return mv ;
105+ }
106+
107+ int argumentCount = Type .getArgumentTypes (descriptor ).length ;
108+ return new MethodVisitor (api , mv ) {
109+ @ Override
110+ public void visitCode () {
111+ super .visitCode ();
112+
113+ // inserts the following at the start of the loadClass method:
114+ /*
115+ InjectedClassHelper.HelperClassInfo helperClassInfo = InjectedClassHelper.getHelperClassInfo(this, name);
116+ if (helperClassInfo != null) {
117+ Class<?> clazz = findLoadedClass(name);
118+ if (clazz != null) {
119+ return clazz;
120+ }
121+ try {
122+ byte[] bytes = helperClassInfo.getClassBytes();
123+ return defineClass(name, bytes, 0, bytes.length, helperClassInfo.getProtectionDomain());
124+ } catch (LinkageError error) {
125+ clazz = findLoadedClass(name);
126+ if (clazz != null) {
127+ return clazz;
128+ }
129+ throw error;
130+ }
131+ }
132+ */
133+
134+ Label startTry = new Label ();
135+ Label endTry = new Label ();
136+ Label handler = new Label ();
137+ mv .visitTryCatchBlock (startTry , endTry , handler , "java/lang/LinkageError" );
138+ // InjectedClassHelper.HelperClassInfo helperClassInfo = InjectedClassHelper
139+ // .getHelperClassInfo(this, name);
140+ mv .visitVarInsn (ALOAD , 0 );
141+ mv .visitVarInsn (ALOAD , 1 );
142+ mv .visitMethodInsn (
143+ INVOKESTATIC ,
144+ Type .getInternalName (InjectedClassHelper .class ),
145+ "getHelperClassInfo" ,
146+ "(Ljava/lang/ClassLoader;Ljava/lang/String;)"
147+ + Type .getDescriptor (HelperClassInfo .class ),
148+ false );
149+ mv .visitVarInsn (ASTORE , argumentCount + 1 ); // store helperClassInfo
150+ mv .visitVarInsn (ALOAD , argumentCount + 1 );
151+ Label notHelperClass = new Label ();
152+ mv .visitJumpInsn (IFNULL , notHelperClass );
153+
154+ // getHelperClassInfo returned non-null
155+ // Class<?> clazz = findLoadedClass(name);
156+ mv .visitVarInsn (ALOAD , 0 );
157+ mv .visitVarInsn (ALOAD , 1 );
158+ mv .visitMethodInsn (
159+ INVOKEVIRTUAL ,
160+ internalClassName ,
161+ "findLoadedClass" ,
162+ "(Ljava/lang/String;)Ljava/lang/Class;" ,
163+ false );
164+ mv .visitVarInsn (ASTORE , argumentCount + 2 ); // store clazz
165+ mv .visitVarInsn (ALOAD , argumentCount + 2 );
166+ mv .visitJumpInsn (IFNULL , startTry );
167+
168+ // findLoadedClass returned non-null
169+ // return clazz
170+ mv .visitVarInsn (ALOAD , argumentCount + 2 );
171+ mv .visitInsn (ARETURN );
172+
173+ mv .visitLabel (startTry );
174+ if (frames ) {
167175 mv .visitFrame (
168176 Opcodes .F_APPEND ,
169177 2 ,
170178 new Object [] {Type .getInternalName (HelperClassInfo .class ), "java/lang/Class" },
171179 0 ,
172180 null );
173- // byte[] bytes = helperClassInfo.getClassBytes();
174- mv .visitVarInsn (ALOAD , argumentCount + 1 );
175- mv .visitMethodInsn (
176- INVOKEINTERFACE ,
177- Type .getInternalName (HelperClassInfo .class ),
178- "getClassBytes" ,
179- "()[B" ,
180- true );
181- mv .visitVarInsn (ASTORE , argumentCount + 3 ); // store bytes
182-
183- // return defineClass(name, bytes, 0, bytes.length,
184- // helperClassInfo.getProtectionDomain());
185- mv .visitVarInsn (ALOAD , 0 );
186- mv .visitVarInsn (ALOAD , 1 );
187- mv .visitVarInsn (ALOAD , argumentCount + 3 );
188- mv .visitInsn (ICONST_0 );
189- mv .visitVarInsn (ALOAD , argumentCount + 3 );
190- mv .visitInsn (ARRAYLENGTH );
191- mv .visitVarInsn (ALOAD , argumentCount + 1 );
192- mv .visitMethodInsn (
193- INVOKEINTERFACE ,
194- Type .getInternalName (HelperClassInfo .class ),
195- "getProtectionDomain" ,
196- "()Ljava/security/ProtectionDomain;" ,
197- true );
198- mv .visitMethodInsn (
199- INVOKEVIRTUAL ,
200- internalClassName ,
201- "defineClass" ,
202- "(Ljava/lang/String;[BIILjava/security/ProtectionDomain;)Ljava/lang/Class;" ,
203- false );
204- mv .visitLabel (endTry );
205- mv .visitInsn (ARETURN );
206-
207- mv .visitLabel (handler );
181+ }
182+ // byte[] bytes = helperClassInfo.getClassBytes();
183+ mv .visitVarInsn (ALOAD , argumentCount + 1 );
184+ mv .visitMethodInsn (
185+ INVOKEINTERFACE ,
186+ Type .getInternalName (HelperClassInfo .class ),
187+ "getClassBytes" ,
188+ "()[B" ,
189+ true );
190+ mv .visitVarInsn (ASTORE , argumentCount + 3 ); // store bytes
191+
192+ // return defineClass(name, bytes, 0, bytes.length,
193+ // helperClassInfo.getProtectionDomain());
194+ mv .visitVarInsn (ALOAD , 0 );
195+ mv .visitVarInsn (ALOAD , 1 );
196+ mv .visitVarInsn (ALOAD , argumentCount + 3 );
197+ mv .visitInsn (ICONST_0 );
198+ mv .visitVarInsn (ALOAD , argumentCount + 3 );
199+ mv .visitInsn (ARRAYLENGTH );
200+ mv .visitVarInsn (ALOAD , argumentCount + 1 );
201+ mv .visitMethodInsn (
202+ INVOKEINTERFACE ,
203+ Type .getInternalName (HelperClassInfo .class ),
204+ "getProtectionDomain" ,
205+ "()Ljava/security/ProtectionDomain;" ,
206+ true );
207+ mv .visitMethodInsn (
208+ INVOKEVIRTUAL ,
209+ internalClassName ,
210+ "defineClass" ,
211+ "(Ljava/lang/String;[BIILjava/security/ProtectionDomain;)Ljava/lang/Class;" ,
212+ false );
213+ mv .visitLabel (endTry );
214+ mv .visitInsn (ARETURN );
215+
216+ mv .visitLabel (handler );
217+ if (frames ) {
208218 mv .visitFrame (Opcodes .F_SAME1 , 0 , null , 1 , new Object [] {"java/lang/LinkageError" });
209- mv .visitVarInsn (ASTORE , argumentCount + 3 ); // store LinkageError
210- // clazz = findLoadedClass(name);
211- mv .visitVarInsn (ALOAD , 0 );
212- mv .visitVarInsn (ALOAD , 1 );
213- mv .visitMethodInsn (
214- INVOKEVIRTUAL ,
215- internalClassName ,
216- "findLoadedClass" ,
217- "(Ljava/lang/String;)Ljava/lang/Class;" ,
218- false );
219- mv .visitVarInsn (ASTORE , argumentCount + 2 ); // score clazz
220- mv .visitVarInsn (ALOAD , argumentCount + 2 );
221- Label throwError = new Label ();
222- mv .visitJumpInsn (IFNULL , throwError );
223- // return clazz
224- mv .visitVarInsn (ALOAD , argumentCount + 2 );
225- mv .visitInsn (ARETURN );
226- mv .visitLabel (throwError );
219+ }
220+ mv .visitVarInsn (ASTORE , argumentCount + 3 ); // store LinkageError
221+ // clazz = findLoadedClass(name);
222+ mv .visitVarInsn (ALOAD , 0 );
223+ mv .visitVarInsn (ALOAD , 1 );
224+ mv .visitMethodInsn (
225+ INVOKEVIRTUAL ,
226+ internalClassName ,
227+ "findLoadedClass" ,
228+ "(Ljava/lang/String;)Ljava/lang/Class;" ,
229+ false );
230+ mv .visitVarInsn (ASTORE , argumentCount + 2 ); // score clazz
231+ mv .visitVarInsn (ALOAD , argumentCount + 2 );
232+ Label throwError = new Label ();
233+ mv .visitJumpInsn (IFNULL , throwError );
234+ // return clazz
235+ mv .visitVarInsn (ALOAD , argumentCount + 2 );
236+ mv .visitInsn (ARETURN );
237+ mv .visitLabel (throwError );
238+ if (frames ) {
227239 mv .visitFrame (Opcodes .F_APPEND , 1 , new Object [] {"java/lang/LinkageError" }, 0 , null );
228- // throw error
229- mv .visitVarInsn (ALOAD , argumentCount + 3 );
230- mv .visitInsn (ATHROW );
240+ }
241+ // throw error
242+ mv .visitVarInsn (ALOAD , argumentCount + 3 );
243+ mv .visitInsn (ATHROW );
231244
232- mv .visitLabel (notHelperClass );
245+ mv .visitLabel (notHelperClass );
246+ if (frames ) {
233247 mv .visitFrame (Opcodes .F_CHOP , 3 , null , 0 , null );
248+ // ensure there aren't two frames at the same location
249+ mv .visitInsn (NOP );
234250 }
251+ }
235252
236- @ Override
237- public void visitMaxs (int maxStack , int maxLocals ) {
238- // minimally we have argumentCount parameters + this + 3 locals added by us
239- super .visitMaxs (maxStack , Math .max (maxLocals , argumentCount + 1 + 3 ));
240- }
241- };
242- }
243- return mv ;
253+ @ Override
254+ public void visitMaxs (int maxStack , int maxLocals ) {
255+ // minimally we have argumentCount parameters + this + 3 locals added by us
256+ super .visitMaxs (maxStack , Math .max (maxLocals , argumentCount + 1 + 3 ));
257+ }
258+ };
244259 }
245260 }
246261}
0 commit comments