@@ -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,6 +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 ();
173+ final Label storeBootClass = new Label ();
174+ final Label loadBootClass = new Label ();
175+ final Label rethrowOriginal = new Label ();
169176 final Label returnDefinedClasses = new Label ();
170177
171178 // common bytecode variables
@@ -175,20 +182,25 @@ private static byte[] generateBytecode(String unsafeNamespace) {
175182 final int mapEntrySetIterator = 4 ;
176183 final int protectionDomain = 5 ;
177184 final int classLoader = 6 ;
185+ final int className = 7 ;
178186
179187 // bytecode variables for non-boot classes
180- final int classLoadingLock = 7 ;
181- final int bytecodeMapEntry = 8 ;
182- final int className = 9 ;
188+ final int classLoadingLock = 8 ;
189+ final int bytecodeMapEntry = 9 ;
183190
184191 // bytecode variables for boot classes
185- final int unsafeInstance = 7 ;
192+ final int unsafeInstance = 8 ;
193+ final int originalError = 9 ;
186194
187195 mv .visitCode ();
188196
189197 // make sure we unlock the class-loader if an exception occurs while defining a class
190198 mv .visitTryCatchBlock (classLoaderLocked , classLoaderUnlocked , unlockClassLoaderAndThrow , null );
191199
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+
192204 // -------- SHARED SETUP CODE --------
193205
194206 // store the defined classes in a list
@@ -278,11 +290,13 @@ private static byte[] generateBytecode(String unsafeNamespace) {
278290 false );
279291 mv .visitInsn (DUP );
280292 mv .visitJumpInsn (IFNONNULL , storeNonBootClass );
281-
282- // define the class using the given class-name and bytecode
283293 mv .visitInsn (POP );
294+
295+ // not yet defined, prepare arguments to define it
284296 mv .visitVarInsn (ALOAD , classLoader );
285297 mv .visitVarInsn (ALOAD , className );
298+
299+ // extract the bytecode of the next class to define
286300 mv .visitVarInsn (ALOAD , bytecodeMapEntry );
287301 mv .visitMethodInsn (
288302 INVOKEINTERFACE , MAP_ENTRY_CLASS , "getValue" , "()L" + OBJECT_CLASS + ";" , true );
@@ -291,7 +305,10 @@ private static byte[] generateBytecode(String unsafeNamespace) {
291305 mv .visitInsn (ARRAYLENGTH );
292306 mv .visitInsn (ICONST_0 );
293307 mv .visitInsn (SWAP );
308+
294309 mv .visitVarInsn (ALOAD , protectionDomain );
310+
311+ // define the class using the given class-name and bytecode
295312 mv .visitMethodInsn (
296313 INVOKEVIRTUAL , CLASSLOADER_CLASS , "defineClass" , CLASSLOADER_DEFINECLASS_DESCRIPTOR , false );
297314
@@ -312,7 +329,6 @@ private static byte[] generateBytecode(String unsafeNamespace) {
312329
313330 // unlock the class-loader if something goes wrong
314331 mv .visitLabel (unlockClassLoaderAndThrow );
315- mv .visitInsn (DUP );
316332 mv .visitVarInsn (ALOAD , classLoadingLock );
317333 mv .visitInsn (MONITOREXIT );
318334 mv .visitInsn (ATHROW );
@@ -330,28 +346,38 @@ private static byte[] generateBytecode(String unsafeNamespace) {
330346 mv .visitMethodInsn (INVOKEINTERFACE , ITERATOR_CLASS , "hasNext" , "()Z" , true );
331347 mv .visitJumpInsn (IFEQ , returnDefinedClasses );
332348
333- // define the class using the given class-name and bytecode
334349 mv .visitVarInsn (ALOAD , unsafeInstance );
350+
351+ // extract the name of the next class to define
335352 mv .visitVarInsn (ALOAD , mapEntrySetIterator );
336353 mv .visitMethodInsn (INVOKEINTERFACE , ITERATOR_CLASS , "next" , "()L" + OBJECT_CLASS + ";" , true );
337354 mv .visitInsn (DUP );
338355 mv .visitMethodInsn (
339356 INVOKEINTERFACE , MAP_ENTRY_CLASS , "getKey" , "()L" + OBJECT_CLASS + ";" , true );
340357 mv .visitTypeInsn (CHECKCAST , STRING_CLASS );
358+ mv .visitInsn (DUP );
359+ mv .visitVarInsn (ASTORE , className );
341360 mv .visitInsn (SWAP );
361+
362+ // extract the bytecode of the next class to define
342363 mv .visitMethodInsn (
343364 INVOKEINTERFACE , MAP_ENTRY_CLASS , "getValue" , "()L" + OBJECT_CLASS + ";" , true );
344365 mv .visitTypeInsn (CHECKCAST , BYTE_ARRAY );
345366 mv .visitInsn (DUP );
346367 mv .visitInsn (ARRAYLENGTH );
347368 mv .visitInsn (ICONST_0 );
348369 mv .visitInsn (SWAP );
370+
349371 mv .visitInsn (ACONST_NULL );
350372 mv .visitVarInsn (ALOAD , protectionDomain );
373+
374+ // define the boot class using the given class-name and bytecode
375+ mv .visitLabel (defineBootClass );
351376 mv .visitMethodInsn (
352377 INVOKEVIRTUAL , unsafeClass , "defineClass" , UNSAFE_DEFINECLASS_DESCRIPTOR , false );
353378
354- // store the class in the list
379+ // store the class in the list whether we defined it or it already existed
380+ mv .visitLabel (storeBootClass );
355381 mv .visitVarInsn (ALOAD , definedClasses );
356382 mv .visitInsn (SWAP );
357383 mv .visitMethodInsn (INVOKEVIRTUAL , ARRAYLIST_CLASS , "add" , "(L" + OBJECT_CLASS + ";)Z" , false );
@@ -360,6 +386,21 @@ private static byte[] generateBytecode(String unsafeNamespace) {
360386 // check again if we've defined all the given bytecode
361387 mv .visitJumpInsn (GOTO , hasNextBootClass );
362388
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+
363404 // -------- SHARED RETURN CODE --------
364405
365406 // return the defined classes
0 commit comments