Skip to content

Commit 2f50831

Browse files
committed
feat: Refactor LoadClassPatch for readability
Introduce dedicated defineClass method per Java version. Extract bytecode unpack to dedicated method for reuse.
1 parent b23ecdd commit 2f50831

File tree

1 file changed

+62
-64
lines changed

1 file changed

+62
-64
lines changed

class-inject/src/main/java/datadog/instrument/classinject/ClassInjector.java

Lines changed: 62 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -169,74 +169,13 @@ public void visitCode() {
169169
mv.visitJumpInsn(IFEQ, notDatadogGlueRequest);
170170

171171
if (JVM.atLeastJava(15)) {
172-
// on Java 15+ prepare MethodHandles.lookup()
173-
mv.visitMethodInsn(
174-
INVOKESTATIC,
175-
"java/lang/invoke/MethodHandles",
176-
"lookup",
177-
"()Ljava/lang/invoke/MethodHandles$Lookup;",
178-
false);
179-
mv.visitLdcInsn(DefineClassGlue.V9);
172+
defineClassUsingMethodHandles();
180173
} else if (JVM.atLeastJava(9)) {
181174
// on Java 9+ prepare jdk.internal.misc.Unsafe
182-
mv.visitMethodInsn(
183-
INVOKESTATIC,
184-
"jdk/internal/misc/Unsafe",
185-
"getUnsafe",
186-
"()Ljdk/internal/misc/Unsafe;",
187-
false);
188-
mv.visitLdcInsn(Type.getType(ClassLoader.class));
189-
mv.visitLdcInsn(DefineClassGlue.V9);
175+
defineClassUsingUnsafe("jdk/internal/misc/Unsafe", DefineClassGlue.V9);
190176
} else {
191177
// on Java 8 prepare sun.misc.Unsafe
192-
mv.visitMethodInsn(
193-
INVOKESTATIC, "sun/misc/Unsafe", "getUnsafe", "()Lsun/misc/Unsafe;", false);
194-
mv.visitLdcInsn(Type.getType(ClassLoader.class));
195-
mv.visitLdcInsn(DefineClassGlue.V8);
196-
}
197-
198-
// unpack the UTF-16BE encoded string back into bytecode
199-
mv.visitFieldInsn(
200-
GETSTATIC, "java/nio/charset/StandardCharsets", "UTF_16BE", "Ljava/nio/charset/Charset;");
201-
mv.visitMethodInsn(
202-
INVOKEVIRTUAL, "java/lang/String", "getBytes", "(Ljava/nio/charset/Charset;)[B", false);
203-
204-
if (JVM.atLeastJava(15)) {
205-
// on Java 15+ use MethodHandles.lookup().defineHiddenClass(...)
206-
mv.visitInsn(ICONST_0);
207-
mv.visitInsn(ICONST_0);
208-
mv.visitTypeInsn(ANEWARRAY, "java/lang/invoke/MethodHandles$Lookup$ClassOption");
209-
mv.visitMethodInsn(
210-
INVOKEVIRTUAL,
211-
"java/lang/invoke/MethodHandles$Lookup",
212-
"defineHiddenClass",
213-
"([BZ[Ljava/lang/invoke/MethodHandles$Lookup$ClassOption;)Ljava/lang/invoke/MethodHandles$Lookup;",
214-
false);
215-
// use lookupClass() to retrieve the hidden class we just defined
216-
mv.visitMethodInsn(
217-
INVOKEVIRTUAL,
218-
"java/lang/invoke/MethodHandles$Lookup",
219-
"lookupClass",
220-
"()Ljava/lang/Class;",
221-
false);
222-
} else if (JVM.atLeastJava(9)) {
223-
// on Java 9+ use jdk.internal.misc.Unsafe.defineAnonymousClass(...)
224-
mv.visitInsn(ACONST_NULL);
225-
mv.visitMethodInsn(
226-
INVOKEVIRTUAL,
227-
"jdk/internal/misc/Unsafe",
228-
"defineAnonymousClass",
229-
"(Ljava/lang/Class;[B[Ljava/lang/Object;)Ljava/lang/Class;",
230-
false);
231-
} else {
232-
// on Java 8 use sun.misc.Unsafe.defineAnonymousClass(...)
233-
mv.visitInsn(ACONST_NULL);
234-
mv.visitMethodInsn(
235-
INVOKEVIRTUAL,
236-
"sun/misc/Unsafe",
237-
"defineAnonymousClass",
238-
"(Ljava/lang/Class;[B[Ljava/lang/Object;)Ljava/lang/Class;",
239-
false);
178+
defineClassUsingUnsafe("sun/misc/Unsafe", DefineClassGlue.V8);
240179
}
241180

242181
mv.visitInsn(ARETURN);
@@ -246,6 +185,65 @@ public void visitCode() {
246185
mv.visitFrame(F_SAME, 0, null, 0, null);
247186
}
248187

188+
private void defineClassUsingMethodHandles() {
189+
// on Java 15+ prepare MethodHandles.lookup()
190+
mv.visitMethodInsn(
191+
INVOKESTATIC,
192+
"java/lang/invoke/MethodHandles",
193+
"lookup",
194+
"()Ljava/lang/invoke/MethodHandles$Lookup;",
195+
false);
196+
mv.visitLdcInsn(DefineClassGlue.V9);
197+
unpackByteCode();
198+
// on Java 15+ use MethodHandles.lookup().defineHiddenClass(...)
199+
mv.visitInsn(ICONST_0);
200+
mv.visitInsn(ICONST_0);
201+
mv.visitTypeInsn(ANEWARRAY, "java/lang/invoke/MethodHandles$Lookup$ClassOption");
202+
mv.visitMethodInsn(
203+
INVOKEVIRTUAL,
204+
"java/lang/invoke/MethodHandles$Lookup",
205+
"defineHiddenClass",
206+
"([BZ[Ljava/lang/invoke/MethodHandles$Lookup$ClassOption;)Ljava/lang/invoke/MethodHandles$Lookup;",
207+
false);
208+
// use lookupClass() to retrieve the hidden class we just defined
209+
mv.visitMethodInsn(
210+
INVOKEVIRTUAL,
211+
"java/lang/invoke/MethodHandles$Lookup",
212+
"lookupClass",
213+
"()Ljava/lang/Class;",
214+
false);
215+
}
216+
217+
private void defineClassUsingUnsafe(String owner, String glue) {
218+
String descriptor = "()L"+owner+";";
219+
// on Java 9+ prepare jdk.internal.misc.Unsafe
220+
mv.visitMethodInsn(
221+
INVOKESTATIC,
222+
owner,
223+
"getUnsafe",
224+
descriptor,
225+
false);
226+
mv.visitLdcInsn(Type.getType(ClassLoader.class));
227+
mv.visitLdcInsn(glue);
228+
unpackByteCode();
229+
// on Java 9+ use jdk.internal.misc.Unsafe.defineAnonymousClass(...)
230+
mv.visitInsn(ACONST_NULL);
231+
mv.visitMethodInsn(
232+
INVOKEVIRTUAL,
233+
owner,
234+
"defineAnonymousClass",
235+
"(Ljava/lang/Class;[B[Ljava/lang/Object;)Ljava/lang/Class;",
236+
false);
237+
}
238+
239+
private void unpackByteCode() {
240+
// unpack the UTF-16BE encoded string back into bytecode
241+
mv.visitFieldInsn(
242+
GETSTATIC, "java/nio/charset/StandardCharsets", "UTF_16BE", "Ljava/nio/charset/Charset;");
243+
mv.visitMethodInsn(
244+
INVOKEVIRTUAL, "java/lang/String", "getBytes", "(Ljava/nio/charset/Charset;)[B", false);
245+
}
246+
249247
@Override
250248
public void visitMaxs(int maxStack, int maxLocals) {
251249
// ensure we have enough stack allocated for our code

0 commit comments

Comments
 (0)