@@ -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