美文网首页
56 - ASM之ClassFile和Instruction

56 - ASM之ClassFile和Instruction

作者: 舍是境界 | 来源:发表于2022-03-10 06:45 被阅读0次

    ClassFile对方法的约束

    从ClassFile的角度来说,它对于方法接收的参数数量、方法体的大小做了约束。

    方法参数的数量(255)

    在一个方法当中,方法接收的参数最多有255个。我们分成三种情况来进行说明:

    • 第一种情况,对于non-static方法来说,this也要占用1个参数位置,因此接收的参数最多有254个参数。
    • 第二种情况,对于static方法来说,不需要存储this变量,因此接收的参数最多有255个参数。
    • 第三种情况,不管是non-static方法,还是static方法,long类型或double类型占据2个参数位置,所以实际的参数数量要小于255。
    public class HelloWorld {
        public void test(int a, int b) {
            // do nothing
        }
    
        public static void main(String[] args) {
            for (int i = 1; i <= 255; i++) {
                String item = String.format("int val%d,", i);
                System.out.println(item);
            }
        }
    }
    

    Java Virtual Machine Specification4.11. Limitations of the Java Virtual Machine部分对方法参数的数量进行了限制:

    The number of method parameters is limited to 255 by the definition of a method descriptor, where the limit includes one unit for this in the case of instance or interface method invocations.

    方法体的大小(65535)

    对于方法来说,方法体并不是想写多少代码就写多少代码,它的大小也有一个限制:方法体内最多包含65535个字节。

    当方法体的代码超过65535字节(bytes)时,会出现编译错误:code too large。
    Java Virtual Machine Specification4.7.3. The Code Attribute部分定义了Code属性:

    Code_attribute {
        u2 attribute_name_index;
        u4 attribute_length;
        u2 max_stack;
        u2 max_locals;
        u4 code_length;
        u1 code[code_length];
        u2 exception_table_length;
        {   u2 start_pc;
            u2 end_pc;
            u2 handler_pc;
            u2 catch_type;
        } exception_table[exception_table_length];
        u2 attributes_count;
        attribute_info attributes[attributes_count];
    }
    

    code_length: The value of the code_length item gives the number of bytes in the code array for this method. The value of code_length must be greater than zero (as the code array must not be empty) and less than 65536.

    Instruction VS. Opcode

    严格的来说,instruction和opcode这两个概念是有区别的。相对来说,instruction是一个比较大的概念,而opcode是一个比较小的概念:

    instruction = opcode + operands
    

    A Java Virtual Machine instruction consists of a one-byte opcode specifying the operation to be performed, followed by zero or more operands supplying arguments or data that are used by the operation. Many instructions have no operands and consist only of an opcode.
    参考: 2.11. Instruction Set Summary

    Opcodes

    • 一个字节的容量(256)

      • opcode占用空间的大小为1 byte。在1 byte中,包含8个bit,因此1 byte最多可以表示256个值(即0~255)。
    • opcode的数量(205)

      • 虽然一个字节(byte)当中可以存储256个值(即0~255),但是在Java 8这个版本中定义的opcode数量只有205个。因此,opcode的内容就是一个“数值”,位于0~255之间。
    • opcode和mnemonic symbol

      • 要记住每个opcode对应数值的含义,是非常困难的。为了方便人们记忆opcode的作用,就给每个opcode起了一个名字,叫作mnemonic symbol(助记符号)。
    opcode mnemonic symbol opcode mnemonic symbol opcode mnemonic symbol opcode mnemonic symbol
    0 nop 64 lstore_1 128 ior 192 checkcast
    1 aconst_null 65 lstore_2 129 lor 193 instanceof
    2 iconst_m1 66 lstore_3 130 ixor 194 monitorenter
    3 iconst_0 67 fstore_0 131 lxor 195 monitorexit
    4 iconst_1 68 fstore_1 132 iinc 196 wide
    5 iconst_2 69 fstore_2 133 i2l 197 multianewarray
    6 iconst_3 70 fstore_3 134 i2f 198 ifnull
    7 iconst_4 71 dstore_0 135 i2d 199 ifnonnull
    8 iconst_5 72 dstore_1 136 l2i 200 goto_w
    9 lconst_0 73 dstore_2 137 l2f 201 jsr_w
    10 lconst_1 74 dstore_3 138 l2d 202 breakpoint
    11 fconst_0 75 astore_0 139 f2i 203
    12 fconst_1 76 astore_1 140 f2l 204
    13 fconst_2 77 astore_2 141 f2d 205
    14 dconst_0 78 astore_3 142 d2i 206
    15 dconst_1 79 iastore 143 d2l 207
    16 bipush 80 lastore 144 d2f 208
    17 sipush 81 fastore 145 i2b 209
    18 ldc 82 dastore 146 i2c 210
    19 ldc_w 83 aastore 147 i2s 211
    20 ldc2_w 84 bastore 148 lcmp 212
    21 iload 85 castore 149 fcmpl 213
    22 lload 86 sastore 150 fcmpg 214
    23 fload 87 pop 151 dcmpl 215
    24 dload 88 pop2 152 dcmpg 216
    25 aload 89 dup 153 ifeq 217
    26 iload_0 90 dup_x1 154 ifne 218
    27 iload_1 91 dup_x2 155 iflt 219
    28 iload_2 92 dup2 156 ifge 220
    29 iload_3 93 dup2_x1 157 ifgt 221
    30 lload_0 94 dup2_x2 158 ifle 222
    31 lload_1 95 swap 159 if_icmpeq 223
    32 lload_2 96 iadd 160 if_icmpne 224
    33 lload_3 97 ladd 161 if_icmplt 225
    34 fload_0 98 fadd 162 if_icmpge 226
    35 fload_1 99 dadd 163 if_icmpgt 227
    36 fload_2 100 isub 164 if_icmple 228
    37 fload_3 101 lsub 165 if_acmpeq 229
    38 dload_0 102 fsub 166 if_acmpne 230
    39 dload_1 103 dsub 167 goto 231
    40 dload_2 104 imul 168 jsr 232
    41 dload_3 105 lmul 169 ret 233
    42 aload_0 106 fmul 170 tableswitch 234
    43 aload_1 107 dmul 171 lookupswitch 235
    44 aload_2 108 idiv 172 ireturn 236
    45 aload_3 109 ldiv 173 lreturn 237
    46 iaload 110 fdiv 174 freturn 238
    47 laload 111 ddiv 175 dreturn 239
    48 faload 112 irem 176 areturn 240
    49 daload 113 lrem 177 return 241
    50 aaload 114 frem 178 getstatic 242
    51 baload 115 drem 179 putstatic 243
    52 caload 116 ineg 180 getfield 244
    53 saload 117 lneg 181 putfield 245
    54 istore 118 fneg 182 invokevirtual 246
    55 lstore 119 dneg 183 invokespecial 247
    56 fstore 120 ishl 184 invokestatic 248
    57 dstore 121 lshl 185 invokeinterface 249
    58 astore 122 ishr 186 invokedynamic 250
    59 istore_0 123 lshr 187 new 251
    60 istore_1 124 iushr 188 newarray 252
    61 istore_2 125 lushr 189 anewarray 253
    62 istore_3 126 iand 190 arraylength 254 impdep1
    63 lstore_0 127 land 191 athrow 255 impdep2

    参考: Chapter 6. The Java Virtual Machine Instruction Set

    mnemonic symbol和类型信息

    对于大多数的opcode,它的mnemonic symbol名字当中带有类型信息(type information)。一般情况下,规律如下:

    • i表示int类型
    • l表示long类型。
    • s表示short类型
    • b表示byte类型
    • c表示char类型
    • f表示float类型
    • d表示double类型。
    • a表示reference类型。a可能是address的首字母,表示指向内存空间的一个地址信息。

    有一些opcode,它的mnemonic symbol名字不带有类型信息(type information),但是可以操作多种类型的数据,例如:

    • arraylength,无论是int[]类型的数组,还是String[]类型的数组,获取数组的长度都是使用arraylength。
    • ldc、ldc_w和ldc2_w表示load constant的缩写,可以加载各种常量值。
      与stack相关的指令,可以操作多种数据类型。pop表示出栈操作,dup相关的指令是duplicate单词的缩写,表示“复制”操作;swap表示“交换”。

    还有一些opcode,它的mnemonic symbol名字不带有类型信息(type information),它也不处理任何类型的数据。例如:

    • goto

    For the majority of typed instructions, the instruction type is represented explicitly in the opcode mnemonic by a letter: i for an int operation, l for long, s for short, b for byte, c for char, f for float, d for double, and a for reference. Some instructions for which the type is unambiguous do not have a type letter in their mnemonic. For instance, arraylength always operates on an object that is an array. Some instructions, such as goto, an unconditional control transfer, do not operate on typed operands.
    参考: 2.11.1. Types and the Java Virtual Machine

    小结

    • 在ClassFile结构中,对于方法接收的参数和方法体的大小是有数量限制的。
    • instruction = opcode + operands
    • opcode占用1个byte大小,目前定义了205个;为了方便记忆,JVM文档为opcode提供了名字(即mnemonic symbol),大多数的名字中带有类型信息。
    • 学习opcode是一个长期积累的过程,不能一蹴而就。所以,推荐大家依据感兴趣的内容,进行有选择性的学习。

    相关文章

      网友评论

          本文标题:56 - ASM之ClassFile和Instruction

          本文链接:https://www.haomeiwen.com/subject/kwgwrrtx.html