111
112 /**
113 * Frame where current locals are the same as the locals in the previous
114 * frame, except that k additional locals are defined. The value of k is
115 * given by the formula frame_type-251.
116 */
117 static final int APPEND_FRAME = 252; // to 254 // fc-fe
118
119 /**
120 * Full frame
121 */
122 static final int FULL_FRAME = 255; // ff
123
124 /**
125 * Indicates that the stack map frames must be recomputed from scratch. In
126 * this case the maximum stack size and number of local variables is also
127 * recomputed from scratch.
128 *
129 * @see #compute
130 */
131 private static final int FRAMES = 0;
132
133 /**
134 * Indicates that the maximum stack size and number of local variables must
135 * be automatically computed.
136 *
137 * @see #compute
138 */
139 private static final int MAXS = 1;
140
141 /**
142 * Indicates that nothing must be automatically computed.
143 *
144 * @see #compute
145 */
146 private static final int NOTHING = 2;
147
148 /**
149 * The class writer to which this method must be added.
150 */
151 final ClassWriter cw;
152
153 /**
154 * Access flags of this method.
155 */
156 private int access;
157
158 /**
159 * The index of the constant pool item that contains the name of this
160 * method.
161 */
162 private final int name;
163
164 /**
165 * The index of the constant pool item that contains the descriptor of this
166 * method.
260 private ByteVector code = new ByteVector();
261
262 /**
263 * Maximum stack size of this method.
264 */
265 private int maxStack;
266
267 /**
268 * Maximum number of local variables for this method.
269 */
270 private int maxLocals;
271
272 /**
273 * Number of local variables in the current stack map frame.
274 */
275 private int currentLocals;
276
277 /**
278 * Number of stack map frames in the StackMapTable attribute.
279 */
280 private int frameCount;
281
282 /**
283 * The StackMapTable attribute.
284 */
285 private ByteVector stackMap;
286
287 /**
288 * The offset of the last frame that was written in the StackMapTable
289 * attribute.
290 */
291 private int previousFrameOffset;
292
293 /**
294 * The last frame that was written in the StackMapTable attribute.
295 *
296 * @see #frame
297 */
298 private int[] previousFrame;
299
300 /**
367 * The start offset of the last visited instruction.
368 */
369 private int lastCodeOffset;
370
371 /**
372 * The runtime visible type annotations of the code. May be <tt>null</tt>.
373 */
374 private AnnotationWriter ctanns;
375
376 /**
377 * The runtime invisible type annotations of the code. May be <tt>null</tt>.
378 */
379 private AnnotationWriter ictanns;
380
381 /**
382 * The non standard attributes of the method's code.
383 */
384 private Attribute cattrs;
385
386 /**
387 * Indicates if some jump instructions are too small and need to be resized.
388 */
389 private boolean resize;
390
391 /**
392 * The number of subroutines in this method.
393 */
394 private int subroutines;
395
396 // ------------------------------------------------------------------------
397
398 /*
399 * Fields for the control flow graph analysis algorithm (used to compute the
400 * maximum stack size). A control flow graph contains one node per "basic
401 * block", and one edge per "jump" from one basic block to another. Each
402 * node (i.e., each basic block) is represented by the Label object that
403 * corresponds to the first instruction of this basic block. Each node also
404 * stores the list of its successors in the graph, as a linked list of Edge
405 * objects.
406 */
407
408 /**
409 * Indicates what must be automatically computed.
410 *
411 * @see #FRAMES
412 * @see #MAXS
413 * @see #NOTHING
414 */
415 private final int compute;
416
417 /**
418 * A list of labels. This list is the list of basic blocks in the method,
419 * i.e. a list of Label objects linked to each other by their
420 * {@link Label#successor} field, in the order they are visited by
421 * {@link MethodVisitor#visitLabel}, and starting with the first basic
422 * block.
423 */
424 private Label labels;
425
426 /**
427 * The previous basic block.
428 */
429 private Label previousBlock;
430
431 /**
454 // ------------------------------------------------------------------------
455 // Constructor
456 // ------------------------------------------------------------------------
457
458 /**
459 * Constructs a new {@link MethodWriter}.
460 *
461 * @param cw
462 * the class writer in which the method must be added.
463 * @param access
464 * the method's access flags (see {@link Opcodes}).
465 * @param name
466 * the method's name.
467 * @param desc
468 * the method's descriptor (see {@link Type}).
469 * @param signature
470 * the method's signature. May be <tt>null</tt>.
471 * @param exceptions
472 * the internal names of the method's exceptions. May be
473 * <tt>null</tt>.
474 * @param computeMaxs
475 * <tt>true</tt> if the maximum stack size and number of local
476 * variables must be automatically computed.
477 * @param computeFrames
478 * <tt>true</tt> if the stack map tables must be recomputed from
479 * scratch.
480 */
481 MethodWriter(final ClassWriter cw, final int access, final String name,
482 final String desc, final String signature,
483 final String[] exceptions, final boolean computeMaxs,
484 final boolean computeFrames) {
485 super(Opcodes.ASM5);
486 if (cw.firstMethod == null) {
487 cw.firstMethod = this;
488 } else {
489 cw.lastMethod.mv = this;
490 }
491 cw.lastMethod = this;
492 this.cw = cw;
493 this.access = access;
494 if ("<init>".equals(name)) {
495 this.access |= ACC_CONSTRUCTOR;
496 }
497 this.name = cw.newUTF8(name);
498 this.desc = cw.newUTF8(desc);
499 this.descriptor = desc;
500 if (ClassReader.SIGNATURES) {
501 this.signature = signature;
502 }
503 if (exceptions != null && exceptions.length > 0) {
504 exceptionCount = exceptions.length;
505 this.exceptions = new int[exceptionCount];
506 for (int i = 0; i < exceptionCount; ++i) {
507 this.exceptions[i] = cw.newClass(exceptions[i]);
508 }
509 }
510 this.compute = computeFrames ? FRAMES : (computeMaxs ? MAXS : NOTHING);
511 if (computeMaxs || computeFrames) {
512 // updates maxLocals
513 int size = Type.getArgumentsAndReturnSizes(descriptor) >> 2;
514 if ((access & Opcodes.ACC_STATIC) != 0) {
515 --size;
516 }
517 maxLocals = size;
518 currentLocals = size;
519 // creates and visits the label for the first basic block
520 labels = new Label();
521 labels.status |= Label.PUSHED;
522 visitLabel(labels);
523 }
524 }
525
526 // ------------------------------------------------------------------------
527 // Implementation of the MethodVisitor abstract class
528 // ------------------------------------------------------------------------
529
530 @Override
531 public void visitParameter(String name, int access) {
532 if (methodParameters == null) {
533 methodParameters = new ByteVector();
534 }
535 ++methodParametersCount;
536 methodParameters.putShort((name == null) ? 0 : cw.newUTF8(name))
537 .putShort(access);
538 }
539
540 @Override
541 public AnnotationVisitor visitAnnotationDefault() {
542 if (!ClassReader.ANNOTATIONS) {
543 return null;
544 }
545 annd = new ByteVector();
546 return new AnnotationWriter(cw, false, annd, null, 0);
547 }
548
549 @Override
550 public AnnotationVisitor visitAnnotation(final String desc,
551 final boolean visible) {
552 if (!ClassReader.ANNOTATIONS) {
553 return null;
554 }
555 ByteVector bv = new ByteVector();
556 // write type, and reserve space for values count
557 bv.putShort(cw.newUTF8(desc)).putShort(0);
558 AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2);
559 if (visible) {
560 aw.next = anns;
561 anns = aw;
562 } else {
563 aw.next = ianns;
564 ianns = aw;
565 }
566 return aw;
567 }
568
569 @Override
570 public AnnotationVisitor visitTypeAnnotation(final int typeRef,
571 final TypePath typePath, final String desc, final boolean visible) {
572 if (!ClassReader.ANNOTATIONS) {
573 return null;
574 }
575 ByteVector bv = new ByteVector();
576 // write target_type and target_info
577 AnnotationWriter.putTarget(typeRef, typePath, bv);
578 // write type, and reserve space for values count
579 bv.putShort(cw.newUTF8(desc)).putShort(0);
580 AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv,
581 bv.length - 2);
582 if (visible) {
583 aw.next = tanns;
584 tanns = aw;
585 } else {
586 aw.next = itanns;
587 itanns = aw;
588 }
589 return aw;
590 }
591
592 @Override
593 public AnnotationVisitor visitParameterAnnotation(final int parameter,
594 final String desc, final boolean visible) {
595 if (!ClassReader.ANNOTATIONS) {
596 return null;
597 }
598 ByteVector bv = new ByteVector();
599 if ("Ljava/lang/Synthetic;".equals(desc)) {
600 // workaround for a bug in javac with synthetic parameters
601 // see ClassReader.readParameterAnnotations
602 synthetics = Math.max(synthetics, parameter + 1);
603 return new AnnotationWriter(cw, false, bv, null, 0);
604 }
605 // write type, and reserve space for values count
606 bv.putShort(cw.newUTF8(desc)).putShort(0);
607 AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2);
608 if (visible) {
609 if (panns == null) {
610 panns = new AnnotationWriter[Type.getArgumentTypes(descriptor).length];
611 }
612 aw.next = panns[parameter];
613 panns[parameter] = aw;
614 } else {
615 if (ipanns == null) {
616 ipanns = new AnnotationWriter[Type.getArgumentTypes(descriptor).length];
617 }
622 }
623
624 @Override
625 public void visitAttribute(final Attribute attr) {
626 if (attr.isCodeAttribute()) {
627 attr.next = cattrs;
628 cattrs = attr;
629 } else {
630 attr.next = attrs;
631 attrs = attr;
632 }
633 }
634
635 @Override
636 public void visitCode() {
637 }
638
639 @Override
640 public void visitFrame(final int type, final int nLocal,
641 final Object[] local, final int nStack, final Object[] stack) {
642 if (!ClassReader.FRAMES || compute == FRAMES) {
643 return;
644 }
645
646 if (type == Opcodes.F_NEW) {
647 if (previousFrame == null) {
648 visitImplicitFirstFrame();
649 }
650 currentLocals = nLocal;
651 int frameIndex = startFrame(code.length, nLocal, nStack);
652 for (int i = 0; i < nLocal; ++i) {
653 if (local[i] instanceof String) {
654 frame[frameIndex++] = Frame.OBJECT
655 | cw.addType((String) local[i]);
656 } else if (local[i] instanceof Integer) {
657 frame[frameIndex++] = ((Integer) local[i]).intValue();
658 } else {
659 frame[frameIndex++] = Frame.UNINITIALIZED
660 | cw.addUninitializedType("",
661 ((Label) local[i]).position);
662 }
663 }
664 for (int i = 0; i < nStack; ++i) {
665 if (stack[i] instanceof String) {
666 frame[frameIndex++] = Frame.OBJECT
667 | cw.addType((String) stack[i]);
668 } else if (stack[i] instanceof Integer) {
669 frame[frameIndex++] = ((Integer) stack[i]).intValue();
670 } else {
671 frame[frameIndex++] = Frame.UNINITIALIZED
672 | cw.addUninitializedType("",
673 ((Label) stack[i]).position);
674 }
675 }
676 endFrame();
677 } else {
678 int delta;
679 if (stackMap == null) {
680 stackMap = new ByteVector();
681 delta = code.length;
682 } else {
683 delta = code.length - previousFrameOffset - 1;
684 if (delta < 0) {
685 if (type == Opcodes.F_SAME) {
686 return;
687 } else {
688 throw new IllegalStateException();
689 }
730 writeFrameType(stack[0]);
731 break;
732 }
733
734 previousFrameOffset = code.length;
735 ++frameCount;
736 }
737
738 maxStack = Math.max(maxStack, nStack);
739 maxLocals = Math.max(maxLocals, currentLocals);
740 }
741
742 @Override
743 public void visitInsn(final int opcode) {
744 lastCodeOffset = code.length;
745 // adds the instruction to the bytecode of the method
746 code.putByte(opcode);
747 // update currentBlock
748 // Label currentBlock = this.currentBlock;
749 if (currentBlock != null) {
750 if (compute == FRAMES) {
751 currentBlock.frame.execute(opcode, 0, null, null);
752 } else {
753 // updates current and max stack sizes
754 int size = stackSize + Frame.SIZE[opcode];
755 if (size > maxStackSize) {
756 maxStackSize = size;
757 }
758 stackSize = size;
759 }
760 // if opcode == ATHROW or xRETURN, ends current block (no successor)
761 if ((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN)
762 || opcode == Opcodes.ATHROW) {
763 noSuccessor();
764 }
765 }
766 }
767
768 @Override
769 public void visitIntInsn(final int opcode, final int operand) {
770 lastCodeOffset = code.length;
771 // Label currentBlock = this.currentBlock;
772 if (currentBlock != null) {
773 if (compute == FRAMES) {
774 currentBlock.frame.execute(opcode, operand, null, null);
775 } else if (opcode != Opcodes.NEWARRAY) {
776 // updates current and max stack sizes only for NEWARRAY
777 // (stack size variation = 0 for BIPUSH or SIPUSH)
778 int size = stackSize + 1;
779 if (size > maxStackSize) {
780 maxStackSize = size;
781 }
782 stackSize = size;
783 }
784 }
785 // adds the instruction to the bytecode of the method
786 if (opcode == Opcodes.SIPUSH) {
787 code.put12(opcode, operand);
788 } else { // BIPUSH or NEWARRAY
789 code.put11(opcode, operand);
790 }
791 }
792
793 @Override
794 public void visitVarInsn(final int opcode, final int var) {
795 lastCodeOffset = code.length;
796 // Label currentBlock = this.currentBlock;
797 if (currentBlock != null) {
798 if (compute == FRAMES) {
799 currentBlock.frame.execute(opcode, var, null, null);
800 } else {
801 // updates current and max stack sizes
802 if (opcode == Opcodes.RET) {
803 // no stack change, but end of current block (no successor)
804 currentBlock.status |= Label.RET;
805 // save 'stackSize' here for future use
806 // (see {@link #findSubroutineSuccessors})
807 currentBlock.inputStackTop = stackSize;
808 noSuccessor();
809 } else { // xLOAD or xSTORE
810 int size = stackSize + Frame.SIZE[opcode];
811 if (size > maxStackSize) {
812 maxStackSize = size;
813 }
814 stackSize = size;
815 }
816 }
817 }
818 if (compute != NOTHING) {
835 /* ILOAD_0 */
836 opt = 26 + ((opcode - Opcodes.ILOAD) << 2) + var;
837 } else {
838 /* ISTORE_0 */
839 opt = 59 + ((opcode - Opcodes.ISTORE) << 2) + var;
840 }
841 code.putByte(opt);
842 } else if (var >= 256) {
843 code.putByte(196 /* WIDE */).put12(opcode, var);
844 } else {
845 code.put11(opcode, var);
846 }
847 if (opcode >= Opcodes.ISTORE && compute == FRAMES && handlerCount > 0) {
848 visitLabel(new Label());
849 }
850 }
851
852 @Override
853 public void visitTypeInsn(final int opcode, final String type) {
854 lastCodeOffset = code.length;
855 Item i = cw.newClassItem(type);
856 // Label currentBlock = this.currentBlock;
857 if (currentBlock != null) {
858 if (compute == FRAMES) {
859 currentBlock.frame.execute(opcode, code.length, cw, i);
860 } else if (opcode == Opcodes.NEW) {
861 // updates current and max stack sizes only if opcode == NEW
862 // (no stack change for ANEWARRAY, CHECKCAST, INSTANCEOF)
863 int size = stackSize + 1;
864 if (size > maxStackSize) {
865 maxStackSize = size;
866 }
867 stackSize = size;
868 }
869 }
870 // adds the instruction to the bytecode of the method
871 code.put12(opcode, i.index);
872 }
873
874 @Override
875 public void visitFieldInsn(final int opcode, final String owner,
876 final String name, final String desc) {
877 lastCodeOffset = code.length;
878 Item i = cw.newFieldItem(owner, name, desc);
879 // Label currentBlock = this.currentBlock;
880 if (currentBlock != null) {
881 if (compute == FRAMES) {
882 currentBlock.frame.execute(opcode, 0, cw, i);
883 } else {
884 int size;
885 // computes the stack size variation
886 char c = desc.charAt(0);
887 switch (opcode) {
888 case Opcodes.GETSTATIC:
889 size = stackSize + (c == 'D' || c == 'J' ? 2 : 1);
890 break;
891 case Opcodes.PUTSTATIC:
892 size = stackSize + (c == 'D' || c == 'J' ? -2 : -1);
893 break;
894 case Opcodes.GETFIELD:
895 size = stackSize + (c == 'D' || c == 'J' ? 1 : 0);
896 break;
897 // case Constants.PUTFIELD:
898 default:
899 size = stackSize + (c == 'D' || c == 'J' ? -3 : -2);
900 break;
901 }
902 // updates current and max stack sizes
903 if (size > maxStackSize) {
904 maxStackSize = size;
905 }
906 stackSize = size;
907 }
908 }
909 // adds the instruction to the bytecode of the method
910 code.put12(opcode, i.index);
911 }
912
913 @Override
914 public void visitMethodInsn(final int opcode, final String owner,
915 final String name, final String desc, final boolean itf) {
916 lastCodeOffset = code.length;
917 Item i = cw.newMethodItem(owner, name, desc, itf);
918 int argSize = i.intVal;
919 // Label currentBlock = this.currentBlock;
920 if (currentBlock != null) {
921 if (compute == FRAMES) {
922 currentBlock.frame.execute(opcode, 0, cw, i);
923 } else {
924 /*
925 * computes the stack size variation. In order not to recompute
926 * several times this variation for the same Item, we use the
927 * intVal field of this item to store this variation, once it
928 * has been computed. More precisely this intVal field stores
929 * the sizes of the arguments and of the return value
930 * corresponding to desc.
931 */
932 if (argSize == 0) {
933 // the above sizes have not been computed yet,
934 // so we compute them...
935 argSize = Type.getArgumentsAndReturnSizes(desc);
936 // ... and we save them in order
937 // not to recompute them in the future
938 i.intVal = argSize;
939 }
940 int size;
941 if (opcode == Opcodes.INVOKESTATIC) {
953 // adds the instruction to the bytecode of the method
954 if (opcode == Opcodes.INVOKEINTERFACE) {
955 if (argSize == 0) {
956 argSize = Type.getArgumentsAndReturnSizes(desc);
957 i.intVal = argSize;
958 }
959 code.put12(Opcodes.INVOKEINTERFACE, i.index).put11(argSize >> 2, 0);
960 } else {
961 code.put12(opcode, i.index);
962 }
963 }
964
965 @Override
966 public void visitInvokeDynamicInsn(final String name, final String desc,
967 final Handle bsm, final Object... bsmArgs) {
968 lastCodeOffset = code.length;
969 Item i = cw.newInvokeDynamicItem(name, desc, bsm, bsmArgs);
970 int argSize = i.intVal;
971 // Label currentBlock = this.currentBlock;
972 if (currentBlock != null) {
973 if (compute == FRAMES) {
974 currentBlock.frame.execute(Opcodes.INVOKEDYNAMIC, 0, cw, i);
975 } else {
976 /*
977 * computes the stack size variation. In order not to recompute
978 * several times this variation for the same Item, we use the
979 * intVal field of this item to store this variation, once it
980 * has been computed. More precisely this intVal field stores
981 * the sizes of the arguments and of the return value
982 * corresponding to desc.
983 */
984 if (argSize == 0) {
985 // the above sizes have not been computed yet,
986 // so we compute them...
987 argSize = Type.getArgumentsAndReturnSizes(desc);
988 // ... and we save them in order
989 // not to recompute them in the future
990 i.intVal = argSize;
991 }
992 int size = stackSize - (argSize >> 2) + (argSize & 0x03) + 1;
993
994 // updates current and max stack sizes
995 if (size > maxStackSize) {
996 maxStackSize = size;
997 }
998 stackSize = size;
999 }
1000 }
1001 // adds the instruction to the bytecode of the method
1002 code.put12(Opcodes.INVOKEDYNAMIC, i.index);
1003 code.putShort(0);
1004 }
1005
1006 @Override
1007 public void visitJumpInsn(final int opcode, final Label label) {
1008 lastCodeOffset = code.length;
1009 Label nextInsn = null;
1010 // Label currentBlock = this.currentBlock;
1011 if (currentBlock != null) {
1012 if (compute == FRAMES) {
1013 currentBlock.frame.execute(opcode, 0, null, null);
1014 // 'label' is the target of a jump instruction
1015 label.getFirst().status |= Label.TARGET;
1016 // adds 'label' as a successor of this basic block
1017 addSuccessor(Edge.NORMAL, label);
1018 if (opcode != Opcodes.GOTO) {
1019 // creates a Label for the next basic block
1020 nextInsn = new Label();
1021 }
1022 } else {
1023 if (opcode == Opcodes.JSR) {
1024 if ((label.status & Label.SUBROUTINE) == 0) {
1025 label.status |= Label.SUBROUTINE;
1026 ++subroutines;
1027 }
1028 currentBlock.status |= Label.JSR;
1029 addSuccessor(stackSize + 1, label);
1030 // creates a Label for the next basic block
1031 nextInsn = new Label();
1032 /*
1033 * note that, by construction in this method, a JSR block
1034 * has at least two successors in the control flow graph:
1035 * the first one leads the next instruction after the JSR,
1036 * while the second one leads to the JSR target.
1037 */
1038 } else {
1039 // updates current stack size (max stack size unchanged
1040 // because stack size variation always negative in this
1041 // case)
1042 stackSize += Frame.SIZE[opcode];
1043 addSuccessor(stackSize, label);
1044 }
1045 }
1046 }
1047 // adds the instruction to the bytecode of the method
1048 if ((label.status & Label.RESOLVED) != 0
1049 && label.position - code.length < Short.MIN_VALUE) {
1050 /*
1051 * case of a backward jump with an offset < -32768. In this case we
1052 * automatically replace GOTO with GOTO_W, JSR with JSR_W and IFxxx
1053 * <l> with IFNOTxxx <l'> GOTO_W <l>, where IFNOTxxx is the
1054 * "opposite" opcode of IFxxx (i.e., IFNE for IFEQ) and where <l'>
1055 * designates the instruction just after the GOTO_W.
1056 */
1057 if (opcode == Opcodes.GOTO) {
1058 code.putByte(200); // GOTO_W
1059 } else if (opcode == Opcodes.JSR) {
1060 code.putByte(201); // JSR_W
1061 } else {
1062 // if the IF instruction is transformed into IFNOT GOTO_W the
1063 // next instruction becomes the target of the IFNOT instruction
1064 if (nextInsn != null) {
1065 nextInsn.status |= Label.TARGET;
1066 }
1067 code.putByte(opcode <= 166 ? ((opcode + 1) ^ 1) - 1
1068 : opcode ^ 1);
1069 code.putShort(8); // jump offset
1070 code.putByte(200); // GOTO_W
1071 }
1072 label.put(this, code, code.length - 1, true);
1073 } else {
1074 /*
1075 * case of a backward jump with an offset >= -32768, or of a forward
1076 * jump with, of course, an unknown offset. In these cases we store
1077 * the offset in 2 bytes (which will be increased in
1078 * resizeInstructions, if needed).
1079 */
1080 code.putByte(opcode);
1081 label.put(this, code, code.length - 1, false);
1082 }
1083 if (currentBlock != null) {
1084 if (nextInsn != null) {
1085 // if the jump instruction is not a GOTO, the next instruction
1086 // is also a successor of this instruction. Calling visitLabel
1087 // adds the label of this next instruction as a successor of the
1088 // current block, and starts a new basic block
1089 visitLabel(nextInsn);
1090 }
1091 if (opcode == Opcodes.GOTO) {
1092 noSuccessor();
1093 }
1094 }
1095 }
1096
1097 @Override
1098 public void visitLabel(final Label label) {
1099 // resolves previous forward references to label, if any
1100 resize |= label.resolve(this, code.length, code.data);
1101 // updates currentBlock
1102 if ((label.status & Label.DEBUG) != 0) {
1103 return;
1104 }
1105 if (compute == FRAMES) {
1106 if (currentBlock != null) {
1107 if (label.position == currentBlock.position) {
1108 // successive labels, do not start a new basic block
1109 currentBlock.status |= (label.status & Label.TARGET);
1110 label.frame = currentBlock.frame;
1111 return;
1112 }
1113 // ends current block (with one new successor)
1114 addSuccessor(Edge.NORMAL, label);
1115 }
1116 // begins a new current block
1117 currentBlock = label;
1118 if (label.frame == null) {
1119 label.frame = new Frame();
1120 label.frame.owner = label;
1121 }
1122 // updates the basic block list
1123 if (previousBlock != null) {
1124 if (label.position == previousBlock.position) {
1125 previousBlock.status |= (label.status & Label.TARGET);
1126 label.frame = previousBlock.frame;
1127 currentBlock = previousBlock;
1128 return;
1129 }
1130 previousBlock.successor = label;
1131 }
1132 previousBlock = label;
1133 } else if (compute == MAXS) {
1134 if (currentBlock != null) {
1135 // ends current block (with one new successor)
1136 currentBlock.outputStackMax = maxStackSize;
1137 addSuccessor(stackSize, label);
1138 }
1139 // begins a new current block
1140 currentBlock = label;
1141 // resets the relative current and max stack sizes
1142 stackSize = 0;
1143 maxStackSize = 0;
1144 // updates the basic block list
1145 if (previousBlock != null) {
1146 previousBlock.successor = label;
1147 }
1148 previousBlock = label;
1149 }
1150 }
1151
1152 @Override
1153 public void visitLdcInsn(final Object cst) {
1154 lastCodeOffset = code.length;
1155 Item i = cw.newConstItem(cst);
1156 // Label currentBlock = this.currentBlock;
1157 if (currentBlock != null) {
1158 if (compute == FRAMES) {
1159 currentBlock.frame.execute(Opcodes.LDC, 0, cw, i);
1160 } else {
1161 int size;
1162 // computes the stack size variation
1163 if (i.type == ClassWriter.LONG || i.type == ClassWriter.DOUBLE) {
1164 size = stackSize + 2;
1165 } else {
1166 size = stackSize + 1;
1167 }
1168 // updates current and max stack sizes
1169 if (size > maxStackSize) {
1170 maxStackSize = size;
1171 }
1172 stackSize = size;
1173 }
1174 }
1175 // adds the instruction to the bytecode of the method
1176 int index = i.index;
1177 if (i.type == ClassWriter.LONG || i.type == ClassWriter.DOUBLE) {
1178 code.put12(20 /* LDC2_W */, index);
1179 } else if (index >= 256) {
1180 code.put12(19 /* LDC_W */, index);
1181 } else {
1182 code.put11(Opcodes.LDC, index);
1183 }
1184 }
1185
1186 @Override
1187 public void visitIincInsn(final int var, final int increment) {
1188 lastCodeOffset = code.length;
1189 if (currentBlock != null) {
1190 if (compute == FRAMES) {
1191 currentBlock.frame.execute(Opcodes.IINC, var, null, null);
1192 }
1193 }
1194 if (compute != NOTHING) {
1195 // updates max locals
1196 int n = var + 1;
1197 if (n > maxLocals) {
1198 maxLocals = n;
1199 }
1200 }
1201 // adds the instruction to the bytecode of the method
1202 if ((var > 255) || (increment > 127) || (increment < -128)) {
1203 code.putByte(196 /* WIDE */).put12(Opcodes.IINC, var)
1204 .putShort(increment);
1205 } else {
1206 code.putByte(Opcodes.IINC).put11(var, increment);
1207 }
1208 }
1209
1210 @Override
1254 addSuccessor(Edge.NORMAL, labels[i]);
1255 labels[i].getFirst().status |= Label.TARGET;
1256 }
1257 } else {
1258 // updates current stack size (max stack size unchanged)
1259 --stackSize;
1260 // adds current block successors
1261 addSuccessor(stackSize, dflt);
1262 for (int i = 0; i < labels.length; ++i) {
1263 addSuccessor(stackSize, labels[i]);
1264 }
1265 }
1266 // ends current block
1267 noSuccessor();
1268 }
1269 }
1270
1271 @Override
1272 public void visitMultiANewArrayInsn(final String desc, final int dims) {
1273 lastCodeOffset = code.length;
1274 Item i = cw.newClassItem(desc);
1275 // Label currentBlock = this.currentBlock;
1276 if (currentBlock != null) {
1277 if (compute == FRAMES) {
1278 currentBlock.frame.execute(Opcodes.MULTIANEWARRAY, dims, cw, i);
1279 } else {
1280 // updates current stack size (max stack size unchanged because
1281 // stack size variation always negative or null)
1282 stackSize += 1 - dims;
1283 }
1284 }
1285 // adds the instruction to the bytecode of the method
1286 code.put12(Opcodes.MULTIANEWARRAY, i.index).putByte(dims);
1287 }
1288
1289 @Override
1290 public AnnotationVisitor visitInsnAnnotation(int typeRef,
1291 TypePath typePath, String desc, boolean visible) {
1292 if (!ClassReader.ANNOTATIONS) {
1293 return null;
1294 }
1295 ByteVector bv = new ByteVector();
1296 // write target_type and target_info
1297 typeRef = (typeRef & 0xFF0000FF) | (lastCodeOffset << 8);
1298 AnnotationWriter.putTarget(typeRef, typePath, bv);
1299 // write type, and reserve space for values count
1300 bv.putShort(cw.newUTF8(desc)).putShort(0);
1301 AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv,
1302 bv.length - 2);
1303 if (visible) {
1304 aw.next = ctanns;
1305 ctanns = aw;
1306 } else {
1307 aw.next = ictanns;
1308 ictanns = aw;
1309 }
1310 return aw;
1311 }
1312
1313 @Override
1314 public void visitTryCatchBlock(final Label start, final Label end,
1315 final Label handler, final String type) {
1316 ++handlerCount;
1317 Handler h = new Handler();
1318 h.start = start;
1319 h.end = end;
1320 h.handler = handler;
1321 h.desc = type;
1322 h.type = type != null ? cw.newClass(type) : 0;
1323 if (lastHandler == null) {
1324 firstHandler = h;
1325 } else {
1326 lastHandler.next = h;
1327 }
1328 lastHandler = h;
1329 }
1330
1331 @Override
1332 public AnnotationVisitor visitTryCatchAnnotation(int typeRef,
1333 TypePath typePath, String desc, boolean visible) {
1334 if (!ClassReader.ANNOTATIONS) {
1335 return null;
1336 }
1337 ByteVector bv = new ByteVector();
1338 // write target_type and target_info
1339 AnnotationWriter.putTarget(typeRef, typePath, bv);
1340 // write type, and reserve space for values count
1341 bv.putShort(cw.newUTF8(desc)).putShort(0);
1342 AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv,
1343 bv.length - 2);
1344 if (visible) {
1345 aw.next = ctanns;
1346 ctanns = aw;
1347 } else {
1348 aw.next = ictanns;
1349 ictanns = aw;
1350 }
1351 return aw;
1352 }
1353
1354 @Override
1355 public void visitLocalVariable(final String name, final String desc,
1356 final String signature, final Label start, final Label end,
1370 }
1371 ++localVarCount;
1372 localVar.putShort(start.position)
1373 .putShort(end.position - start.position)
1374 .putShort(cw.newUTF8(name)).putShort(cw.newUTF8(desc))
1375 .putShort(index);
1376 if (compute != NOTHING) {
1377 // updates max locals
1378 char c = desc.charAt(0);
1379 int n = index + (c == 'J' || c == 'D' ? 2 : 1);
1380 if (n > maxLocals) {
1381 maxLocals = n;
1382 }
1383 }
1384 }
1385
1386 @Override
1387 public AnnotationVisitor visitLocalVariableAnnotation(int typeRef,
1388 TypePath typePath, Label[] start, Label[] end, int[] index,
1389 String desc, boolean visible) {
1390 if (!ClassReader.ANNOTATIONS) {
1391 return null;
1392 }
1393 ByteVector bv = new ByteVector();
1394 // write target_type and target_info
1395 bv.putByte(typeRef >>> 24).putShort(start.length);
1396 for (int i = 0; i < start.length; ++i) {
1397 bv.putShort(start[i].position)
1398 .putShort(end[i].position - start[i].position)
1399 .putShort(index[i]);
1400 }
1401 if (typePath == null) {
1402 bv.putByte(0);
1403 } else {
1404 int length = typePath.b[typePath.offset] * 2 + 1;
1405 bv.putByteArray(typePath.b, typePath.offset, length);
1406 }
1407 // write type, and reserve space for values count
1408 bv.putShort(cw.newUTF8(desc)).putShort(0);
1409 AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv,
1410 bv.length - 2);
1411 if (visible) {
1412 aw.next = ctanns;
1413 ctanns = aw;
1414 } else {
1415 aw.next = ictanns;
1416 ictanns = aw;
1417 }
1418 return aw;
1419 }
1420
1421 @Override
1422 public void visitLineNumber(final int line, final Label start) {
1423 if (lineNumber == null) {
1424 lineNumber = new ByteVector();
1425 }
1426 ++lineNumberCount;
1427 lineNumber.putShort(start.position);
1428 lineNumber.putShort(line);
1429 }
1430
1431 @Override
1432 public void visitMaxs(final int maxStack, final int maxLocals) {
1433 if (resize) {
1434 // replaces the temporary jump opcodes introduced by Label.resolve.
1435 if (ClassReader.RESIZE) {
1436 resizeInstructions();
1437 } else {
1438 throw new RuntimeException("Method code too large!");
1439 }
1440 }
1441 if (ClassReader.FRAMES && compute == FRAMES) {
1442 // completes the control flow graph with exception handler blocks
1443 Handler handler = firstHandler;
1444 while (handler != null) {
1445 Label l = handler.start.getFirst();
1446 Label h = handler.handler.getFirst();
1447 Label e = handler.end.getFirst();
1448 // computes the kind of the edges to 'h'
1449 String t = handler.desc == null ? "java/lang/Throwable"
1450 : handler.desc;
1451 int kind = Frame.OBJECT | cw.addType(t);
1452 // h is an exception handler
1453 h.status |= Label.TARGET;
1454 // adds 'h' as a successor of labels between 'start' and 'end'
1455 while (l != e) {
1456 // creates an edge to 'h'
1457 Edge b = new Edge();
1458 b.info = kind;
1459 b.successor = h;
1460 // adds it to the successors of 'l'
1461 b.next = l.successors;
1462 l.successors = b;
1463 // goes to the next label
1464 l = l.successor;
1465 }
1466 handler = handler.next;
1467 }
1468
1469 // creates and visits the first (implicit) frame
1470 Frame f = labels.frame;
1471 Type[] args = Type.getArgumentTypes(descriptor);
1472 f.initInputFrame(cw, access, args, this.maxLocals);
1473 visitFrame(f);
1474
1475 /*
1476 * fix point algorithm: mark the first basic block as 'changed'
1477 * (i.e. put it in the 'changed' list) and, while there are changed
1478 * basic blocks, choose one, mark it as unchanged, and update its
1479 * successors (which can be changed in the process).
1480 */
1481 int max = 0;
1482 Label changed = labels;
1483 while (changed != null) {
1484 // removes a basic block from the list of changed basic blocks
1485 Label l = changed;
1486 changed = changed.next;
1487 l.next = null;
1488 f = l.frame;
1489 // a reachable jump target must be stored in the stack map
1490 if ((l.status & Label.TARGET) != 0) {
1491 l.status |= Label.STORE;
1492 }
1700 // ...and adds it to the successor list of the currentBlock block
1701 b.next = currentBlock.successors;
1702 currentBlock.successors = b;
1703 }
1704
1705 /**
1706 * Ends the current basic block. This method must be used in the case where
1707 * the current basic block does not have any successor.
1708 */
1709 private void noSuccessor() {
1710 if (compute == FRAMES) {
1711 Label l = new Label();
1712 l.frame = new Frame();
1713 l.frame.owner = l;
1714 l.resolve(this, code.length, code.data);
1715 previousBlock.successor = l;
1716 previousBlock = l;
1717 } else {
1718 currentBlock.outputStackMax = maxStackSize;
1719 }
1720 currentBlock = null;
1721 }
1722
1723 // ------------------------------------------------------------------------
1724 // Utility methods: stack map frames
1725 // ------------------------------------------------------------------------
1726
1727 /**
1728 * Visits a frame that has been computed from scratch.
1729 *
1730 * @param f
1731 * the frame that must be visited.
1732 */
1733 private void visitFrame(final Frame f) {
1734 int i, t;
1735 int nTop = 0;
1736 int nLocal = 0;
1737 int nStack = 0;
1738 int[] locals = f.inputLocals;
1739 int[] stacks = f.inputStack;
1740 // computes the number of locals (ignores TOP types that are just after
1741 // a LONG or a DOUBLE, and all trailing TOP types)
1772 for (i = 0; i < stacks.length; ++i) {
1773 t = stacks[i];
1774 frame[frameIndex++] = t;
1775 if (t == Frame.LONG || t == Frame.DOUBLE) {
1776 ++i;
1777 }
1778 }
1779 endFrame();
1780 }
1781
1782 /**
1783 * Visit the implicit first frame of this method.
1784 */
1785 private void visitImplicitFirstFrame() {
1786 // There can be at most descriptor.length() + 1 locals
1787 int frameIndex = startFrame(0, descriptor.length() + 1, 0);
1788 if ((access & Opcodes.ACC_STATIC) == 0) {
1789 if ((access & ACC_CONSTRUCTOR) == 0) {
1790 frame[frameIndex++] = Frame.OBJECT | cw.addType(cw.thisName);
1791 } else {
1792 frame[frameIndex++] = 6; // Opcodes.UNINITIALIZED_THIS;
1793 }
1794 }
1795 int i = 1;
1796 loop: while (true) {
1797 int j = i;
1798 switch (descriptor.charAt(i++)) {
1799 case 'Z':
1800 case 'C':
1801 case 'B':
1802 case 'S':
1803 case 'I':
1804 frame[frameIndex++] = 1; // Opcodes.INTEGER;
1805 break;
1806 case 'F':
1807 frame[frameIndex++] = 2; // Opcodes.FLOAT;
1808 break;
1809 case 'J':
1810 frame[frameIndex++] = 4; // Opcodes.LONG;
1811 break;
1812 case 'D':
1813 frame[frameIndex++] = 3; // Opcodes.DOUBLE;
1814 break;
1815 case '[':
1816 while (descriptor.charAt(i) == '[') {
1817 ++i;
1818 }
1819 if (descriptor.charAt(i) == 'L') {
1820 ++i;
1821 while (descriptor.charAt(i) != ';') {
1822 ++i;
1823 }
1824 }
1825 frame[frameIndex++] = Frame.OBJECT
1826 | cw.addType(descriptor.substring(j, ++i));
1827 break;
1828 case 'L':
1829 while (descriptor.charAt(i) != ';') {
1830 ++i;
1831 }
1832 frame[frameIndex++] = Frame.OBJECT
1833 | cw.addType(descriptor.substring(j + 1, i++));
1834 break;
1835 default:
1836 break loop;
1837 }
1838 }
1839 frame[1] = frameIndex - 3;
1840 endFrame();
1841 }
1842
1843 /**
1844 * Starts the visit of a stack map frame.
1845 *
1846 * @param offset
2066 }
2067 cw.newUTF8("Code");
2068 size += 18 + code.length + 8 * handlerCount;
2069 if (localVar != null) {
2070 cw.newUTF8("LocalVariableTable");
2071 size += 8 + localVar.length;
2072 }
2073 if (localVarType != null) {
2074 cw.newUTF8("LocalVariableTypeTable");
2075 size += 8 + localVarType.length;
2076 }
2077 if (lineNumber != null) {
2078 cw.newUTF8("LineNumberTable");
2079 size += 8 + lineNumber.length;
2080 }
2081 if (stackMap != null) {
2082 boolean zip = (cw.version & 0xFFFF) >= Opcodes.V1_6;
2083 cw.newUTF8(zip ? "StackMapTable" : "StackMap");
2084 size += 8 + stackMap.length;
2085 }
2086 if (ClassReader.ANNOTATIONS && ctanns != null) {
2087 cw.newUTF8("RuntimeVisibleTypeAnnotations");
2088 size += 8 + ctanns.getSize();
2089 }
2090 if (ClassReader.ANNOTATIONS && ictanns != null) {
2091 cw.newUTF8("RuntimeInvisibleTypeAnnotations");
2092 size += 8 + ictanns.getSize();
2093 }
2094 if (cattrs != null) {
2095 size += cattrs.getSize(cw, code.data, code.length, maxStack,
2096 maxLocals);
2097 }
2098 }
2099 if (exceptionCount > 0) {
2100 cw.newUTF8("Exceptions");
2101 size += 8 + 2 * exceptionCount;
2102 }
2103 if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
2104 if ((cw.version & 0xFFFF) < Opcodes.V1_5
2105 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) {
2106 cw.newUTF8("Synthetic");
2107 size += 6;
2108 }
2109 }
2110 if ((access & Opcodes.ACC_DEPRECATED) != 0) {
2111 cw.newUTF8("Deprecated");
2112 size += 6;
2113 }
2114 if (ClassReader.SIGNATURES && signature != null) {
2115 cw.newUTF8("Signature");
2116 cw.newUTF8(signature);
2117 size += 8;
2118 }
2119 if (methodParameters != null) {
2120 cw.newUTF8("MethodParameters");
2121 size += 7 + methodParameters.length;
2122 }
2123 if (ClassReader.ANNOTATIONS && annd != null) {
2124 cw.newUTF8("AnnotationDefault");
2125 size += 6 + annd.length;
2126 }
2127 if (ClassReader.ANNOTATIONS && anns != null) {
2128 cw.newUTF8("RuntimeVisibleAnnotations");
2129 size += 8 + anns.getSize();
2130 }
2131 if (ClassReader.ANNOTATIONS && ianns != null) {
2132 cw.newUTF8("RuntimeInvisibleAnnotations");
2133 size += 8 + ianns.getSize();
2134 }
2135 if (ClassReader.ANNOTATIONS && tanns != null) {
2136 cw.newUTF8("RuntimeVisibleTypeAnnotations");
2137 size += 8 + tanns.getSize();
2138 }
2139 if (ClassReader.ANNOTATIONS && itanns != null) {
2140 cw.newUTF8("RuntimeInvisibleTypeAnnotations");
2141 size += 8 + itanns.getSize();
2142 }
2143 if (ClassReader.ANNOTATIONS && panns != null) {
2144 cw.newUTF8("RuntimeVisibleParameterAnnotations");
2145 size += 7 + 2 * (panns.length - synthetics);
2146 for (int i = panns.length - 1; i >= synthetics; --i) {
2147 size += panns[i] == null ? 0 : panns[i].getSize();
2148 }
2149 }
2150 if (ClassReader.ANNOTATIONS && ipanns != null) {
2151 cw.newUTF8("RuntimeInvisibleParameterAnnotations");
2152 size += 7 + 2 * (ipanns.length - synthetics);
2153 for (int i = ipanns.length - 1; i >= synthetics; --i) {
2154 size += ipanns[i] == null ? 0 : ipanns[i].getSize();
2155 }
2156 }
2157 if (attrs != null) {
2158 size += attrs.getSize(cw, null, 0, -1, -1);
2159 }
2160 return size;
2161 }
2162
2163 /**
2164 * Puts the bytecode of this method in the given byte vector.
2165 *
2166 * @param out
2167 * the byte vector into which the bytecode of this method must be
2168 * copied.
2169 */
2170 final void put(final ByteVector out) {
2176 if (classReaderOffset != 0) {
2177 out.putByteArray(cw.cr.b, classReaderOffset, classReaderLength);
2178 return;
2179 }
2180 int attributeCount = 0;
2181 if (code.length > 0) {
2182 ++attributeCount;
2183 }
2184 if (exceptionCount > 0) {
2185 ++attributeCount;
2186 }
2187 if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
2188 if ((cw.version & 0xFFFF) < Opcodes.V1_5
2189 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) {
2190 ++attributeCount;
2191 }
2192 }
2193 if ((access & Opcodes.ACC_DEPRECATED) != 0) {
2194 ++attributeCount;
2195 }
2196 if (ClassReader.SIGNATURES && signature != null) {
2197 ++attributeCount;
2198 }
2199 if (methodParameters != null) {
2200 ++attributeCount;
2201 }
2202 if (ClassReader.ANNOTATIONS && annd != null) {
2203 ++attributeCount;
2204 }
2205 if (ClassReader.ANNOTATIONS && anns != null) {
2206 ++attributeCount;
2207 }
2208 if (ClassReader.ANNOTATIONS && ianns != null) {
2209 ++attributeCount;
2210 }
2211 if (ClassReader.ANNOTATIONS && tanns != null) {
2212 ++attributeCount;
2213 }
2214 if (ClassReader.ANNOTATIONS && itanns != null) {
2215 ++attributeCount;
2216 }
2217 if (ClassReader.ANNOTATIONS && panns != null) {
2218 ++attributeCount;
2219 }
2220 if (ClassReader.ANNOTATIONS && ipanns != null) {
2221 ++attributeCount;
2222 }
2223 if (attrs != null) {
2224 attributeCount += attrs.getCount();
2225 }
2226 out.putShort(attributeCount);
2227 if (code.length > 0) {
2228 int size = 12 + code.length + 8 * handlerCount;
2229 if (localVar != null) {
2230 size += 8 + localVar.length;
2231 }
2232 if (localVarType != null) {
2233 size += 8 + localVarType.length;
2234 }
2235 if (lineNumber != null) {
2236 size += 8 + lineNumber.length;
2237 }
2238 if (stackMap != null) {
2239 size += 8 + stackMap.length;
2240 }
2241 if (ClassReader.ANNOTATIONS && ctanns != null) {
2242 size += 8 + ctanns.getSize();
2243 }
2244 if (ClassReader.ANNOTATIONS && ictanns != null) {
2245 size += 8 + ictanns.getSize();
2246 }
2247 if (cattrs != null) {
2248 size += cattrs.getSize(cw, code.data, code.length, maxStack,
2249 maxLocals);
2250 }
2251 out.putShort(cw.newUTF8("Code")).putInt(size);
2252 out.putShort(maxStack).putShort(maxLocals);
2253 out.putInt(code.length).putByteArray(code.data, 0, code.length);
2254 out.putShort(handlerCount);
2255 if (handlerCount > 0) {
2256 Handler h = firstHandler;
2257 while (h != null) {
2258 out.putShort(h.start.position).putShort(h.end.position)
2259 .putShort(h.handler.position).putShort(h.type);
2260 h = h.next;
2261 }
2262 }
2263 attributeCount = 0;
2264 if (localVar != null) {
2265 ++attributeCount;
2266 }
2267 if (localVarType != null) {
2268 ++attributeCount;
2269 }
2270 if (lineNumber != null) {
2271 ++attributeCount;
2272 }
2273 if (stackMap != null) {
2274 ++attributeCount;
2275 }
2276 if (ClassReader.ANNOTATIONS && ctanns != null) {
2277 ++attributeCount;
2278 }
2279 if (ClassReader.ANNOTATIONS && ictanns != null) {
2280 ++attributeCount;
2281 }
2282 if (cattrs != null) {
2283 attributeCount += cattrs.getCount();
2284 }
2285 out.putShort(attributeCount);
2286 if (localVar != null) {
2287 out.putShort(cw.newUTF8("LocalVariableTable"));
2288 out.putInt(localVar.length + 2).putShort(localVarCount);
2289 out.putByteArray(localVar.data, 0, localVar.length);
2290 }
2291 if (localVarType != null) {
2292 out.putShort(cw.newUTF8("LocalVariableTypeTable"));
2293 out.putInt(localVarType.length + 2).putShort(localVarTypeCount);
2294 out.putByteArray(localVarType.data, 0, localVarType.length);
2295 }
2296 if (lineNumber != null) {
2297 out.putShort(cw.newUTF8("LineNumberTable"));
2298 out.putInt(lineNumber.length + 2).putShort(lineNumberCount);
2299 out.putByteArray(lineNumber.data, 0, lineNumber.length);
2300 }
2301 if (stackMap != null) {
2302 boolean zip = (cw.version & 0xFFFF) >= Opcodes.V1_6;
2303 out.putShort(cw.newUTF8(zip ? "StackMapTable" : "StackMap"));
2304 out.putInt(stackMap.length + 2).putShort(frameCount);
2305 out.putByteArray(stackMap.data, 0, stackMap.length);
2306 }
2307 if (ClassReader.ANNOTATIONS && ctanns != null) {
2308 out.putShort(cw.newUTF8("RuntimeVisibleTypeAnnotations"));
2309 ctanns.put(out);
2310 }
2311 if (ClassReader.ANNOTATIONS && ictanns != null) {
2312 out.putShort(cw.newUTF8("RuntimeInvisibleTypeAnnotations"));
2313 ictanns.put(out);
2314 }
2315 if (cattrs != null) {
2316 cattrs.put(cw, code.data, code.length, maxLocals, maxStack, out);
2317 }
2318 }
2319 if (exceptionCount > 0) {
2320 out.putShort(cw.newUTF8("Exceptions")).putInt(
2321 2 * exceptionCount + 2);
2322 out.putShort(exceptionCount);
2323 for (int i = 0; i < exceptionCount; ++i) {
2324 out.putShort(exceptions[i]);
2325 }
2326 }
2327 if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
2328 if ((cw.version & 0xFFFF) < Opcodes.V1_5
2329 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) {
2330 out.putShort(cw.newUTF8("Synthetic")).putInt(0);
2331 }
2332 }
2333 if ((access & Opcodes.ACC_DEPRECATED) != 0) {
2334 out.putShort(cw.newUTF8("Deprecated")).putInt(0);
2335 }
2336 if (ClassReader.SIGNATURES && signature != null) {
2337 out.putShort(cw.newUTF8("Signature")).putInt(2)
2338 .putShort(cw.newUTF8(signature));
2339 }
2340 if (methodParameters != null) {
2341 out.putShort(cw.newUTF8("MethodParameters"));
2342 out.putInt(methodParameters.length + 1).putByte(
2343 methodParametersCount);
2344 out.putByteArray(methodParameters.data, 0, methodParameters.length);
2345 }
2346 if (ClassReader.ANNOTATIONS && annd != null) {
2347 out.putShort(cw.newUTF8("AnnotationDefault"));
2348 out.putInt(annd.length);
2349 out.putByteArray(annd.data, 0, annd.length);
2350 }
2351 if (ClassReader.ANNOTATIONS && anns != null) {
2352 out.putShort(cw.newUTF8("RuntimeVisibleAnnotations"));
2353 anns.put(out);
2354 }
2355 if (ClassReader.ANNOTATIONS && ianns != null) {
2356 out.putShort(cw.newUTF8("RuntimeInvisibleAnnotations"));
2357 ianns.put(out);
2358 }
2359 if (ClassReader.ANNOTATIONS && tanns != null) {
2360 out.putShort(cw.newUTF8("RuntimeVisibleTypeAnnotations"));
2361 tanns.put(out);
2362 }
2363 if (ClassReader.ANNOTATIONS && itanns != null) {
2364 out.putShort(cw.newUTF8("RuntimeInvisibleTypeAnnotations"));
2365 itanns.put(out);
2366 }
2367 if (ClassReader.ANNOTATIONS && panns != null) {
2368 out.putShort(cw.newUTF8("RuntimeVisibleParameterAnnotations"));
2369 AnnotationWriter.put(panns, synthetics, out);
2370 }
2371 if (ClassReader.ANNOTATIONS && ipanns != null) {
2372 out.putShort(cw.newUTF8("RuntimeInvisibleParameterAnnotations"));
2373 AnnotationWriter.put(ipanns, synthetics, out);
2374 }
2375 if (attrs != null) {
2376 attrs.put(cw, null, 0, -1, -1, out);
2377 }
2378 }
2379
2380 // ------------------------------------------------------------------------
2381 // Utility methods: instruction resizing (used to handle GOTO_W and JSR_W)
2382 // ------------------------------------------------------------------------
2383
2384 /**
2385 * Resizes and replaces the temporary instructions inserted by
2386 * {@link Label#resolve} for wide forward jumps, while keeping jump offsets
2387 * and instruction addresses consistent. This may require to resize other
2388 * existing instructions, or even to introduce new instructions: for
2389 * example, increasing the size of an instruction by 2 at the middle of a
2390 * method can increases the offset of an IFEQ instruction from 32766 to
2391 * 32768, in which case IFEQ 32766 must be replaced with IFNEQ 8 GOTO_W
2392 * 32765. This, in turn, may require to increase the size of another jump
2393 * instruction, and so on... All these operations are handled automatically
2394 * by this method.
2395 * <p>
2396 * <i>This method must be called after all the method that is being built
2397 * has been visited</i>. In particular, the {@link Label Label} objects used
2398 * to construct the method are no longer valid after this method has been
2399 * called.
2400 */
2401 private void resizeInstructions() {
2402 byte[] b = code.data; // bytecode of the method
2403 int u, v, label; // indexes in b
2404 int i, j; // loop indexes
2405 /*
2406 * 1st step: As explained above, resizing an instruction may require to
2407 * resize another one, which may require to resize yet another one, and
2408 * so on. The first step of the algorithm consists in finding all the
2409 * instructions that need to be resized, without modifying the code.
2410 * This is done by the following "fix point" algorithm:
2411 *
2412 * Parse the code to find the jump instructions whose offset will need
2413 * more than 2 bytes to be stored (the future offset is computed from
2414 * the current offset and from the number of bytes that will be inserted
2415 * or removed between the source and target instructions). For each such
2416 * instruction, adds an entry in (a copy of) the indexes and sizes
2417 * arrays (if this has not already been done in a previous iteration!).
2418 *
2419 * If at least one entry has been added during the previous step, go
2420 * back to the beginning, otherwise stop.
2421 *
2422 * In fact the real algorithm is complicated by the fact that the size
2423 * of TABLESWITCH and LOOKUPSWITCH instructions depends on their
2424 * position in the bytecode (because of padding). In order to ensure the
2425 * convergence of the algorithm, the number of bytes to be added or
2426 * removed from these instructions is over estimated during the previous
2427 * loop, and computed exactly only after the loop is finished (this
2428 * requires another pass to parse the bytecode of the method).
2429 */
2430 int[] allIndexes = new int[0]; // copy of indexes
2431 int[] allSizes = new int[0]; // copy of sizes
2432 boolean[] resize; // instructions to be resized
2433 int newOffset; // future offset of a jump instruction
2434
2435 resize = new boolean[code.length];
2436
2437 // 3 = loop again, 2 = loop ended, 1 = last pass, 0 = done
2438 int state = 3;
2439 do {
2440 if (state == 3) {
2441 state = 2;
2442 }
2443 u = 0;
2444 while (u < b.length) {
2445 int opcode = b[u] & 0xFF; // opcode of current instruction
2446 int insert = 0; // bytes to be added after this instruction
2447
2448 switch (ClassWriter.TYPE[opcode]) {
2449 case ClassWriter.NOARG_INSN:
2450 case ClassWriter.IMPLVAR_INSN:
2451 u += 1;
2452 break;
2453 case ClassWriter.LABEL_INSN:
2454 if (opcode > 201) {
2455 // converts temporary opcodes 202 to 217, 218 and
2456 // 219 to IFEQ ... JSR (inclusive), IFNULL and
2457 // IFNONNULL
2458 opcode = opcode < 218 ? opcode - 49 : opcode - 20;
2459 label = u + readUnsignedShort(b, u + 1);
2460 } else {
2461 label = u + readShort(b, u + 1);
2462 }
2463 newOffset = getNewOffset(allIndexes, allSizes, u, label);
2464 if (newOffset < Short.MIN_VALUE
2465 || newOffset > Short.MAX_VALUE) {
2466 if (!resize[u]) {
2467 if (opcode == Opcodes.GOTO || opcode == Opcodes.JSR) {
2468 // two additional bytes will be required to
2469 // replace this GOTO or JSR instruction with
2470 // a GOTO_W or a JSR_W
2471 insert = 2;
2472 } else {
2473 // five additional bytes will be required to
2474 // replace this IFxxx <l> instruction with
2475 // IFNOTxxx <l'> GOTO_W <l>, where IFNOTxxx
2476 // is the "opposite" opcode of IFxxx (i.e.,
2477 // IFNE for IFEQ) and where <l'> designates
2478 // the instruction just after the GOTO_W.
2479 insert = 5;
2480 }
2481 resize[u] = true;
2482 }
2483 }
2484 u += 3;
2485 break;
2486 case ClassWriter.LABELW_INSN:
2487 u += 5;
2488 break;
2489 case ClassWriter.TABL_INSN:
2490 if (state == 1) {
2491 // true number of bytes to be added (or removed)
2492 // from this instruction = (future number of padding
2493 // bytes - current number of padding byte) -
2494 // previously over estimated variation =
2495 // = ((3 - newOffset%4) - (3 - u%4)) - u%4
2496 // = (-newOffset%4 + u%4) - u%4
2497 // = -(newOffset & 3)
2498 newOffset = getNewOffset(allIndexes, allSizes, 0, u);
2499 insert = -(newOffset & 3);
2500 } else if (!resize[u]) {
2501 // over estimation of the number of bytes to be
2502 // added to this instruction = 3 - current number
2503 // of padding bytes = 3 - (3 - u%4) = u%4 = u & 3
2504 insert = u & 3;
2505 resize[u] = true;
2506 }
2507 // skips instruction
2508 u = u + 4 - (u & 3);
2509 u += 4 * (readInt(b, u + 8) - readInt(b, u + 4) + 1) + 12;
2510 break;
2511 case ClassWriter.LOOK_INSN:
2512 if (state == 1) {
2513 // like TABL_INSN
2514 newOffset = getNewOffset(allIndexes, allSizes, 0, u);
2515 insert = -(newOffset & 3);
2516 } else if (!resize[u]) {
2517 // like TABL_INSN
2518 insert = u & 3;
2519 resize[u] = true;
2520 }
2521 // skips instruction
2522 u = u + 4 - (u & 3);
2523 u += 8 * readInt(b, u + 4) + 8;
2524 break;
2525 case ClassWriter.WIDE_INSN:
2526 opcode = b[u + 1] & 0xFF;
2527 if (opcode == Opcodes.IINC) {
2528 u += 6;
2529 } else {
2530 u += 4;
2531 }
2532 break;
2533 case ClassWriter.VAR_INSN:
2534 case ClassWriter.SBYTE_INSN:
2535 case ClassWriter.LDC_INSN:
2536 u += 2;
2537 break;
2538 case ClassWriter.SHORT_INSN:
2539 case ClassWriter.LDCW_INSN:
2540 case ClassWriter.FIELDORMETH_INSN:
2541 case ClassWriter.TYPE_INSN:
2542 case ClassWriter.IINC_INSN:
2543 u += 3;
2544 break;
2545 case ClassWriter.ITFMETH_INSN:
2546 case ClassWriter.INDYMETH_INSN:
2547 u += 5;
2548 break;
2549 // case ClassWriter.MANA_INSN:
2550 default:
2551 u += 4;
2552 break;
2553 }
2554 if (insert != 0) {
2555 // adds a new (u, insert) entry in the allIndexes and
2556 // allSizes arrays
2557 int[] newIndexes = new int[allIndexes.length + 1];
2558 int[] newSizes = new int[allSizes.length + 1];
2559 System.arraycopy(allIndexes, 0, newIndexes, 0,
2560 allIndexes.length);
2561 System.arraycopy(allSizes, 0, newSizes, 0, allSizes.length);
2562 newIndexes[allIndexes.length] = u;
2563 newSizes[allSizes.length] = insert;
2564 allIndexes = newIndexes;
2565 allSizes = newSizes;
2566 if (insert > 0) {
2567 state = 3;
2568 }
2569 }
2570 }
2571 if (state < 3) {
2572 --state;
2573 }
2574 } while (state != 0);
2575
2576 // 2nd step:
2577 // copies the bytecode of the method into a new bytevector, updates the
2578 // offsets, and inserts (or removes) bytes as requested.
2579
2580 ByteVector newCode = new ByteVector(code.length);
2581
2582 u = 0;
2583 while (u < code.length) {
2584 int opcode = b[u] & 0xFF;
2585 switch (ClassWriter.TYPE[opcode]) {
2586 case ClassWriter.NOARG_INSN:
2587 case ClassWriter.IMPLVAR_INSN:
2588 newCode.putByte(opcode);
2589 u += 1;
2590 break;
2591 case ClassWriter.LABEL_INSN:
2592 if (opcode > 201) {
2593 // changes temporary opcodes 202 to 217 (inclusive), 218
2594 // and 219 to IFEQ ... JSR (inclusive), IFNULL and
2595 // IFNONNULL
2596 opcode = opcode < 218 ? opcode - 49 : opcode - 20;
2597 label = u + readUnsignedShort(b, u + 1);
2598 } else {
2599 label = u + readShort(b, u + 1);
2600 }
2601 newOffset = getNewOffset(allIndexes, allSizes, u, label);
2602 if (resize[u]) {
2603 // replaces GOTO with GOTO_W, JSR with JSR_W and IFxxx
2604 // <l> with IFNOTxxx <l'> GOTO_W <l>, where IFNOTxxx is
2605 // the "opposite" opcode of IFxxx (i.e., IFNE for IFEQ)
2606 // and where <l'> designates the instruction just after
2607 // the GOTO_W.
2608 if (opcode == Opcodes.GOTO) {
2609 newCode.putByte(200); // GOTO_W
2610 } else if (opcode == Opcodes.JSR) {
2611 newCode.putByte(201); // JSR_W
2612 } else {
2613 newCode.putByte(opcode <= 166 ? ((opcode + 1) ^ 1) - 1
2614 : opcode ^ 1);
2615 newCode.putShort(8); // jump offset
2616 newCode.putByte(200); // GOTO_W
2617 // newOffset now computed from start of GOTO_W
2618 newOffset -= 3;
2619 }
2620 newCode.putInt(newOffset);
2621 } else {
2622 newCode.putByte(opcode);
2623 newCode.putShort(newOffset);
2624 }
2625 u += 3;
2626 break;
2627 case ClassWriter.LABELW_INSN:
2628 label = u + readInt(b, u + 1);
2629 newOffset = getNewOffset(allIndexes, allSizes, u, label);
2630 newCode.putByte(opcode);
2631 newCode.putInt(newOffset);
2632 u += 5;
2633 break;
2634 case ClassWriter.TABL_INSN:
2635 // skips 0 to 3 padding bytes
2636 v = u;
2637 u = u + 4 - (v & 3);
2638 // reads and copies instruction
2639 newCode.putByte(Opcodes.TABLESWITCH);
2640 newCode.putByteArray(null, 0, (4 - newCode.length % 4) % 4);
2641 label = v + readInt(b, u);
2642 u += 4;
2643 newOffset = getNewOffset(allIndexes, allSizes, v, label);
2644 newCode.putInt(newOffset);
2645 j = readInt(b, u);
2646 u += 4;
2647 newCode.putInt(j);
2648 j = readInt(b, u) - j + 1;
2649 u += 4;
2650 newCode.putInt(readInt(b, u - 4));
2651 for (; j > 0; --j) {
2652 label = v + readInt(b, u);
2653 u += 4;
2654 newOffset = getNewOffset(allIndexes, allSizes, v, label);
2655 newCode.putInt(newOffset);
2656 }
2657 break;
2658 case ClassWriter.LOOK_INSN:
2659 // skips 0 to 3 padding bytes
2660 v = u;
2661 u = u + 4 - (v & 3);
2662 // reads and copies instruction
2663 newCode.putByte(Opcodes.LOOKUPSWITCH);
2664 newCode.putByteArray(null, 0, (4 - newCode.length % 4) % 4);
2665 label = v + readInt(b, u);
2666 u += 4;
2667 newOffset = getNewOffset(allIndexes, allSizes, v, label);
2668 newCode.putInt(newOffset);
2669 j = readInt(b, u);
2670 u += 4;
2671 newCode.putInt(j);
2672 for (; j > 0; --j) {
2673 newCode.putInt(readInt(b, u));
2674 u += 4;
2675 label = v + readInt(b, u);
2676 u += 4;
2677 newOffset = getNewOffset(allIndexes, allSizes, v, label);
2678 newCode.putInt(newOffset);
2679 }
2680 break;
2681 case ClassWriter.WIDE_INSN:
2682 opcode = b[u + 1] & 0xFF;
2683 if (opcode == Opcodes.IINC) {
2684 newCode.putByteArray(b, u, 6);
2685 u += 6;
2686 } else {
2687 newCode.putByteArray(b, u, 4);
2688 u += 4;
2689 }
2690 break;
2691 case ClassWriter.VAR_INSN:
2692 case ClassWriter.SBYTE_INSN:
2693 case ClassWriter.LDC_INSN:
2694 newCode.putByteArray(b, u, 2);
2695 u += 2;
2696 break;
2697 case ClassWriter.SHORT_INSN:
2698 case ClassWriter.LDCW_INSN:
2699 case ClassWriter.FIELDORMETH_INSN:
2700 case ClassWriter.TYPE_INSN:
2701 case ClassWriter.IINC_INSN:
2702 newCode.putByteArray(b, u, 3);
2703 u += 3;
2704 break;
2705 case ClassWriter.ITFMETH_INSN:
2706 case ClassWriter.INDYMETH_INSN:
2707 newCode.putByteArray(b, u, 5);
2708 u += 5;
2709 break;
2710 // case MANA_INSN:
2711 default:
2712 newCode.putByteArray(b, u, 4);
2713 u += 4;
2714 break;
2715 }
2716 }
2717
2718 // updates the stack map frame labels
2719 if (compute == FRAMES) {
2720 Label l = labels;
2721 while (l != null) {
2722 /*
2723 * Detects the labels that are just after an IF instruction that
2724 * has been resized with the IFNOT GOTO_W pattern. These labels
2725 * are now the target of a jump instruction (the IFNOT
2726 * instruction). Note that we need the original label position
2727 * here. getNewOffset must therefore never have been called for
2728 * this label.
2729 */
2730 u = l.position - 3;
2731 if (u >= 0 && resize[u]) {
2732 l.status |= Label.TARGET;
2733 }
2734 getNewOffset(allIndexes, allSizes, l);
2735 l = l.successor;
2736 }
2737 // Update the offsets in the uninitialized types
2738 if (cw.typeTable != null) {
2739 for (i = 0; i < cw.typeTable.length; ++i) {
2740 Item item = cw.typeTable[i];
2741 if (item != null && item.type == ClassWriter.TYPE_UNINIT) {
2742 item.intVal = getNewOffset(allIndexes, allSizes, 0,
2743 item.intVal);
2744 }
2745 }
2746 }
2747 // The stack map frames are not serialized yet, so we don't need
2748 // to update them. They will be serialized in visitMaxs.
2749 } else if (frameCount > 0) {
2750 /*
2751 * Resizing an existing stack map frame table is really hard. Not
2752 * only the table must be parsed to update the offets, but new
2753 * frames may be needed for jump instructions that were inserted by
2754 * this method. And updating the offsets or inserting frames can
2755 * change the format of the following frames, in case of packed
2756 * frames. In practice the whole table must be recomputed. For this
2757 * the frames are marked as potentially invalid. This will cause the
2758 * whole class to be reread and rewritten with the COMPUTE_FRAMES
2759 * option (see the ClassWriter.toByteArray method). This is not very
2760 * efficient but is much easier and requires much less code than any
2761 * other method I can think of.
2762 */
2763 cw.invalidFrames = true;
2764 }
2765 // updates the exception handler block labels
2766 Handler h = firstHandler;
2767 while (h != null) {
2768 getNewOffset(allIndexes, allSizes, h.start);
2769 getNewOffset(allIndexes, allSizes, h.end);
2770 getNewOffset(allIndexes, allSizes, h.handler);
2771 h = h.next;
2772 }
2773 // updates the instructions addresses in the
2774 // local var and line number tables
2775 for (i = 0; i < 2; ++i) {
2776 ByteVector bv = i == 0 ? localVar : localVarType;
2777 if (bv != null) {
2778 b = bv.data;
2779 u = 0;
2780 while (u < bv.length) {
2781 label = readUnsignedShort(b, u);
2782 newOffset = getNewOffset(allIndexes, allSizes, 0, label);
2783 writeShort(b, u, newOffset);
2784 label += readUnsignedShort(b, u + 2);
2785 newOffset = getNewOffset(allIndexes, allSizes, 0, label)
2786 - newOffset;
2787 writeShort(b, u + 2, newOffset);
2788 u += 10;
2789 }
2790 }
2791 }
2792 if (lineNumber != null) {
2793 b = lineNumber.data;
2794 u = 0;
2795 while (u < lineNumber.length) {
2796 writeShort(
2797 b,
2798 u,
2799 getNewOffset(allIndexes, allSizes, 0,
2800 readUnsignedShort(b, u)));
2801 u += 4;
2802 }
2803 }
2804 // updates the labels of the other attributes
2805 Attribute attr = cattrs;
2806 while (attr != null) {
2807 Label[] labels = attr.getLabels();
2808 if (labels != null) {
2809 for (i = labels.length - 1; i >= 0; --i) {
2810 getNewOffset(allIndexes, allSizes, labels[i]);
2811 }
2812 }
2813 attr = attr.next;
2814 }
2815
2816 // replaces old bytecodes with new ones
2817 code = newCode;
2818 }
2819
2820 /**
2821 * Reads an unsigned short value in the given byte array.
2822 *
2823 * @param b
2824 * a byte array.
2825 * @param index
2826 * the start index of the value to be read.
2827 * @return the read value.
2828 */
2829 static int readUnsignedShort(final byte[] b, final int index) {
2830 return ((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF);
2831 }
2832
2833 /**
2834 * Reads a signed short value in the given byte array.
2835 *
2836 * @param b
2837 * a byte array.
2838 * @param index
2839 * the start index of the value to be read.
2840 * @return the read value.
2841 */
2842 static short readShort(final byte[] b, final int index) {
2843 return (short) (((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF));
2844 }
2845
2846 /**
2847 * Reads a signed int value in the given byte array.
2848 *
2849 * @param b
2850 * a byte array.
2851 * @param index
2852 * the start index of the value to be read.
2853 * @return the read value.
2854 */
2855 static int readInt(final byte[] b, final int index) {
2856 return ((b[index] & 0xFF) << 24) | ((b[index + 1] & 0xFF) << 16)
2857 | ((b[index + 2] & 0xFF) << 8) | (b[index + 3] & 0xFF);
2858 }
2859
2860 /**
2861 * Writes a short value in the given byte array.
2862 *
2863 * @param b
2864 * a byte array.
2865 * @param index
2866 * where the first byte of the short value must be written.
2867 * @param s
2868 * the value to be written in the given byte array.
2869 */
2870 static void writeShort(final byte[] b, final int index, final int s) {
2871 b[index] = (byte) (s >>> 8);
2872 b[index + 1] = (byte) s;
2873 }
2874
2875 /**
2876 * Computes the future value of a bytecode offset.
2877 * <p>
2878 * Note: it is possible to have several entries for the same instruction in
2879 * the <tt>indexes</tt> and <tt>sizes</tt>: two entries (index=a,size=b) and
2880 * (index=a,size=b') are equivalent to a single entry (index=a,size=b+b').
2881 *
2882 * @param indexes
2883 * current positions of the instructions to be resized. Each
2884 * instruction must be designated by the index of its <i>last</i>
2885 * byte, plus one (or, in other words, by the index of the
2886 * <i>first</i> byte of the <i>next</i> instruction).
2887 * @param sizes
2888 * the number of bytes to be <i>added</i> to the above
2889 * instructions. More precisely, for each i < <tt>len</tt>,
2890 * <tt>sizes</tt>[i] bytes will be added at the end of the
2891 * instruction designated by <tt>indexes</tt>[i] or, if
2892 * <tt>sizes</tt>[i] is negative, the <i>last</i> |
2893 * <tt>sizes[i]</tt>| bytes of the instruction will be removed
2894 * (the instruction size <i>must not</i> become negative or
2895 * null).
2896 * @param begin
2897 * index of the first byte of the source instruction.
2898 * @param end
2899 * index of the first byte of the target instruction.
2900 * @return the future value of the given bytecode offset.
2901 */
2902 static int getNewOffset(final int[] indexes, final int[] sizes,
2903 final int begin, final int end) {
2904 int offset = end - begin;
2905 for (int i = 0; i < indexes.length; ++i) {
2906 if (begin < indexes[i] && indexes[i] <= end) {
2907 // forward jump
2908 offset += sizes[i];
2909 } else if (end < indexes[i] && indexes[i] <= begin) {
2910 // backward jump
2911 offset -= sizes[i];
2912 }
2913 }
2914 return offset;
2915 }
2916
2917 /**
2918 * Updates the offset of the given label.
2919 *
2920 * @param indexes
2921 * current positions of the instructions to be resized. Each
2922 * instruction must be designated by the index of its <i>last</i>
2923 * byte, plus one (or, in other words, by the index of the
2924 * <i>first</i> byte of the <i>next</i> instruction).
2925 * @param sizes
2926 * the number of bytes to be <i>added</i> to the above
2927 * instructions. More precisely, for each i < <tt>len</tt>,
2928 * <tt>sizes</tt>[i] bytes will be added at the end of the
2929 * instruction designated by <tt>indexes</tt>[i] or, if
2930 * <tt>sizes</tt>[i] is negative, the <i>last</i> |
2931 * <tt>sizes[i]</tt>| bytes of the instruction will be removed
2932 * (the instruction size <i>must not</i> become negative or
2933 * null).
2934 * @param label
2935 * the label whose offset must be updated.
2936 */
2937 static void getNewOffset(final int[] indexes, final int[] sizes,
2938 final Label label) {
2939 if ((label.status & Label.RESIZED) == 0) {
2940 label.position = getNewOffset(indexes, sizes, 0, label.position);
2941 label.status |= Label.RESIZED;
2942 }
2943 }
2944 }
|
111
112 /**
113 * Frame where current locals are the same as the locals in the previous
114 * frame, except that k additional locals are defined. The value of k is
115 * given by the formula frame_type-251.
116 */
117 static final int APPEND_FRAME = 252; // to 254 // fc-fe
118
119 /**
120 * Full frame
121 */
122 static final int FULL_FRAME = 255; // ff
123
124 /**
125 * Indicates that the stack map frames must be recomputed from scratch. In
126 * this case the maximum stack size and number of local variables is also
127 * recomputed from scratch.
128 *
129 * @see #compute
130 */
131 static final int FRAMES = 0;
132
133 /**
134 * Indicates that the stack map frames of type F_INSERT must be computed.
135 * The other frames are not (re)computed. They should all be of type F_NEW
136 * and should be sufficient to compute the content of the F_INSERT frames,
137 * together with the bytecode instructions between a F_NEW and a F_INSERT
138 * frame - and without any knowledge of the type hierarchy (by definition of
139 * F_INSERT).
140 *
141 * @see #compute
142 */
143 static final int INSERTED_FRAMES = 1;
144
145 /**
146 * Indicates that the maximum stack size and number of local variables must
147 * be automatically computed.
148 *
149 * @see #compute
150 */
151 static final int MAXS = 2;
152
153 /**
154 * Indicates that nothing must be automatically computed.
155 *
156 * @see #compute
157 */
158 static final int NOTHING = 3;
159
160 /**
161 * The class writer to which this method must be added.
162 */
163 final ClassWriter cw;
164
165 /**
166 * Access flags of this method.
167 */
168 private int access;
169
170 /**
171 * The index of the constant pool item that contains the name of this
172 * method.
173 */
174 private final int name;
175
176 /**
177 * The index of the constant pool item that contains the descriptor of this
178 * method.
272 private ByteVector code = new ByteVector();
273
274 /**
275 * Maximum stack size of this method.
276 */
277 private int maxStack;
278
279 /**
280 * Maximum number of local variables for this method.
281 */
282 private int maxLocals;
283
284 /**
285 * Number of local variables in the current stack map frame.
286 */
287 private int currentLocals;
288
289 /**
290 * Number of stack map frames in the StackMapTable attribute.
291 */
292 int frameCount;
293
294 /**
295 * The StackMapTable attribute.
296 */
297 private ByteVector stackMap;
298
299 /**
300 * The offset of the last frame that was written in the StackMapTable
301 * attribute.
302 */
303 private int previousFrameOffset;
304
305 /**
306 * The last frame that was written in the StackMapTable attribute.
307 *
308 * @see #frame
309 */
310 private int[] previousFrame;
311
312 /**
379 * The start offset of the last visited instruction.
380 */
381 private int lastCodeOffset;
382
383 /**
384 * The runtime visible type annotations of the code. May be <tt>null</tt>.
385 */
386 private AnnotationWriter ctanns;
387
388 /**
389 * The runtime invisible type annotations of the code. May be <tt>null</tt>.
390 */
391 private AnnotationWriter ictanns;
392
393 /**
394 * The non standard attributes of the method's code.
395 */
396 private Attribute cattrs;
397
398 /**
399 * The number of subroutines in this method.
400 */
401 private int subroutines;
402
403 // ------------------------------------------------------------------------
404
405 /*
406 * Fields for the control flow graph analysis algorithm (used to compute the
407 * maximum stack size). A control flow graph contains one node per "basic
408 * block", and one edge per "jump" from one basic block to another. Each
409 * node (i.e., each basic block) is represented by the Label object that
410 * corresponds to the first instruction of this basic block. Each node also
411 * stores the list of its successors in the graph, as a linked list of Edge
412 * objects.
413 */
414
415 /**
416 * Indicates what must be automatically computed.
417 *
418 * @see #FRAMES
419 * @see #INSERTED_FRAMES
420 * @see #MAXS
421 * @see #NOTHING
422 */
423 private final int compute;
424
425 /**
426 * A list of labels. This list is the list of basic blocks in the method,
427 * i.e. a list of Label objects linked to each other by their
428 * {@link Label#successor} field, in the order they are visited by
429 * {@link MethodVisitor#visitLabel}, and starting with the first basic
430 * block.
431 */
432 private Label labels;
433
434 /**
435 * The previous basic block.
436 */
437 private Label previousBlock;
438
439 /**
462 // ------------------------------------------------------------------------
463 // Constructor
464 // ------------------------------------------------------------------------
465
466 /**
467 * Constructs a new {@link MethodWriter}.
468 *
469 * @param cw
470 * the class writer in which the method must be added.
471 * @param access
472 * the method's access flags (see {@link Opcodes}).
473 * @param name
474 * the method's name.
475 * @param desc
476 * the method's descriptor (see {@link Type}).
477 * @param signature
478 * the method's signature. May be <tt>null</tt>.
479 * @param exceptions
480 * the internal names of the method's exceptions. May be
481 * <tt>null</tt>.
482 * @param compute
483 * Indicates what must be automatically computed (see #compute).
484 */
485 MethodWriter(final ClassWriter cw, final int access, final String name,
486 final String desc, final String signature,
487 final String[] exceptions, final int compute) {
488 super(Opcodes.ASM6);
489 if (cw.firstMethod == null) {
490 cw.firstMethod = this;
491 } else {
492 cw.lastMethod.mv = this;
493 }
494 cw.lastMethod = this;
495 this.cw = cw;
496 this.access = access;
497 if ("<init>".equals(name)) {
498 this.access |= ACC_CONSTRUCTOR;
499 }
500 this.name = cw.newUTF8(name);
501 this.desc = cw.newUTF8(desc);
502 this.descriptor = desc;
503 this.signature = signature;
504 if (exceptions != null && exceptions.length > 0) {
505 exceptionCount = exceptions.length;
506 this.exceptions = new int[exceptionCount];
507 for (int i = 0; i < exceptionCount; ++i) {
508 this.exceptions[i] = cw.newClass(exceptions[i]);
509 }
510 }
511 this.compute = compute;
512 if (compute != NOTHING) {
513 // updates maxLocals
514 int size = Type.getArgumentsAndReturnSizes(descriptor) >> 2;
515 if ((access & Opcodes.ACC_STATIC) != 0) {
516 --size;
517 }
518 maxLocals = size;
519 currentLocals = size;
520 // creates and visits the label for the first basic block
521 labels = new Label();
522 labels.status |= Label.PUSHED;
523 visitLabel(labels);
524 }
525 }
526
527 // ------------------------------------------------------------------------
528 // Implementation of the MethodVisitor abstract class
529 // ------------------------------------------------------------------------
530
531 @Override
532 public void visitParameter(String name, int access) {
533 if (methodParameters == null) {
534 methodParameters = new ByteVector();
535 }
536 ++methodParametersCount;
537 methodParameters.putShort((name == null) ? 0 : cw.newUTF8(name))
538 .putShort(access);
539 }
540
541 @Override
542 public AnnotationVisitor visitAnnotationDefault() {
543 annd = new ByteVector();
544 return new AnnotationWriter(cw, false, annd, null, 0);
545 }
546
547 @Override
548 public AnnotationVisitor visitAnnotation(final String desc,
549 final boolean visible) {
550 ByteVector bv = new ByteVector();
551 // write type, and reserve space for values count
552 bv.putShort(cw.newUTF8(desc)).putShort(0);
553 AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2);
554 if (visible) {
555 aw.next = anns;
556 anns = aw;
557 } else {
558 aw.next = ianns;
559 ianns = aw;
560 }
561 return aw;
562 }
563
564 @Override
565 public AnnotationVisitor visitTypeAnnotation(final int typeRef,
566 final TypePath typePath, final String desc, final boolean visible) {
567 ByteVector bv = new ByteVector();
568 // write target_type and target_info
569 AnnotationWriter.putTarget(typeRef, typePath, bv);
570 // write type, and reserve space for values count
571 bv.putShort(cw.newUTF8(desc)).putShort(0);
572 AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv,
573 bv.length - 2);
574 if (visible) {
575 aw.next = tanns;
576 tanns = aw;
577 } else {
578 aw.next = itanns;
579 itanns = aw;
580 }
581 return aw;
582 }
583
584 @Override
585 public AnnotationVisitor visitParameterAnnotation(final int parameter,
586 final String desc, final boolean visible) {
587 ByteVector bv = new ByteVector();
588 if ("Ljava/lang/Synthetic;".equals(desc)) {
589 // workaround for a bug in javac with synthetic parameters
590 // see ClassReader.readParameterAnnotations
591 synthetics = Math.max(synthetics, parameter + 1);
592 return new AnnotationWriter(cw, false, bv, null, 0);
593 }
594 // write type, and reserve space for values count
595 bv.putShort(cw.newUTF8(desc)).putShort(0);
596 AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2);
597 if (visible) {
598 if (panns == null) {
599 panns = new AnnotationWriter[Type.getArgumentTypes(descriptor).length];
600 }
601 aw.next = panns[parameter];
602 panns[parameter] = aw;
603 } else {
604 if (ipanns == null) {
605 ipanns = new AnnotationWriter[Type.getArgumentTypes(descriptor).length];
606 }
611 }
612
613 @Override
614 public void visitAttribute(final Attribute attr) {
615 if (attr.isCodeAttribute()) {
616 attr.next = cattrs;
617 cattrs = attr;
618 } else {
619 attr.next = attrs;
620 attrs = attr;
621 }
622 }
623
624 @Override
625 public void visitCode() {
626 }
627
628 @Override
629 public void visitFrame(final int type, final int nLocal,
630 final Object[] local, final int nStack, final Object[] stack) {
631 if (compute == FRAMES) {
632 return;
633 }
634
635 if (compute == INSERTED_FRAMES) {
636 if (currentBlock.frame == null) {
637 // This should happen only once, for the implicit first frame
638 // (which is explicitly visited in ClassReader if the
639 // EXPAND_ASM_INSNS option is used).
640 currentBlock.frame = new CurrentFrame();
641 currentBlock.frame.owner = currentBlock;
642 currentBlock.frame.initInputFrame(cw, access,
643 Type.getArgumentTypes(descriptor), nLocal);
644 visitImplicitFirstFrame();
645 } else {
646 if (type == Opcodes.F_NEW) {
647 currentBlock.frame.set(cw, nLocal, local, nStack, stack);
648 } else {
649 // In this case type is equal to F_INSERT by hypothesis, and
650 // currentBlock.frame contains the stack map frame at the
651 // current instruction, computed from the last F_NEW frame
652 // and the bytecode instructions in between (via calls to
653 // CurrentFrame#execute).
654 }
655 visitFrame(currentBlock.frame);
656 }
657 } else if (type == Opcodes.F_NEW) {
658 if (previousFrame == null) {
659 visitImplicitFirstFrame();
660 }
661 currentLocals = nLocal;
662 int frameIndex = startFrame(code.length, nLocal, nStack);
663 for (int i = 0; i < nLocal; ++i) {
664 if (local[i] instanceof String) {
665 String desc = Type.getObjectType((String) local[i]).getDescriptor();
666 frame[frameIndex++] = Frame.type(cw, desc);
667 } else if (local[i] instanceof Integer) {
668 frame[frameIndex++] = Frame.BASE | ((Integer) local[i]).intValue();
669 } else {
670 frame[frameIndex++] = Frame.UNINITIALIZED
671 | cw.addUninitializedType("",
672 ((Label) local[i]).position);
673 }
674 }
675 for (int i = 0; i < nStack; ++i) {
676 if (stack[i] instanceof String) {
677 String desc = Type.getObjectType((String) stack[i]).getDescriptor();
678 frame[frameIndex++] = Frame.type(cw, desc);
679 } else if (stack[i] instanceof Integer) {
680 frame[frameIndex++] = Frame.BASE | ((Integer) stack[i]).intValue();
681 } else {
682 frame[frameIndex++] = Frame.UNINITIALIZED
683 | cw.addUninitializedType("",
684 ((Label) stack[i]).position);
685 }
686 }
687 endFrame();
688 } else {
689 int delta;
690 if (stackMap == null) {
691 stackMap = new ByteVector();
692 delta = code.length;
693 } else {
694 delta = code.length - previousFrameOffset - 1;
695 if (delta < 0) {
696 if (type == Opcodes.F_SAME) {
697 return;
698 } else {
699 throw new IllegalStateException();
700 }
741 writeFrameType(stack[0]);
742 break;
743 }
744
745 previousFrameOffset = code.length;
746 ++frameCount;
747 }
748
749 maxStack = Math.max(maxStack, nStack);
750 maxLocals = Math.max(maxLocals, currentLocals);
751 }
752
753 @Override
754 public void visitInsn(final int opcode) {
755 lastCodeOffset = code.length;
756 // adds the instruction to the bytecode of the method
757 code.putByte(opcode);
758 // update currentBlock
759 // Label currentBlock = this.currentBlock;
760 if (currentBlock != null) {
761 if (compute == FRAMES || compute == INSERTED_FRAMES) {
762 currentBlock.frame.execute(opcode, 0, null, null);
763 } else {
764 // updates current and max stack sizes
765 int size = stackSize + Frame.SIZE[opcode];
766 if (size > maxStackSize) {
767 maxStackSize = size;
768 }
769 stackSize = size;
770 }
771 // if opcode == ATHROW or xRETURN, ends current block (no successor)
772 if ((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN)
773 || opcode == Opcodes.ATHROW) {
774 noSuccessor();
775 }
776 }
777 }
778
779 @Override
780 public void visitIntInsn(final int opcode, final int operand) {
781 lastCodeOffset = code.length;
782 // Label currentBlock = this.currentBlock;
783 if (currentBlock != null) {
784 if (compute == FRAMES || compute == INSERTED_FRAMES) {
785 currentBlock.frame.execute(opcode, operand, null, null);
786 } else if (opcode != Opcodes.NEWARRAY) {
787 // updates current and max stack sizes only for NEWARRAY
788 // (stack size variation = 0 for BIPUSH or SIPUSH)
789 int size = stackSize + 1;
790 if (size > maxStackSize) {
791 maxStackSize = size;
792 }
793 stackSize = size;
794 }
795 }
796 // adds the instruction to the bytecode of the method
797 if (opcode == Opcodes.SIPUSH) {
798 code.put12(opcode, operand);
799 } else { // BIPUSH or NEWARRAY
800 code.put11(opcode, operand);
801 }
802 }
803
804 @Override
805 public void visitVarInsn(final int opcode, final int var) {
806 lastCodeOffset = code.length;
807 // Label currentBlock = this.currentBlock;
808 if (currentBlock != null) {
809 if (compute == FRAMES || compute == INSERTED_FRAMES) {
810 currentBlock.frame.execute(opcode, var, null, null);
811 } else {
812 // updates current and max stack sizes
813 if (opcode == Opcodes.RET) {
814 // no stack change, but end of current block (no successor)
815 currentBlock.status |= Label.RET;
816 // save 'stackSize' here for future use
817 // (see {@link #findSubroutineSuccessors})
818 currentBlock.inputStackTop = stackSize;
819 noSuccessor();
820 } else { // xLOAD or xSTORE
821 int size = stackSize + Frame.SIZE[opcode];
822 if (size > maxStackSize) {
823 maxStackSize = size;
824 }
825 stackSize = size;
826 }
827 }
828 }
829 if (compute != NOTHING) {
846 /* ILOAD_0 */
847 opt = 26 + ((opcode - Opcodes.ILOAD) << 2) + var;
848 } else {
849 /* ISTORE_0 */
850 opt = 59 + ((opcode - Opcodes.ISTORE) << 2) + var;
851 }
852 code.putByte(opt);
853 } else if (var >= 256) {
854 code.putByte(196 /* WIDE */).put12(opcode, var);
855 } else {
856 code.put11(opcode, var);
857 }
858 if (opcode >= Opcodes.ISTORE && compute == FRAMES && handlerCount > 0) {
859 visitLabel(new Label());
860 }
861 }
862
863 @Override
864 public void visitTypeInsn(final int opcode, final String type) {
865 lastCodeOffset = code.length;
866 Item i = cw.newStringishItem(ClassWriter.CLASS, type);
867 // Label currentBlock = this.currentBlock;
868 if (currentBlock != null) {
869 if (compute == FRAMES || compute == INSERTED_FRAMES) {
870 currentBlock.frame.execute(opcode, code.length, cw, i);
871 } else if (opcode == Opcodes.NEW) {
872 // updates current and max stack sizes only if opcode == NEW
873 // (no stack change for ANEWARRAY, CHECKCAST, INSTANCEOF)
874 int size = stackSize + 1;
875 if (size > maxStackSize) {
876 maxStackSize = size;
877 }
878 stackSize = size;
879 }
880 }
881 // adds the instruction to the bytecode of the method
882 code.put12(opcode, i.index);
883 }
884
885 @Override
886 public void visitFieldInsn(final int opcode, final String owner,
887 final String name, final String desc) {
888 lastCodeOffset = code.length;
889 Item i = cw.newFieldItem(owner, name, desc);
890 // Label currentBlock = this.currentBlock;
891 if (currentBlock != null) {
892 if (compute == FRAMES || compute == INSERTED_FRAMES) {
893 currentBlock.frame.execute(opcode, 0, cw, i);
894 } else {
895 int size;
896 // computes the stack size variation
897 char c = desc.charAt(0);
898 switch (opcode) {
899 case Opcodes.GETSTATIC:
900 size = stackSize + (c == 'D' || c == 'J' ? 2 : 1);
901 break;
902 case Opcodes.PUTSTATIC:
903 size = stackSize + (c == 'D' || c == 'J' ? -2 : -1);
904 break;
905 case Opcodes.GETFIELD:
906 size = stackSize + (c == 'D' || c == 'J' ? 1 : 0);
907 break;
908 // case Constants.PUTFIELD:
909 default:
910 size = stackSize + (c == 'D' || c == 'J' ? -3 : -2);
911 break;
912 }
913 // updates current and max stack sizes
914 if (size > maxStackSize) {
915 maxStackSize = size;
916 }
917 stackSize = size;
918 }
919 }
920 // adds the instruction to the bytecode of the method
921 code.put12(opcode, i.index);
922 }
923
924 @Override
925 public void visitMethodInsn(final int opcode, final String owner,
926 final String name, final String desc, final boolean itf) {
927 lastCodeOffset = code.length;
928 Item i = cw.newMethodItem(owner, name, desc, itf);
929 int argSize = i.intVal;
930 // Label currentBlock = this.currentBlock;
931 if (currentBlock != null) {
932 if (compute == FRAMES || compute == INSERTED_FRAMES) {
933 currentBlock.frame.execute(opcode, 0, cw, i);
934 } else {
935 /*
936 * computes the stack size variation. In order not to recompute
937 * several times this variation for the same Item, we use the
938 * intVal field of this item to store this variation, once it
939 * has been computed. More precisely this intVal field stores
940 * the sizes of the arguments and of the return value
941 * corresponding to desc.
942 */
943 if (argSize == 0) {
944 // the above sizes have not been computed yet,
945 // so we compute them...
946 argSize = Type.getArgumentsAndReturnSizes(desc);
947 // ... and we save them in order
948 // not to recompute them in the future
949 i.intVal = argSize;
950 }
951 int size;
952 if (opcode == Opcodes.INVOKESTATIC) {
964 // adds the instruction to the bytecode of the method
965 if (opcode == Opcodes.INVOKEINTERFACE) {
966 if (argSize == 0) {
967 argSize = Type.getArgumentsAndReturnSizes(desc);
968 i.intVal = argSize;
969 }
970 code.put12(Opcodes.INVOKEINTERFACE, i.index).put11(argSize >> 2, 0);
971 } else {
972 code.put12(opcode, i.index);
973 }
974 }
975
976 @Override
977 public void visitInvokeDynamicInsn(final String name, final String desc,
978 final Handle bsm, final Object... bsmArgs) {
979 lastCodeOffset = code.length;
980 Item i = cw.newInvokeDynamicItem(name, desc, bsm, bsmArgs);
981 int argSize = i.intVal;
982 // Label currentBlock = this.currentBlock;
983 if (currentBlock != null) {
984 if (compute == FRAMES || compute == INSERTED_FRAMES) {
985 currentBlock.frame.execute(Opcodes.INVOKEDYNAMIC, 0, cw, i);
986 } else {
987 /*
988 * computes the stack size variation. In order not to recompute
989 * several times this variation for the same Item, we use the
990 * intVal field of this item to store this variation, once it
991 * has been computed. More precisely this intVal field stores
992 * the sizes of the arguments and of the return value
993 * corresponding to desc.
994 */
995 if (argSize == 0) {
996 // the above sizes have not been computed yet,
997 // so we compute them...
998 argSize = Type.getArgumentsAndReturnSizes(desc);
999 // ... and we save them in order
1000 // not to recompute them in the future
1001 i.intVal = argSize;
1002 }
1003 int size = stackSize - (argSize >> 2) + (argSize & 0x03) + 1;
1004
1005 // updates current and max stack sizes
1006 if (size > maxStackSize) {
1007 maxStackSize = size;
1008 }
1009 stackSize = size;
1010 }
1011 }
1012 // adds the instruction to the bytecode of the method
1013 code.put12(Opcodes.INVOKEDYNAMIC, i.index);
1014 code.putShort(0);
1015 }
1016
1017 @Override
1018 public void visitJumpInsn(int opcode, final Label label) {
1019 boolean isWide = opcode >= 200; // GOTO_W
1020 opcode = isWide ? opcode - 33 : opcode;
1021 lastCodeOffset = code.length;
1022 Label nextInsn = null;
1023 // Label currentBlock = this.currentBlock;
1024 if (currentBlock != null) {
1025 if (compute == FRAMES) {
1026 currentBlock.frame.execute(opcode, 0, null, null);
1027 // 'label' is the target of a jump instruction
1028 label.getFirst().status |= Label.TARGET;
1029 // adds 'label' as a successor of this basic block
1030 addSuccessor(Edge.NORMAL, label);
1031 if (opcode != Opcodes.GOTO) {
1032 // creates a Label for the next basic block
1033 nextInsn = new Label();
1034 }
1035 } else if (compute == INSERTED_FRAMES) {
1036 currentBlock.frame.execute(opcode, 0, null, null);
1037 } else {
1038 if (opcode == Opcodes.JSR) {
1039 if ((label.status & Label.SUBROUTINE) == 0) {
1040 label.status |= Label.SUBROUTINE;
1041 ++subroutines;
1042 }
1043 currentBlock.status |= Label.JSR;
1044 addSuccessor(stackSize + 1, label);
1045 // creates a Label for the next basic block
1046 nextInsn = new Label();
1047 /*
1048 * note that, by construction in this method, a JSR block
1049 * has at least two successors in the control flow graph:
1050 * the first one leads the next instruction after the JSR,
1051 * while the second one leads to the JSR target.
1052 */
1053 } else {
1054 // updates current stack size (max stack size unchanged
1055 // because stack size variation always negative in this
1056 // case)
1057 stackSize += Frame.SIZE[opcode];
1058 addSuccessor(stackSize, label);
1059 }
1060 }
1061 }
1062 // adds the instruction to the bytecode of the method
1063 if ((label.status & Label.RESOLVED) != 0
1064 && label.position - code.length < Short.MIN_VALUE) {
1065 /*
1066 * case of a backward jump with an offset < -32768. In this case we
1067 * automatically replace GOTO with GOTO_W, JSR with JSR_W and IFxxx
1068 * <l> with IFNOTxxx <L> GOTO_W <l> L:..., where IFNOTxxx is the
1069 * "opposite" opcode of IFxxx (i.e., IFNE for IFEQ) and where <L>
1070 * designates the instruction just after the GOTO_W.
1071 */
1072 if (opcode == Opcodes.GOTO) {
1073 code.putByte(200); // GOTO_W
1074 } else if (opcode == Opcodes.JSR) {
1075 code.putByte(201); // JSR_W
1076 } else {
1077 // if the IF instruction is transformed into IFNOT GOTO_W the
1078 // next instruction becomes the target of the IFNOT instruction
1079 if (nextInsn != null) {
1080 nextInsn.status |= Label.TARGET;
1081 }
1082 code.putByte(opcode <= 166 ? ((opcode + 1) ^ 1) - 1
1083 : opcode ^ 1);
1084 code.putShort(8); // jump offset
1085 // ASM pseudo GOTO_W insn, see ClassReader. We don't use a real
1086 // GOTO_W because we might need to insert a frame just after (as
1087 // the target of the IFNOTxxx jump instruction).
1088 code.putByte(220);
1089 cw.hasAsmInsns = true;
1090 }
1091 label.put(this, code, code.length - 1, true);
1092 } else if (isWide) {
1093 /*
1094 * case of a GOTO_W or JSR_W specified by the user (normally
1095 * ClassReader when used to resize instructions). In this case we
1096 * keep the original instruction.
1097 */
1098 code.putByte(opcode + 33);
1099 label.put(this, code, code.length - 1, true);
1100 } else {
1101 /*
1102 * case of a backward jump with an offset >= -32768, or of a forward
1103 * jump with, of course, an unknown offset. In these cases we store
1104 * the offset in 2 bytes (which will be increased in
1105 * resizeInstructions, if needed).
1106 */
1107 code.putByte(opcode);
1108 label.put(this, code, code.length - 1, false);
1109 }
1110 if (currentBlock != null) {
1111 if (nextInsn != null) {
1112 // if the jump instruction is not a GOTO, the next instruction
1113 // is also a successor of this instruction. Calling visitLabel
1114 // adds the label of this next instruction as a successor of the
1115 // current block, and starts a new basic block
1116 visitLabel(nextInsn);
1117 }
1118 if (opcode == Opcodes.GOTO) {
1119 noSuccessor();
1120 }
1121 }
1122 }
1123
1124 @Override
1125 public void visitLabel(final Label label) {
1126 // resolves previous forward references to label, if any
1127 cw.hasAsmInsns |= label.resolve(this, code.length, code.data);
1128 // updates currentBlock
1129 if ((label.status & Label.DEBUG) != 0) {
1130 return;
1131 }
1132 if (compute == FRAMES) {
1133 if (currentBlock != null) {
1134 if (label.position == currentBlock.position) {
1135 // successive labels, do not start a new basic block
1136 currentBlock.status |= (label.status & Label.TARGET);
1137 label.frame = currentBlock.frame;
1138 return;
1139 }
1140 // ends current block (with one new successor)
1141 addSuccessor(Edge.NORMAL, label);
1142 }
1143 // begins a new current block
1144 currentBlock = label;
1145 if (label.frame == null) {
1146 label.frame = new Frame();
1147 label.frame.owner = label;
1148 }
1149 // updates the basic block list
1150 if (previousBlock != null) {
1151 if (label.position == previousBlock.position) {
1152 previousBlock.status |= (label.status & Label.TARGET);
1153 label.frame = previousBlock.frame;
1154 currentBlock = previousBlock;
1155 return;
1156 }
1157 previousBlock.successor = label;
1158 }
1159 previousBlock = label;
1160 } else if (compute == INSERTED_FRAMES) {
1161 if (currentBlock == null) {
1162 // This case should happen only once, for the visitLabel call in
1163 // the constructor. Indeed, if compute is equal to
1164 // INSERTED_FRAMES currentBlock can not be set back to null (see
1165 // #noSuccessor).
1166 currentBlock = label;
1167 } else {
1168 // Updates the frame owner so that a correct frame offset is
1169 // computed in visitFrame(Frame).
1170 currentBlock.frame.owner = label;
1171 }
1172 } else if (compute == MAXS) {
1173 if (currentBlock != null) {
1174 // ends current block (with one new successor)
1175 currentBlock.outputStackMax = maxStackSize;
1176 addSuccessor(stackSize, label);
1177 }
1178 // begins a new current block
1179 currentBlock = label;
1180 // resets the relative current and max stack sizes
1181 stackSize = 0;
1182 maxStackSize = 0;
1183 // updates the basic block list
1184 if (previousBlock != null) {
1185 previousBlock.successor = label;
1186 }
1187 previousBlock = label;
1188 }
1189 }
1190
1191 @Override
1192 public void visitLdcInsn(final Object cst) {
1193 lastCodeOffset = code.length;
1194 Item i = cw.newConstItem(cst);
1195 // Label currentBlock = this.currentBlock;
1196 if (currentBlock != null) {
1197 if (compute == FRAMES || compute == INSERTED_FRAMES) {
1198 currentBlock.frame.execute(Opcodes.LDC, 0, cw, i);
1199 } else {
1200 int size;
1201 // computes the stack size variation
1202 if (i.type == ClassWriter.LONG || i.type == ClassWriter.DOUBLE) {
1203 size = stackSize + 2;
1204 } else {
1205 size = stackSize + 1;
1206 }
1207 // updates current and max stack sizes
1208 if (size > maxStackSize) {
1209 maxStackSize = size;
1210 }
1211 stackSize = size;
1212 }
1213 }
1214 // adds the instruction to the bytecode of the method
1215 int index = i.index;
1216 if (i.type == ClassWriter.LONG || i.type == ClassWriter.DOUBLE) {
1217 code.put12(20 /* LDC2_W */, index);
1218 } else if (index >= 256) {
1219 code.put12(19 /* LDC_W */, index);
1220 } else {
1221 code.put11(Opcodes.LDC, index);
1222 }
1223 }
1224
1225 @Override
1226 public void visitIincInsn(final int var, final int increment) {
1227 lastCodeOffset = code.length;
1228 if (currentBlock != null) {
1229 if (compute == FRAMES || compute == INSERTED_FRAMES) {
1230 currentBlock.frame.execute(Opcodes.IINC, var, null, null);
1231 }
1232 }
1233 if (compute != NOTHING) {
1234 // updates max locals
1235 int n = var + 1;
1236 if (n > maxLocals) {
1237 maxLocals = n;
1238 }
1239 }
1240 // adds the instruction to the bytecode of the method
1241 if ((var > 255) || (increment > 127) || (increment < -128)) {
1242 code.putByte(196 /* WIDE */).put12(Opcodes.IINC, var)
1243 .putShort(increment);
1244 } else {
1245 code.putByte(Opcodes.IINC).put11(var, increment);
1246 }
1247 }
1248
1249 @Override
1293 addSuccessor(Edge.NORMAL, labels[i]);
1294 labels[i].getFirst().status |= Label.TARGET;
1295 }
1296 } else {
1297 // updates current stack size (max stack size unchanged)
1298 --stackSize;
1299 // adds current block successors
1300 addSuccessor(stackSize, dflt);
1301 for (int i = 0; i < labels.length; ++i) {
1302 addSuccessor(stackSize, labels[i]);
1303 }
1304 }
1305 // ends current block
1306 noSuccessor();
1307 }
1308 }
1309
1310 @Override
1311 public void visitMultiANewArrayInsn(final String desc, final int dims) {
1312 lastCodeOffset = code.length;
1313 Item i = cw.newStringishItem(ClassWriter.CLASS, desc);
1314 // Label currentBlock = this.currentBlock;
1315 if (currentBlock != null) {
1316 if (compute == FRAMES || compute == INSERTED_FRAMES) {
1317 currentBlock.frame.execute(Opcodes.MULTIANEWARRAY, dims, cw, i);
1318 } else {
1319 // updates current stack size (max stack size unchanged because
1320 // stack size variation always negative or null)
1321 stackSize += 1 - dims;
1322 }
1323 }
1324 // adds the instruction to the bytecode of the method
1325 code.put12(Opcodes.MULTIANEWARRAY, i.index).putByte(dims);
1326 }
1327
1328 @Override
1329 public AnnotationVisitor visitInsnAnnotation(int typeRef,
1330 TypePath typePath, String desc, boolean visible) {
1331 ByteVector bv = new ByteVector();
1332 // write target_type and target_info
1333 typeRef = (typeRef & 0xFF0000FF) | (lastCodeOffset << 8);
1334 AnnotationWriter.putTarget(typeRef, typePath, bv);
1335 // write type, and reserve space for values count
1336 bv.putShort(cw.newUTF8(desc)).putShort(0);
1337 AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv,
1338 bv.length - 2);
1339 if (visible) {
1340 aw.next = ctanns;
1341 ctanns = aw;
1342 } else {
1343 aw.next = ictanns;
1344 ictanns = aw;
1345 }
1346 return aw;
1347 }
1348
1349 @Override
1350 public void visitTryCatchBlock(final Label start, final Label end,
1351 final Label handler, final String type) {
1352 ++handlerCount;
1353 Handler h = new Handler();
1354 h.start = start;
1355 h.end = end;
1356 h.handler = handler;
1357 h.desc = type;
1358 h.type = type != null ? cw.newClass(type) : 0;
1359 if (lastHandler == null) {
1360 firstHandler = h;
1361 } else {
1362 lastHandler.next = h;
1363 }
1364 lastHandler = h;
1365 }
1366
1367 @Override
1368 public AnnotationVisitor visitTryCatchAnnotation(int typeRef,
1369 TypePath typePath, String desc, boolean visible) {
1370 ByteVector bv = new ByteVector();
1371 // write target_type and target_info
1372 AnnotationWriter.putTarget(typeRef, typePath, bv);
1373 // write type, and reserve space for values count
1374 bv.putShort(cw.newUTF8(desc)).putShort(0);
1375 AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv,
1376 bv.length - 2);
1377 if (visible) {
1378 aw.next = ctanns;
1379 ctanns = aw;
1380 } else {
1381 aw.next = ictanns;
1382 ictanns = aw;
1383 }
1384 return aw;
1385 }
1386
1387 @Override
1388 public void visitLocalVariable(final String name, final String desc,
1389 final String signature, final Label start, final Label end,
1403 }
1404 ++localVarCount;
1405 localVar.putShort(start.position)
1406 .putShort(end.position - start.position)
1407 .putShort(cw.newUTF8(name)).putShort(cw.newUTF8(desc))
1408 .putShort(index);
1409 if (compute != NOTHING) {
1410 // updates max locals
1411 char c = desc.charAt(0);
1412 int n = index + (c == 'J' || c == 'D' ? 2 : 1);
1413 if (n > maxLocals) {
1414 maxLocals = n;
1415 }
1416 }
1417 }
1418
1419 @Override
1420 public AnnotationVisitor visitLocalVariableAnnotation(int typeRef,
1421 TypePath typePath, Label[] start, Label[] end, int[] index,
1422 String desc, boolean visible) {
1423 ByteVector bv = new ByteVector();
1424 // write target_type and target_info
1425 bv.putByte(typeRef >>> 24).putShort(start.length);
1426 for (int i = 0; i < start.length; ++i) {
1427 bv.putShort(start[i].position)
1428 .putShort(end[i].position - start[i].position)
1429 .putShort(index[i]);
1430 }
1431 if (typePath == null) {
1432 bv.putByte(0);
1433 } else {
1434 int length = typePath.b[typePath.offset] * 2 + 1;
1435 bv.putByteArray(typePath.b, typePath.offset, length);
1436 }
1437 // write type, and reserve space for values count
1438 bv.putShort(cw.newUTF8(desc)).putShort(0);
1439 AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv,
1440 bv.length - 2);
1441 if (visible) {
1442 aw.next = ctanns;
1443 ctanns = aw;
1444 } else {
1445 aw.next = ictanns;
1446 ictanns = aw;
1447 }
1448 return aw;
1449 }
1450
1451 @Override
1452 public void visitLineNumber(final int line, final Label start) {
1453 if (lineNumber == null) {
1454 lineNumber = new ByteVector();
1455 }
1456 ++lineNumberCount;
1457 lineNumber.putShort(start.position);
1458 lineNumber.putShort(line);
1459 }
1460
1461 @Override
1462 public void visitMaxs(final int maxStack, final int maxLocals) {
1463 if (compute == FRAMES) {
1464 // completes the control flow graph with exception handler blocks
1465 Handler handler = firstHandler;
1466 while (handler != null) {
1467 Label l = handler.start.getFirst();
1468 Label h = handler.handler.getFirst();
1469 Label e = handler.end.getFirst();
1470 // computes the kind of the edges to 'h'
1471 String t = handler.desc == null ? "java/lang/Throwable"
1472 : handler.desc;
1473 int kind = Frame.OBJECT | cw.addType(t);
1474 // h is an exception handler
1475 h.status |= Label.TARGET;
1476 // adds 'h' as a successor of labels between 'start' and 'end'
1477 while (l != e) {
1478 // creates an edge to 'h'
1479 Edge b = new Edge();
1480 b.info = kind;
1481 b.successor = h;
1482 // adds it to the successors of 'l'
1483 b.next = l.successors;
1484 l.successors = b;
1485 // goes to the next label
1486 l = l.successor;
1487 }
1488 handler = handler.next;
1489 }
1490
1491 // creates and visits the first (implicit) frame
1492 Frame f = labels.frame;
1493 f.initInputFrame(cw, access, Type.getArgumentTypes(descriptor),
1494 this.maxLocals);
1495 visitFrame(f);
1496
1497 /*
1498 * fix point algorithm: mark the first basic block as 'changed'
1499 * (i.e. put it in the 'changed' list) and, while there are changed
1500 * basic blocks, choose one, mark it as unchanged, and update its
1501 * successors (which can be changed in the process).
1502 */
1503 int max = 0;
1504 Label changed = labels;
1505 while (changed != null) {
1506 // removes a basic block from the list of changed basic blocks
1507 Label l = changed;
1508 changed = changed.next;
1509 l.next = null;
1510 f = l.frame;
1511 // a reachable jump target must be stored in the stack map
1512 if ((l.status & Label.TARGET) != 0) {
1513 l.status |= Label.STORE;
1514 }
1722 // ...and adds it to the successor list of the currentBlock block
1723 b.next = currentBlock.successors;
1724 currentBlock.successors = b;
1725 }
1726
1727 /**
1728 * Ends the current basic block. This method must be used in the case where
1729 * the current basic block does not have any successor.
1730 */
1731 private void noSuccessor() {
1732 if (compute == FRAMES) {
1733 Label l = new Label();
1734 l.frame = new Frame();
1735 l.frame.owner = l;
1736 l.resolve(this, code.length, code.data);
1737 previousBlock.successor = l;
1738 previousBlock = l;
1739 } else {
1740 currentBlock.outputStackMax = maxStackSize;
1741 }
1742 if (compute != INSERTED_FRAMES) {
1743 currentBlock = null;
1744 }
1745 }
1746
1747 // ------------------------------------------------------------------------
1748 // Utility methods: stack map frames
1749 // ------------------------------------------------------------------------
1750
1751 /**
1752 * Visits a frame that has been computed from scratch.
1753 *
1754 * @param f
1755 * the frame that must be visited.
1756 */
1757 private void visitFrame(final Frame f) {
1758 int i, t;
1759 int nTop = 0;
1760 int nLocal = 0;
1761 int nStack = 0;
1762 int[] locals = f.inputLocals;
1763 int[] stacks = f.inputStack;
1764 // computes the number of locals (ignores TOP types that are just after
1765 // a LONG or a DOUBLE, and all trailing TOP types)
1796 for (i = 0; i < stacks.length; ++i) {
1797 t = stacks[i];
1798 frame[frameIndex++] = t;
1799 if (t == Frame.LONG || t == Frame.DOUBLE) {
1800 ++i;
1801 }
1802 }
1803 endFrame();
1804 }
1805
1806 /**
1807 * Visit the implicit first frame of this method.
1808 */
1809 private void visitImplicitFirstFrame() {
1810 // There can be at most descriptor.length() + 1 locals
1811 int frameIndex = startFrame(0, descriptor.length() + 1, 0);
1812 if ((access & Opcodes.ACC_STATIC) == 0) {
1813 if ((access & ACC_CONSTRUCTOR) == 0) {
1814 frame[frameIndex++] = Frame.OBJECT | cw.addType(cw.thisName);
1815 } else {
1816 frame[frameIndex++] = Frame.UNINITIALIZED_THIS;
1817 }
1818 }
1819 int i = 1;
1820 loop: while (true) {
1821 int j = i;
1822 switch (descriptor.charAt(i++)) {
1823 case 'Z':
1824 case 'C':
1825 case 'B':
1826 case 'S':
1827 case 'I':
1828 frame[frameIndex++] = Frame.INTEGER;
1829 break;
1830 case 'F':
1831 frame[frameIndex++] = Frame.FLOAT;
1832 break;
1833 case 'J':
1834 frame[frameIndex++] = Frame.LONG;
1835 break;
1836 case 'D':
1837 frame[frameIndex++] = Frame.DOUBLE;
1838 break;
1839 case '[':
1840 while (descriptor.charAt(i) == '[') {
1841 ++i;
1842 }
1843 if (descriptor.charAt(i) == 'L') {
1844 ++i;
1845 while (descriptor.charAt(i) != ';') {
1846 ++i;
1847 }
1848 }
1849 frame[frameIndex++] = Frame.type(cw, descriptor.substring(j, ++i));
1850 break;
1851 case 'L':
1852 while (descriptor.charAt(i) != ';') {
1853 ++i;
1854 }
1855 frame[frameIndex++] = Frame.OBJECT
1856 | cw.addType(descriptor.substring(j + 1, i++));
1857 break;
1858 default:
1859 break loop;
1860 }
1861 }
1862 frame[1] = frameIndex - 3;
1863 endFrame();
1864 }
1865
1866 /**
1867 * Starts the visit of a stack map frame.
1868 *
1869 * @param offset
2089 }
2090 cw.newUTF8("Code");
2091 size += 18 + code.length + 8 * handlerCount;
2092 if (localVar != null) {
2093 cw.newUTF8("LocalVariableTable");
2094 size += 8 + localVar.length;
2095 }
2096 if (localVarType != null) {
2097 cw.newUTF8("LocalVariableTypeTable");
2098 size += 8 + localVarType.length;
2099 }
2100 if (lineNumber != null) {
2101 cw.newUTF8("LineNumberTable");
2102 size += 8 + lineNumber.length;
2103 }
2104 if (stackMap != null) {
2105 boolean zip = (cw.version & 0xFFFF) >= Opcodes.V1_6;
2106 cw.newUTF8(zip ? "StackMapTable" : "StackMap");
2107 size += 8 + stackMap.length;
2108 }
2109 if (ctanns != null) {
2110 cw.newUTF8("RuntimeVisibleTypeAnnotations");
2111 size += 8 + ctanns.getSize();
2112 }
2113 if (ictanns != null) {
2114 cw.newUTF8("RuntimeInvisibleTypeAnnotations");
2115 size += 8 + ictanns.getSize();
2116 }
2117 if (cattrs != null) {
2118 size += cattrs.getSize(cw, code.data, code.length, maxStack,
2119 maxLocals);
2120 }
2121 }
2122 if (exceptionCount > 0) {
2123 cw.newUTF8("Exceptions");
2124 size += 8 + 2 * exceptionCount;
2125 }
2126 if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
2127 if ((cw.version & 0xFFFF) < Opcodes.V1_5
2128 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) {
2129 cw.newUTF8("Synthetic");
2130 size += 6;
2131 }
2132 }
2133 if ((access & Opcodes.ACC_DEPRECATED) != 0) {
2134 cw.newUTF8("Deprecated");
2135 size += 6;
2136 }
2137 if (signature != null) {
2138 cw.newUTF8("Signature");
2139 cw.newUTF8(signature);
2140 size += 8;
2141 }
2142 if (methodParameters != null) {
2143 cw.newUTF8("MethodParameters");
2144 size += 7 + methodParameters.length;
2145 }
2146 if (annd != null) {
2147 cw.newUTF8("AnnotationDefault");
2148 size += 6 + annd.length;
2149 }
2150 if (anns != null) {
2151 cw.newUTF8("RuntimeVisibleAnnotations");
2152 size += 8 + anns.getSize();
2153 }
2154 if (ianns != null) {
2155 cw.newUTF8("RuntimeInvisibleAnnotations");
2156 size += 8 + ianns.getSize();
2157 }
2158 if (tanns != null) {
2159 cw.newUTF8("RuntimeVisibleTypeAnnotations");
2160 size += 8 + tanns.getSize();
2161 }
2162 if (itanns != null) {
2163 cw.newUTF8("RuntimeInvisibleTypeAnnotations");
2164 size += 8 + itanns.getSize();
2165 }
2166 if (panns != null) {
2167 cw.newUTF8("RuntimeVisibleParameterAnnotations");
2168 size += 7 + 2 * (panns.length - synthetics);
2169 for (int i = panns.length - 1; i >= synthetics; --i) {
2170 size += panns[i] == null ? 0 : panns[i].getSize();
2171 }
2172 }
2173 if (ipanns != null) {
2174 cw.newUTF8("RuntimeInvisibleParameterAnnotations");
2175 size += 7 + 2 * (ipanns.length - synthetics);
2176 for (int i = ipanns.length - 1; i >= synthetics; --i) {
2177 size += ipanns[i] == null ? 0 : ipanns[i].getSize();
2178 }
2179 }
2180 if (attrs != null) {
2181 size += attrs.getSize(cw, null, 0, -1, -1);
2182 }
2183 return size;
2184 }
2185
2186 /**
2187 * Puts the bytecode of this method in the given byte vector.
2188 *
2189 * @param out
2190 * the byte vector into which the bytecode of this method must be
2191 * copied.
2192 */
2193 final void put(final ByteVector out) {
2199 if (classReaderOffset != 0) {
2200 out.putByteArray(cw.cr.b, classReaderOffset, classReaderLength);
2201 return;
2202 }
2203 int attributeCount = 0;
2204 if (code.length > 0) {
2205 ++attributeCount;
2206 }
2207 if (exceptionCount > 0) {
2208 ++attributeCount;
2209 }
2210 if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
2211 if ((cw.version & 0xFFFF) < Opcodes.V1_5
2212 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) {
2213 ++attributeCount;
2214 }
2215 }
2216 if ((access & Opcodes.ACC_DEPRECATED) != 0) {
2217 ++attributeCount;
2218 }
2219 if (signature != null) {
2220 ++attributeCount;
2221 }
2222 if (methodParameters != null) {
2223 ++attributeCount;
2224 }
2225 if (annd != null) {
2226 ++attributeCount;
2227 }
2228 if (anns != null) {
2229 ++attributeCount;
2230 }
2231 if (ianns != null) {
2232 ++attributeCount;
2233 }
2234 if (tanns != null) {
2235 ++attributeCount;
2236 }
2237 if (itanns != null) {
2238 ++attributeCount;
2239 }
2240 if (panns != null) {
2241 ++attributeCount;
2242 }
2243 if (ipanns != null) {
2244 ++attributeCount;
2245 }
2246 if (attrs != null) {
2247 attributeCount += attrs.getCount();
2248 }
2249 out.putShort(attributeCount);
2250 if (code.length > 0) {
2251 int size = 12 + code.length + 8 * handlerCount;
2252 if (localVar != null) {
2253 size += 8 + localVar.length;
2254 }
2255 if (localVarType != null) {
2256 size += 8 + localVarType.length;
2257 }
2258 if (lineNumber != null) {
2259 size += 8 + lineNumber.length;
2260 }
2261 if (stackMap != null) {
2262 size += 8 + stackMap.length;
2263 }
2264 if (ctanns != null) {
2265 size += 8 + ctanns.getSize();
2266 }
2267 if (ictanns != null) {
2268 size += 8 + ictanns.getSize();
2269 }
2270 if (cattrs != null) {
2271 size += cattrs.getSize(cw, code.data, code.length, maxStack,
2272 maxLocals);
2273 }
2274 out.putShort(cw.newUTF8("Code")).putInt(size);
2275 out.putShort(maxStack).putShort(maxLocals);
2276 out.putInt(code.length).putByteArray(code.data, 0, code.length);
2277 out.putShort(handlerCount);
2278 if (handlerCount > 0) {
2279 Handler h = firstHandler;
2280 while (h != null) {
2281 out.putShort(h.start.position).putShort(h.end.position)
2282 .putShort(h.handler.position).putShort(h.type);
2283 h = h.next;
2284 }
2285 }
2286 attributeCount = 0;
2287 if (localVar != null) {
2288 ++attributeCount;
2289 }
2290 if (localVarType != null) {
2291 ++attributeCount;
2292 }
2293 if (lineNumber != null) {
2294 ++attributeCount;
2295 }
2296 if (stackMap != null) {
2297 ++attributeCount;
2298 }
2299 if (ctanns != null) {
2300 ++attributeCount;
2301 }
2302 if (ictanns != null) {
2303 ++attributeCount;
2304 }
2305 if (cattrs != null) {
2306 attributeCount += cattrs.getCount();
2307 }
2308 out.putShort(attributeCount);
2309 if (localVar != null) {
2310 out.putShort(cw.newUTF8("LocalVariableTable"));
2311 out.putInt(localVar.length + 2).putShort(localVarCount);
2312 out.putByteArray(localVar.data, 0, localVar.length);
2313 }
2314 if (localVarType != null) {
2315 out.putShort(cw.newUTF8("LocalVariableTypeTable"));
2316 out.putInt(localVarType.length + 2).putShort(localVarTypeCount);
2317 out.putByteArray(localVarType.data, 0, localVarType.length);
2318 }
2319 if (lineNumber != null) {
2320 out.putShort(cw.newUTF8("LineNumberTable"));
2321 out.putInt(lineNumber.length + 2).putShort(lineNumberCount);
2322 out.putByteArray(lineNumber.data, 0, lineNumber.length);
2323 }
2324 if (stackMap != null) {
2325 boolean zip = (cw.version & 0xFFFF) >= Opcodes.V1_6;
2326 out.putShort(cw.newUTF8(zip ? "StackMapTable" : "StackMap"));
2327 out.putInt(stackMap.length + 2).putShort(frameCount);
2328 out.putByteArray(stackMap.data, 0, stackMap.length);
2329 }
2330 if (ctanns != null) {
2331 out.putShort(cw.newUTF8("RuntimeVisibleTypeAnnotations"));
2332 ctanns.put(out);
2333 }
2334 if (ictanns != null) {
2335 out.putShort(cw.newUTF8("RuntimeInvisibleTypeAnnotations"));
2336 ictanns.put(out);
2337 }
2338 if (cattrs != null) {
2339 cattrs.put(cw, code.data, code.length, maxLocals, maxStack, out);
2340 }
2341 }
2342 if (exceptionCount > 0) {
2343 out.putShort(cw.newUTF8("Exceptions")).putInt(
2344 2 * exceptionCount + 2);
2345 out.putShort(exceptionCount);
2346 for (int i = 0; i < exceptionCount; ++i) {
2347 out.putShort(exceptions[i]);
2348 }
2349 }
2350 if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
2351 if ((cw.version & 0xFFFF) < Opcodes.V1_5
2352 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) {
2353 out.putShort(cw.newUTF8("Synthetic")).putInt(0);
2354 }
2355 }
2356 if ((access & Opcodes.ACC_DEPRECATED) != 0) {
2357 out.putShort(cw.newUTF8("Deprecated")).putInt(0);
2358 }
2359 if (signature != null) {
2360 out.putShort(cw.newUTF8("Signature")).putInt(2)
2361 .putShort(cw.newUTF8(signature));
2362 }
2363 if (methodParameters != null) {
2364 out.putShort(cw.newUTF8("MethodParameters"));
2365 out.putInt(methodParameters.length + 1).putByte(
2366 methodParametersCount);
2367 out.putByteArray(methodParameters.data, 0, methodParameters.length);
2368 }
2369 if (annd != null) {
2370 out.putShort(cw.newUTF8("AnnotationDefault"));
2371 out.putInt(annd.length);
2372 out.putByteArray(annd.data, 0, annd.length);
2373 }
2374 if (anns != null) {
2375 out.putShort(cw.newUTF8("RuntimeVisibleAnnotations"));
2376 anns.put(out);
2377 }
2378 if (ianns != null) {
2379 out.putShort(cw.newUTF8("RuntimeInvisibleAnnotations"));
2380 ianns.put(out);
2381 }
2382 if (tanns != null) {
2383 out.putShort(cw.newUTF8("RuntimeVisibleTypeAnnotations"));
2384 tanns.put(out);
2385 }
2386 if (itanns != null) {
2387 out.putShort(cw.newUTF8("RuntimeInvisibleTypeAnnotations"));
2388 itanns.put(out);
2389 }
2390 if (panns != null) {
2391 out.putShort(cw.newUTF8("RuntimeVisibleParameterAnnotations"));
2392 AnnotationWriter.put(panns, synthetics, out);
2393 }
2394 if (ipanns != null) {
2395 out.putShort(cw.newUTF8("RuntimeInvisibleParameterAnnotations"));
2396 AnnotationWriter.put(ipanns, synthetics, out);
2397 }
2398 if (attrs != null) {
2399 attrs.put(cw, null, 0, -1, -1, out);
2400 }
2401 }
2402 }
|