Skip to content

Commit 4244540

Browse files
committed
Fall back to Class.forName in case boot class is already defined
1 parent eed1078 commit 4244540

File tree

1 file changed

+29
-2
lines changed

1 file changed

+29
-2
lines changed

class-inject/src/glue/java/datadog/instrument/glue/DefineClassGlueGenerator.java

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,9 @@ final class DefineClassGlueGenerator {
8181
+ CLASS_CLASS
8282
+ ";";
8383

84+
private static final String CLASS_FORNAME_DESCRIPTOR =
85+
"(L" + STRING_CLASS + ";ZL" + CLASSLOADER_CLASS + ";)L" + CLASS_CLASS + ";";
86+
8487
private DefineClassGlueGenerator() {}
8588

8689
/**
@@ -166,7 +169,10 @@ private static byte[] generateBytecode(String unsafeNamespace) {
166169
final Label unlockClassLoaderAndThrow = new Label();
167170
final Label setupUnsafeDefiner = new Label();
168171
final Label hasNextBootClass = new Label();
172+
final Label defineBootClass = new Label();
169173
final Label storeBootClass = new Label();
174+
final Label loadBootClass = new Label();
175+
final Label rethrowOriginal = new Label();
170176
final Label returnDefinedClasses = new Label();
171177

172178
// common bytecode variables
@@ -184,12 +190,17 @@ private static byte[] generateBytecode(String unsafeNamespace) {
184190

185191
// bytecode variables for boot classes
186192
final int unsafeInstance = 8;
193+
final int originalError = 9;
187194

188195
mv.visitCode();
189196

190197
// make sure we unlock the class-loader if an exception occurs while defining a class
191198
mv.visitTryCatchBlock(classLoaderLocked, classLoaderUnlocked, unlockClassLoaderAndThrow, null);
192199

200+
// fall back and see if the boot class is already loaded if defining it fails
201+
mv.visitTryCatchBlock(defineBootClass, storeBootClass, loadBootClass, null);
202+
mv.visitTryCatchBlock(loadBootClass, rethrowOriginal, rethrowOriginal, null);
203+
193204
// -------- SHARED SETUP CODE --------
194205

195206
// store the defined classes in a list
@@ -361,10 +372,11 @@ private static byte[] generateBytecode(String unsafeNamespace) {
361372
mv.visitVarInsn(ALOAD, protectionDomain);
362373

363374
// define the boot class using the given class-name and bytecode
375+
mv.visitLabel(defineBootClass);
364376
mv.visitMethodInsn(
365377
INVOKEVIRTUAL, unsafeClass, "defineClass", UNSAFE_DEFINECLASS_DESCRIPTOR, false);
366378

367-
// store the class in the list
379+
// store the class in the list whether we defined it or it already existed
368380
mv.visitLabel(storeBootClass);
369381
mv.visitVarInsn(ALOAD, definedClasses);
370382
mv.visitInsn(SWAP);
@@ -374,6 +386,21 @@ private static byte[] generateBytecode(String unsafeNamespace) {
374386
// check again if we've defined all the given bytecode
375387
mv.visitJumpInsn(GOTO, hasNextBootClass);
376388

389+
// see if the boot class has already been defined
390+
mv.visitLabel(loadBootClass);
391+
mv.visitVarInsn(ASTORE, originalError);
392+
mv.visitVarInsn(ALOAD, className);
393+
mv.visitInsn(ICONST_0); // initialize=false
394+
mv.visitInsn(ACONST_NULL);
395+
mv.visitMethodInsn(INVOKESTATIC, CLASS_CLASS, "forName", CLASS_FORNAME_DESCRIPTOR, false);
396+
mv.visitJumpInsn(GOTO, storeBootClass);
397+
398+
// boot class is not defined, report original error
399+
mv.visitLabel(rethrowOriginal);
400+
mv.visitInsn(POP);
401+
mv.visitVarInsn(ALOAD, originalError);
402+
mv.visitInsn(ATHROW);
403+
377404
// -------- SHARED RETURN CODE --------
378405

379406
// return the defined classes
@@ -385,7 +412,7 @@ private static byte[] generateBytecode(String unsafeNamespace) {
385412
mv.visitEnd();
386413

387414
// pad bytecode to even number of bytes, to make string encoding/decoding easier
388-
if ((unsafeNamespace.length() & 0x01) == 1) {
415+
if ((unsafeNamespace.length() & 0x01) == 0) {
389416
cw.newConst(0);
390417
}
391418

0 commit comments

Comments
 (0)