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 (ClassReader.FRAMES && compute == FRAMES) { 1434 // completes the control flow graph with exception handler blocks 1435 Handler handler = firstHandler; 1436 while (handler != null) { 1437 Label l = handler.start.getFirst(); 1438 Label h = handler.handler.getFirst(); 1439 Label e = handler.end.getFirst(); 1440 // computes the kind of the edges to 'h' 1441 String t = handler.desc == null ? "java/lang/Throwable" 1442 : handler.desc; 1443 int kind = Frame.OBJECT | cw.addType(t); 1444 // h is an exception handler 1445 h.status |= Label.TARGET; 1446 // adds 'h' as a successor of labels between 'start' and 'end' 1447 while (l != e) { 1448 // creates an edge to 'h' 1449 Edge b = new Edge(); 1450 b.info = kind; 1451 b.successor = h; 1452 // adds it to the successors of 'l' 1970 * index of last type in {@link #frame} to write (exclusive). 1971 */ 1972 private void writeFrameTypes(final int start, final int end) { 1973 for (int i = start; i < end; ++i) { 1974 int t = frame[i]; 1975 int d = t & Frame.DIM; 1976 if (d == 0) { 1977 int v = t & Frame.BASE_VALUE; 1978 switch (t & Frame.BASE_KIND) { 1979 case Frame.OBJECT: 1980 stackMap.putByte(7).putShort( 1981 cw.newClass(cw.typeTable[v].strVal1)); 1982 break; 1983 case Frame.UNINITIALIZED: 1984 stackMap.putByte(8).putShort(cw.typeTable[v].intVal); 1985 break; 1986 default: 1987 stackMap.putByte(v); 1988 } 1989 } else { 1990 StringBuffer buf = new StringBuffer(); 1991 d >>= 28; 1992 while (d-- > 0) { 1993 buf.append('['); 1994 } 1995 if ((t & Frame.BASE_KIND) == Frame.OBJECT) { 1996 buf.append('L'); 1997 buf.append(cw.typeTable[t & Frame.BASE_VALUE].strVal1); 1998 buf.append(';'); 1999 } else { 2000 switch (t & 0xF) { 2001 case 1: 2002 buf.append('I'); 2003 break; 2004 case 2: 2005 buf.append('F'); 2006 break; 2007 case 3: 2008 buf.append('D'); 2009 break; 2010 case 9: 2011 buf.append('Z'); 2012 break; 2013 case 10: 2014 buf.append('B'); 2015 break; 2016 case 11: 2017 buf.append('C'); 2018 break; 2019 case 12: 2020 buf.append('S'); 2021 break; 2022 default: 2023 buf.append('J'); 2024 } 2025 } 2026 stackMap.putByte(7).putShort(cw.newClass(buf.toString())); 2027 } 2028 } 2029 } 2030 2031 private void writeFrameType(final Object type) { 2032 if (type instanceof String) { 2033 stackMap.putByte(7).putShort(cw.newClass((String) type)); 2034 } else if (type instanceof Integer) { 2035 stackMap.putByte(((Integer) type).intValue()); 2036 } else { 2037 stackMap.putByte(8).putShort(((Label) type).position); 2038 } 2039 } 2040 2041 // ------------------------------------------------------------------------ 2042 // Utility methods: dump bytecode array 2043 // ------------------------------------------------------------------------ 2044 2045 /** 2046 * Returns the size of the bytecode of this method. 2047 * 2048 * @return the size of the bytecode of this method. 2049 */ 2050 final int getSize() { 2051 if (classReaderOffset != 0) { 2052 return 6 + classReaderLength; 2053 } 2054 if (resize) { 2055 // replaces the temporary jump opcodes introduced by Label.resolve. 2056 if (ClassReader.RESIZE) { 2057 resizeInstructions(); 2058 } else { 2059 throw new RuntimeException("Method code too large!"); 2060 } 2061 } 2062 int size = 8; 2063 if (code.length > 0) { 2064 if (code.length > 65536) { 2065 throw new RuntimeException("Method code too large!"); 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) { 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 // recomputes the stack map frames 2719 if (frameCount > 0) { 2720 if (compute == FRAMES) { 2721 frameCount = 0; 2722 stackMap = null; 2723 previousFrame = null; 2724 frame = null; 2725 Frame f = new Frame(); 2726 f.owner = labels; 2727 Type[] args = Type.getArgumentTypes(descriptor); 2728 f.initInputFrame(cw, access, args, maxLocals); 2729 visitFrame(f); 2730 Label l = labels; 2731 while (l != null) { 2732 /* 2733 * here we need the original label position. getNewOffset 2734 * must therefore never have been called for this label. 2735 */ 2736 u = l.position - 3; 2737 if ((l.status & Label.STORE) != 0 || (u >= 0 && resize[u])) { 2738 getNewOffset(allIndexes, allSizes, l); 2739 // TODO update offsets in UNINITIALIZED values 2740 visitFrame(l.frame); 2741 } 2742 l = l.successor; 2743 } 2744 } else { 2745 /* 2746 * Resizing an existing stack map frame table is really hard. 2747 * Not only the table must be parsed to update the offets, but 2748 * new frames may be needed for jump instructions that were 2749 * inserted by this method. And updating the offsets or 2750 * inserting frames can change the format of the following 2751 * frames, in case of packed frames. In practice the whole table 2752 * must be recomputed. For this the frames are marked as 2753 * potentially invalid. This will cause the whole class to be 2754 * reread and rewritten with the COMPUTE_FRAMES option (see the 2755 * ClassWriter.toByteArray method). This is not very efficient 2756 * but is much easier and requires much less code than any other 2757 * method I can think of. 2758 */ 2759 cw.invalidFrames = true; 2760 } 2761 } 2762 // updates the exception handler block labels 2763 Handler h = firstHandler; 2764 while (h != null) { 2765 getNewOffset(allIndexes, allSizes, h.start); 2766 getNewOffset(allIndexes, allSizes, h.end); 2767 getNewOffset(allIndexes, allSizes, h.handler); 2768 h = h.next; 2769 } 2770 // updates the instructions addresses in the 2771 // local var and line number tables 2772 for (i = 0; i < 2; ++i) { 2773 ByteVector bv = i == 0 ? localVar : localVarType; 2774 if (bv != null) { 2775 b = bv.data; 2776 u = 0; 2777 while (u < bv.length) { 2778 label = readUnsignedShort(b, u); 2779 newOffset = getNewOffset(allIndexes, allSizes, 0, label); 2780 writeShort(b, u, newOffset); 2781 label += readUnsignedShort(b, u + 2); | 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' 1978 * index of last type in {@link #frame} to write (exclusive). 1979 */ 1980 private void writeFrameTypes(final int start, final int end) { 1981 for (int i = start; i < end; ++i) { 1982 int t = frame[i]; 1983 int d = t & Frame.DIM; 1984 if (d == 0) { 1985 int v = t & Frame.BASE_VALUE; 1986 switch (t & Frame.BASE_KIND) { 1987 case Frame.OBJECT: 1988 stackMap.putByte(7).putShort( 1989 cw.newClass(cw.typeTable[v].strVal1)); 1990 break; 1991 case Frame.UNINITIALIZED: 1992 stackMap.putByte(8).putShort(cw.typeTable[v].intVal); 1993 break; 1994 default: 1995 stackMap.putByte(v); 1996 } 1997 } else { 1998 StringBuilder sb = new StringBuilder(); 1999 d >>= 28; 2000 while (d-- > 0) { 2001 sb.append('['); 2002 } 2003 if ((t & Frame.BASE_KIND) == Frame.OBJECT) { 2004 sb.append('L'); 2005 sb.append(cw.typeTable[t & Frame.BASE_VALUE].strVal1); 2006 sb.append(';'); 2007 } else { 2008 switch (t & 0xF) { 2009 case 1: 2010 sb.append('I'); 2011 break; 2012 case 2: 2013 sb.append('F'); 2014 break; 2015 case 3: 2016 sb.append('D'); 2017 break; 2018 case 9: 2019 sb.append('Z'); 2020 break; 2021 case 10: 2022 sb.append('B'); 2023 break; 2024 case 11: 2025 sb.append('C'); 2026 break; 2027 case 12: 2028 sb.append('S'); 2029 break; 2030 default: 2031 sb.append('J'); 2032 } 2033 } 2034 stackMap.putByte(7).putShort(cw.newClass(sb.toString())); 2035 } 2036 } 2037 } 2038 2039 private void writeFrameType(final Object type) { 2040 if (type instanceof String) { 2041 stackMap.putByte(7).putShort(cw.newClass((String) type)); 2042 } else if (type instanceof Integer) { 2043 stackMap.putByte(((Integer) type).intValue()); 2044 } else { 2045 stackMap.putByte(8).putShort(((Label) type).position); 2046 } 2047 } 2048 2049 // ------------------------------------------------------------------------ 2050 // Utility methods: dump bytecode array 2051 // ------------------------------------------------------------------------ 2052 2053 /** 2054 * Returns the size of the bytecode of this method. 2055 * 2056 * @return the size of the bytecode of this method. 2057 */ 2058 final int getSize() { 2059 if (classReaderOffset != 0) { 2060 return 6 + classReaderLength; 2061 } 2062 int size = 8; 2063 if (code.length > 0) { 2064 if (code.length > 65536) { 2065 throw new RuntimeException("Method code too large!"); 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) { 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 for (i = 0; i < cw.typeTable.length; ++i) { 2739 Item item = cw.typeTable[i]; 2740 if (item != null && item.type == ClassWriter.TYPE_UNINIT) { 2741 item.intVal = getNewOffset(allIndexes, allSizes, 0, 2742 item.intVal); 2743 } 2744 } 2745 // The stack map frames are not serialized yet, so we don't need 2746 // to update them. They will be serialized in visitMaxs. 2747 } else if (frameCount > 0) { 2748 /* 2749 * Resizing an existing stack map frame table is really hard. Not 2750 * only the table must be parsed to update the offets, but new 2751 * frames may be needed for jump instructions that were inserted by 2752 * this method. And updating the offsets or inserting frames can 2753 * change the format of the following frames, in case of packed 2754 * frames. In practice the whole table must be recomputed. For this 2755 * the frames are marked as potentially invalid. This will cause the 2756 * whole class to be reread and rewritten with the COMPUTE_FRAMES 2757 * option (see the ClassWriter.toByteArray method). This is not very 2758 * efficient but is much easier and requires much less code than any 2759 * other method I can think of. 2760 */ 2761 cw.invalidFrames = true; 2762 } 2763 // updates the exception handler block labels 2764 Handler h = firstHandler; 2765 while (h != null) { 2766 getNewOffset(allIndexes, allSizes, h.start); 2767 getNewOffset(allIndexes, allSizes, h.end); 2768 getNewOffset(allIndexes, allSizes, h.handler); 2769 h = h.next; 2770 } 2771 // updates the instructions addresses in the 2772 // local var and line number tables 2773 for (i = 0; i < 2; ++i) { 2774 ByteVector bv = i == 0 ? localVar : localVarType; 2775 if (bv != null) { 2776 b = bv.data; 2777 u = 0; 2778 while (u < bv.length) { 2779 label = readUnsignedShort(b, u); 2780 newOffset = getNewOffset(allIndexes, allSizes, 0, label); 2781 writeShort(b, u, newOffset); 2782 label += readUnsignedShort(b, u + 2); |