@@ -222,6 +222,8 @@ public ClassReader(final byte[] b, final int off, final int len) {
222
222
// case ClassWriter.CLASS:
223
223
// case ClassWriter.STR:
224
224
// case ClassWriter.MTYPE
225
+ // case ClassWriter.PACKAGE:
226
+ // case ClassWriter.MODULE:
225
227
default :
226
228
size = 3 ;
227
229
break ;
@@ -365,7 +367,9 @@ void copyPool(final ClassWriter classWriter) {
365
367
break ;
366
368
// case ClassWriter.STR:
367
369
// case ClassWriter.CLASS:
368
- // case ClassWriter.MTYPE
370
+ // case ClassWriter.MTYPE:
371
+ // case ClassWriter.MODULE:
372
+ // case ClassWriter.PACKAGE:
369
373
default :
370
374
item .set (tag , readUTF8 (index , buf ), null , null );
371
375
break ;
@@ -572,11 +576,14 @@ public void accept(final ClassVisitor classVisitor,
572
576
String enclosingOwner = null ;
573
577
String enclosingName = null ;
574
578
String enclosingDesc = null ;
579
+ String moduleMainClass = null ;
575
580
int anns = 0 ;
576
581
int ianns = 0 ;
577
582
int tanns = 0 ;
578
583
int itanns = 0 ;
579
584
int innerClasses = 0 ;
585
+ int module = 0 ;
586
+ int packages = 0 ;
580
587
Attribute attributes = null ;
581
588
582
589
u = getAttributes ();
@@ -617,6 +624,12 @@ public void accept(final ClassVisitor classVisitor,
617
624
} else if (ANNOTATIONS
618
625
&& "RuntimeInvisibleTypeAnnotations" .equals (attrName )) {
619
626
itanns = u + 8 ;
627
+ } else if ("Module" .equals (attrName )) {
628
+ module = u + 8 ;
629
+ } else if ("ModuleMainClass" .equals (attrName )) {
630
+ moduleMainClass = readClass (u + 8 , c );
631
+ } else if ("ModulePackages" .equals (attrName )) {
632
+ packages = u + 10 ;
620
633
} else if ("BootstrapMethods" .equals (attrName )) {
621
634
int [] bootstrapMethods = new int [readUnsignedShort (u + 8 )];
622
635
for (int j = 0 , v = u + 10 ; j < bootstrapMethods .length ; j ++) {
@@ -645,6 +658,12 @@ public void accept(final ClassVisitor classVisitor,
645
658
classVisitor .visitSource (sourceFile , sourceDebug );
646
659
}
647
660
661
+ // visits the module info and associated attributes
662
+ if (module != 0 ) {
663
+ readModule (classVisitor , context , module ,
664
+ moduleMainClass , packages );
665
+ }
666
+
648
667
// visits the outer class
649
668
if (enclosingOwner != null ) {
650
669
classVisitor .visitOuterClass (enclosingOwner , enclosingName ,
@@ -714,6 +733,120 @@ public void accept(final ClassVisitor classVisitor,
714
733
classVisitor .visitEnd ();
715
734
}
716
735
736
+ /**
737
+ * Reads the module attribute and visit it.
738
+ *
739
+ * @param classVisitor
740
+ * the current class visitor
741
+ * @param context
742
+ * information about the class being parsed.
743
+ * @param u
744
+ * start offset of the module attribute in the class file.
745
+ * @param mainClass
746
+ * name of the main class of a module or null.
747
+ * @param packages
748
+ * start offset of the concealed package attribute.
749
+ */
750
+ private void readModule (final ClassVisitor classVisitor ,
751
+ final Context context , int u ,
752
+ final String mainClass , int packages ) {
753
+
754
+ char [] buffer = context .buffer ;
755
+
756
+ // reads module name, flags and version
757
+ String name = readModule (u , buffer );
758
+ int flags = readUnsignedShort (u + 2 );
759
+ String version = readUTF8 (u + 4 , buffer );
760
+ u += 6 ;
761
+
762
+ ModuleVisitor mv = classVisitor .visitModule (name , flags , version );
763
+ if (mv == null ) {
764
+ return ;
765
+ }
766
+
767
+ // module attributes (main class, packages)
768
+ if (mainClass != null ) {
769
+ mv .visitMainClass (mainClass );
770
+ }
771
+
772
+ if (packages != 0 ) {
773
+ for (int i = readUnsignedShort (packages - 2 ); i > 0 ; --i ) {
774
+ String packaze = readPackage (packages , buffer );
775
+ mv .visitPackage (packaze );
776
+ packages += 2 ;
777
+ }
778
+ }
779
+
780
+ // reads requires
781
+ u += 2 ;
782
+ for (int i = readUnsignedShort (u - 2 ); i > 0 ; --i ) {
783
+ String module = readModule (u , buffer );
784
+ int access = readUnsignedShort (u + 2 );
785
+ String requireVersion = readUTF8 (u + 4 , buffer );
786
+ mv .visitRequire (module , access , requireVersion );
787
+ u += 6 ;
788
+ }
789
+
790
+ // reads exports
791
+ u += 2 ;
792
+ for (int i = readUnsignedShort (u - 2 ); i > 0 ; --i ) {
793
+ String export = readPackage (u , buffer );
794
+ int access = readUnsignedShort (u + 2 );
795
+ int exportToCount = readUnsignedShort (u + 4 );
796
+ u += 6 ;
797
+ String [] tos = null ;
798
+ if (exportToCount != 0 ) {
799
+ tos = new String [exportToCount ];
800
+ for (int j = 0 ; j < tos .length ; ++j ) {
801
+ tos [j ] = readModule (u , buffer );
802
+ u += 2 ;
803
+ }
804
+ }
805
+ mv .visitExport (export , access , tos );
806
+ }
807
+
808
+ // reads opens
809
+ u += 2 ;
810
+ for (int i = readUnsignedShort (u - 2 ); i > 0 ; --i ) {
811
+ String open = readPackage (u , buffer );
812
+ int access = readUnsignedShort (u + 2 );
813
+ int openToCount = readUnsignedShort (u + 4 );
814
+ u += 6 ;
815
+ String [] tos = null ;
816
+ if (openToCount != 0 ) {
817
+ tos = new String [openToCount ];
818
+ for (int j = 0 ; j < tos .length ; ++j ) {
819
+ tos [j ] = readModule (u , buffer );
820
+ u += 2 ;
821
+ }
822
+ }
823
+ mv .visitOpen (open , access , tos );
824
+ }
825
+
826
+ // read uses
827
+ u += 2 ;
828
+ for (int i = readUnsignedShort (u - 2 ); i > 0 ; --i ) {
829
+ mv .visitUse (readClass (u , buffer ));
830
+ u += 2 ;
831
+ }
832
+
833
+ // read provides
834
+ u += 2 ;
835
+ for (int i = readUnsignedShort (u - 2 ); i > 0 ; --i ) {
836
+ String service = readClass (u , buffer );
837
+ int provideWithCount = readUnsignedShort (u + 2 );
838
+ u += 4 ;
839
+ String [] withs = new String [provideWithCount ];
840
+ for (int j = 0 ; j < withs .length ; ++j ) {
841
+ withs [j ] = readClass (u , buffer );
842
+ u += 2 ;
843
+ }
844
+ mv .visitProvide (service , withs );
845
+ }
846
+
847
+ mv .visitEnd ();
848
+ }
849
+
717
850
/**
718
851
* Reads a field and makes the given visitor visit it.
719
852
*
@@ -1082,6 +1215,7 @@ private void readCode(final MethodVisitor mv, final Context context, int u) {
1082
1215
u += 3 ;
1083
1216
break ;
1084
1217
case ClassWriter .LABELW_INSN :
1218
+ case ClassWriter .ASM_LABELW_INSN :
1085
1219
readLabel (offset + readInt (u + 1 ), labels );
1086
1220
u += 5 ;
1087
1221
break ;
@@ -1305,7 +1439,8 @@ private void readCode(final MethodVisitor mv, final Context context, int u) {
1305
1439
}
1306
1440
}
1307
1441
}
1308
- if ((context .flags & EXPAND_ASM_INSNS ) != 0 ) {
1442
+ if ((context .flags & EXPAND_ASM_INSNS ) != 0
1443
+ && (context .flags & EXPAND_FRAMES ) != 0 ) {
1309
1444
// Expanding the ASM pseudo instructions can introduce F_INSERT
1310
1445
// frames, even if the method does not currently have any frame.
1311
1446
// Also these inserted frames must be computed by simulating the
@@ -1322,6 +1457,7 @@ private void readCode(final MethodVisitor mv, final Context context, int u) {
1322
1457
1323
1458
// visits the instructions
1324
1459
int opcodeDelta = (context .flags & EXPAND_ASM_INSNS ) == 0 ? -33 : 0 ;
1460
+ boolean insertFrame = false ;
1325
1461
u = codeStart ;
1326
1462
while (u < codeEnd ) {
1327
1463
int offset = u - codeStart ;
@@ -1354,6 +1490,9 @@ private void readCode(final MethodVisitor mv, final Context context, int u) {
1354
1490
mv .visitFrame (frame .mode , frame .localDiff , frame .local ,
1355
1491
frame .stackCount , frame .stack );
1356
1492
}
1493
+ // if there is already a frame for this offset, there is no
1494
+ // need to insert a new one.
1495
+ insertFrame = false ;
1357
1496
}
1358
1497
if (frameCount > 0 ) {
1359
1498
stackMap = readFrame (stackMap , zip , unzip , frame );
@@ -1362,6 +1501,13 @@ private void readCode(final MethodVisitor mv, final Context context, int u) {
1362
1501
frame = null ;
1363
1502
}
1364
1503
}
1504
+ // inserts a frame for this offset, if requested by setting
1505
+ // insertFrame to true during the previous iteration. The actual
1506
+ // frame content will be computed in MethodWriter.
1507
+ if (FRAMES && insertFrame ) {
1508
+ mv .visitFrame (ClassWriter .F_INSERT , 0 , null , 0 , null );
1509
+ insertFrame = false ;
1510
+ }
1365
1511
1366
1512
// visits the instruction at this offset
1367
1513
int opcode = b [u ] & 0xFF ;
@@ -1397,31 +1543,36 @@ private void readCode(final MethodVisitor mv, final Context context, int u) {
1397
1543
opcode = opcode < 218 ? opcode - 49 : opcode - 20 ;
1398
1544
Label target = labels [offset + readUnsignedShort (u + 1 )];
1399
1545
// replaces GOTO with GOTO_W, JSR with JSR_W and IFxxx
1400
- // <l> with IFNOTxxx <l' > GOTO_W <l>, where IFNOTxxx is
1546
+ // <l> with IFNOTxxx <L > GOTO_W <l> L:... , where IFNOTxxx is
1401
1547
// the "opposite" opcode of IFxxx (i.e., IFNE for IFEQ)
1402
- // and where <l' > designates the instruction just after
1548
+ // and where <L > designates the instruction just after
1403
1549
// the GOTO_W.
1404
1550
if (opcode == Opcodes .GOTO || opcode == Opcodes .JSR ) {
1405
1551
mv .visitJumpInsn (opcode + 33 , target );
1406
1552
} else {
1407
1553
opcode = opcode <= 166 ? ((opcode + 1 ) ^ 1 ) - 1
1408
1554
: opcode ^ 1 ;
1409
- Label endif = new Label ( );
1555
+ Label endif = readLabel ( offset + 3 , labels );
1410
1556
mv .visitJumpInsn (opcode , endif );
1411
1557
mv .visitJumpInsn (200 , target ); // GOTO_W
1412
- mv .visitLabel (endif );
1413
- // since we introduced an unconditional jump instruction we
1414
- // also need to insert a stack map frame here, unless there
1415
- // is already one. The actual frame content will be computed
1416
- // in MethodWriter.
1417
- if (FRAMES && stackMap != 0
1418
- && (frame == null || frame .offset != offset + 3 )) {
1419
- mv .visitFrame (ClassWriter .F_INSERT , 0 , null , 0 , null );
1420
- }
1558
+ // endif designates the instruction just after GOTO_W,
1559
+ // and is visited as part of the next instruction. Since
1560
+ // it is a jump target, we need to insert a frame here.
1561
+ insertFrame = true ;
1421
1562
}
1422
1563
u += 3 ;
1423
1564
break ;
1424
1565
}
1566
+ case ClassWriter .ASM_LABELW_INSN : {
1567
+ // replaces the pseudo GOTO_W instruction with a real one.
1568
+ mv .visitJumpInsn (200 , labels [offset + readInt (u + 1 )]);
1569
+ // The instruction just after is a jump target (because pseudo
1570
+ // GOTO_W are used in patterns IFNOTxxx <L> GOTO_W <l> L:...,
1571
+ // see MethodWriter), so we need to insert a frame here.
1572
+ insertFrame = true ;
1573
+ u += 5 ;
1574
+ break ;
1575
+ }
1425
1576
case ClassWriter .WIDE_INSN :
1426
1577
opcode = b [u + 1 ] & 0xFF ;
1427
1578
if (opcode == Opcodes .IINC ) {
@@ -2516,6 +2667,20 @@ private String readUTF(int index, final int utfLen, final char[] buf) {
2516
2667
return new String (buf , 0 , strLen );
2517
2668
}
2518
2669
2670
+ /**
2671
+ * Read a stringish constant item (CONSTANT_Class, CONSTANT_String,
2672
+ * CONSTANT_MethodType, CONSTANT_Module or CONSTANT_Package
2673
+ * @param index
2674
+ * @param buf
2675
+ * @return
2676
+ */
2677
+ private String readStringish (final int index , final char [] buf ) {
2678
+ // computes the start index of the item in b
2679
+ // and reads the CONSTANT_Utf8 item designated by
2680
+ // the first two bytes of this item
2681
+ return readUTF8 (items [readUnsignedShort (index )], buf );
2682
+ }
2683
+
2519
2684
/**
2520
2685
* Reads a class constant pool item in {@link #b b}. <i>This method is
2521
2686
* intended for {@link Attribute} sub classes, and is normally not needed by
@@ -2530,11 +2695,41 @@ private String readUTF(int index, final int utfLen, final char[] buf) {
2530
2695
* @return the String corresponding to the specified class item.
2531
2696
*/
2532
2697
public String readClass (final int index , final char [] buf ) {
2533
- // computes the start index of the CONSTANT_Class item in b
2534
- // and reads the CONSTANT_Utf8 item designated by
2535
- // the first two bytes of this CONSTANT_Class item
2536
- String name = readUTF8 (items [readUnsignedShort (index )], buf );
2537
- return (name != null ? name .intern () : null );
2698
+ return readStringish (index , buf );
2699
+ }
2700
+
2701
+ /**
2702
+ * Reads a module constant pool item in {@link #b b}. <i>This method is
2703
+ * intended for {@link Attribute} sub classes, and is normally not needed by
2704
+ * class generators or adapters.</i>
2705
+ *
2706
+ * @param index
2707
+ * the start index of an unsigned short value in {@link #b b},
2708
+ * whose value is the index of a module constant pool item.
2709
+ * @param buf
2710
+ * buffer to be used to read the item. This buffer must be
2711
+ * sufficiently large. It is not automatically resized.
2712
+ * @return the String corresponding to the specified module item.
2713
+ */
2714
+ public String readModule (final int index , final char [] buf ) {
2715
+ return readStringish (index , buf );
2716
+ }
2717
+
2718
+ /**
2719
+ * Reads a module constant pool item in {@link #b b}. <i>This method is
2720
+ * intended for {@link Attribute} sub classes, and is normally not needed by
2721
+ * class generators or adapters.</i>
2722
+ *
2723
+ * @param index
2724
+ * the start index of an unsigned short value in {@link #b b},
2725
+ * whose value is the index of a module constant pool item.
2726
+ * @param buf
2727
+ * buffer to be used to read the item. This buffer must be
2728
+ * sufficiently large. It is not automatically resized.
2729
+ * @return the String corresponding to the specified module item.
2730
+ */
2731
+ public String readPackage (final int index , final char [] buf ) {
2732
+ return readStringish (index , buf );
2538
2733
}
2539
2734
2540
2735
/**
0 commit comments