继第一篇,我们来看看readCode的代码:
private void readCode(final MethodVisitor mv, final Context context, int u) { // reads the header byte[] b = this.b; char[] c = context.buffer;//这个buffer长度为maxStringLength int maxStack = readUnsignedShort(u);//maxStack值 int maxLocals = readUnsignedShort(u + 2);//max locals 值 int codeLength = readInt(u + 4);//代码长度 u += 8; // reads the bytecode to find the labels int codeStart = u; int codeEnd = u + codeLength; Label[] labels = context.labels = new Label[codeLength + 2];//为啥+2? readLabel(codeLength + 1, labels); while (u < codeEnd) { int offset = u - codeStart; int opcode = b[u] & 0xFF; switch (ClassWriter.TYPE[opcode]) { case ClassWriter.NOARG_INSN: case ClassWriter.IMPLVAR_INSN: u += 1; break; case ClassWriter.LABEL_INSN: readLabel(offset + readShort(u + 1), labels); u += 3; break; case ClassWriter.LABELW_INSN: readLabel(offset + readInt(u + 1), labels); u += 5; break; case ClassWriter.WIDE_INSN: opcode = b[u + 1] & 0xFF; if (opcode == Opcodes.IINC) { u += 6; } else { u += 4; } break; case ClassWriter.TABL_INSN: // skips 0 to 3 padding bytes u = u + 4 - (offset & 3); // reads instruction readLabel(offset + readInt(u), labels); for (int i = readInt(u + 8) - readInt(u + 4) + 1; i > 0; --i) { readLabel(offset + readInt(u + 12), labels); u += 4; } u += 12; break; case ClassWriter.LOOK_INSN: // skips 0 to 3 padding bytes u = u + 4 - (offset & 3); // reads instruction readLabel(offset + readInt(u), labels); for (int i = readInt(u + 4); i > 0; --i) { readLabel(offset + readInt(u + 12), labels); u += 8; } u += 8; break; case ClassWriter.VAR_INSN: case ClassWriter.SBYTE_INSN: case ClassWriter.LDC_INSN: u += 2; break; case ClassWriter.SHORT_INSN: case ClassWriter.LDCW_INSN: case ClassWriter.FIELDORMETH_INSN: case ClassWriter.TYPE_INSN: case ClassWriter.IINC_INSN: u += 3; break; case ClassWriter.ITFMETH_INSN: case ClassWriter.INDYMETH_INSN: u += 5; break; // case MANA_INSN: default: u += 4; break; } } // reads the try catch entries to find the labels, and also visits them for (int i = readUnsignedShort(u); i > 0; --i) { Label start = readLabel(readUnsignedShort(u + 2), labels); Label end = readLabel(readUnsignedShort(u + 4), labels); Label handler = readLabel(readUnsignedShort(u + 6), labels); String type = readUTF8(items[readUnsignedShort(u + 8)], c); mv.visitTryCatchBlock(start, end, handler, type); u += 8; } u += 2; // reads the code attributes int[] tanns = null; // start index of each visible type annotation int[] itanns = null; // start index of each invisible type annotation int tann = 0; // current index in tanns array int itann = 0; // current index in itanns array int ntoff = -1; // next visible type annotation code offset int nitoff = -1; // next invisible type annotation code offset int varTable = 0; int varTypeTable = 0; boolean zip = true; boolean unzip = (context.flags & EXPAND_FRAMES) != 0; int stackMap = 0; int stackMapSize = 0; int frameCount = 0; Context frame = null; Attribute attributes = null; for (int i = readUnsignedShort(u); i > 0; --i) { String attrName = readUTF8(u + 2, c); if ("LocalVariableTable".equals(attrName)) { if ((context.flags & SKIP_DEBUG) == 0) { varTable = u + 8; for (int j = readUnsignedShort(u + 8), v = u; j > 0; --j) { int label = readUnsignedShort(v + 10); if (labels[label] == null) { readLabel(label, labels).status |= Label.DEBUG; } label += readUnsignedShort(v + 12); if (labels[label] == null) { readLabel(label, labels).status |= Label.DEBUG; } v += 10; } } } else if ("LocalVariableTypeTable".equals(attrName)) { varTypeTable = u + 8; } else if ("LineNumberTable".equals(attrName)) { if ((context.flags & SKIP_DEBUG) == 0) { for (int j = readUnsignedShort(u + 8), v = u; j > 0; --j) { int label = readUnsignedShort(v + 10); if (labels[label] == null) { readLabel(label, labels).status |= Label.DEBUG; } labels[label].line = readUnsignedShort(v + 12); v += 4; } } } else if (ANNOTATIONS && "RuntimeVisibleTypeAnnotations".equals(attrName)) { tanns = readTypeAnnotations(mv, context, u + 8, true); ntoff = tann >= tanns.length || readUnsignedShort(tanns[tann]) < 0x86 ? -1 : readUnsignedShort(tanns[tann] + 2); } else if (ANNOTATIONS && "RuntimeInvisibleTypeAnnotations".equals(attrName)) { itanns = readTypeAnnotations(mv, context, u + 8, false); nitoff = itann >= itanns.length || readUnsignedShort(itanns[itann]) < 0x86 ? -1 : readUnsignedShort(itanns[itann] + 2); } else if (FRAMES && "StackMapTable".equals(attrName)) { if ((context.flags & SKIP_FRAMES) == 0) { stackMap = u + 10;//stackMap位置后边是stack_map_frame类型的entries,10 = attribute_count(u2)、attribute_name_index(u2)、attribute_length(u4)、number_of_entries(u2) stackMapSize = readInt(u + 4);//stackMapSize是attribute_length frameCount = readUnsignedShort(u + 8);// } /* * here we do not extract the labels corresponding to the * attribute content. This would require a full parsing of the * attribute, which would need to be repeated in the second * phase (see below). Instead the content of the attribute is * read one frame at a time (i.e. after a frame has been * visited, the next frame is read), and the labels it contains * are also extracted one frame at a time. Thanks to the * ordering of frames, having only a "one frame lookahead" is * not a problem, i.e. it is not possible to see an offset * smaller than the offset of the current insn and for which no * Label exist. */ /* * This is not true for UNINITIALIZED type offsets. We solve * this by parsing the stack map table without a full decoding * (see below). */ } else if (FRAMES && "StackMap".equals(attrName)) { if ((context.flags & SKIP_FRAMES) == 0) { zip = false; stackMap = u + 10; stackMapSize = readInt(u + 4); frameCount = readUnsignedShort(u + 8); } /* * IMPORTANT! here we assume that the frames are ordered, as in * the StackMapTable attribute, although this is not guaranteed * by the attribute format. */ } else { for (int j = 0; j < context.attrs.length; ++j) { if (context.attrs[j].type.equals(attrName)) { Attribute attr = context.attrs[j].read(this, u + 8, readInt(u + 4), c, codeStart - 8, labels); if (attr != null) { attr.next = attributes; attributes = attr; } } } } u += 6 + readInt(u + 4); } u += 2; // generates the first (implicit) stack map frame if (FRAMES && (stackMap != 0 || unzip)) { /* * for the first explicit frame the offset is not offset_delta + 1 * but only offset_delta; setting the implicit frame offset to -1 * allow the use of the "offset_delta + 1" rule in all cases */ frame = context; frame.offset = -1; frame.mode = 0; frame.localCount = 0; frame.localDiff = 0; frame.stackCount = 0; frame.local = new Object[maxLocals]; frame.stack = new Object[maxStack]; if (unzip) { getImplicitFrame(context); } } if (FRAMES && stackMap != 0) { /* * Finds labels for UNINITIALIZED frame types. Instead of decoding * each element of the stack map table, we look for 3 consecutive * bytes that "look like" an UNINITIALIZED type (tag 8, offset * within code bounds, NEW instruction at this offset). We may find * false positives (i.e. not real UNINITIALIZED types), but this * should be rare, and the only consequence will be the creation of * an unneeded label. This is better than creating a label for each * NEW instruction, and faster than fully decoding the whole stack * map table. */ for (int i = stackMap; i < stackMap + stackMapSize - 2; ++i) { if (b[i] == 8) { // UNINITIALIZED FRAME TYPE int v = readUnsignedShort(i + 1); if (v >= 0 && v < codeLength) { if ((b[codeStart + v] & 0xFF) == Opcodes.NEW) { readLabel(v, labels); } } } } } // visits the instructions u = codeStart; while (u < codeEnd) { int offset = u - codeStart; // visits the label and line number for this offset, if any Label l = labels[offset]; if (l != null) { mv.visitLabel(l); if ((context.flags & SKIP_DEBUG) == 0 && l.line > 0) { mv.visitLineNumber(l.line, l); } } // visits the frame(s) for this offset, if any while (FRAMES && frame != null && (frame.offset == offset || frame.offset == -1)) { // if there is a frame for this offset, makes the visitor visit // it, and reads the next frame if there is one. if (!zip || unzip) { mv.visitFrame(Opcodes.F_NEW, frame.localCount, frame.local, frame.stackCount, frame.stack); } else if (frame.offset != -1) { mv.visitFrame(frame.mode, frame.localDiff, frame.local, frame.stackCount, frame.stack); } if (frameCount > 0) { stackMap = readFrame(stackMap, zip, unzip, frame); --frameCount; } else { frame = null; } } // visits the instruction at this offset int opcode = b[u] & 0xFF; switch (ClassWriter.TYPE[opcode]) { case ClassWriter.NOARG_INSN: mv.visitInsn(opcode); u += 1; break; case ClassWriter.IMPLVAR_INSN: if (opcode > Opcodes.ISTORE) { opcode -= 59; // ISTORE_0 mv.visitVarInsn(Opcodes.ISTORE + (opcode >> 2), opcode & 0x3); } else { opcode -= 26; // ILOAD_0 mv.visitVarInsn(Opcodes.ILOAD + (opcode >> 2), opcode & 0x3); } u += 1; break; case ClassWriter.LABEL_INSN: mv.visitJumpInsn(opcode, labels[offset + readShort(u + 1)]); u += 3; break; case ClassWriter.LABELW_INSN: mv.visitJumpInsn(opcode - 33, labels[offset + readInt(u + 1)]); u += 5; break; case ClassWriter.WIDE_INSN: opcode = b[u + 1] & 0xFF; if (opcode == Opcodes.IINC) { mv.visitIincInsn(readUnsignedShort(u + 2), readShort(u + 4)); u += 6; } else { mv.visitVarInsn(opcode, readUnsignedShort(u + 2)); u += 4; } break; case ClassWriter.TABL_INSN: { // skips 0 to 3 padding bytes u = u + 4 - (offset & 3); // reads instruction int label = offset + readInt(u); int min = readInt(u + 4); int max = readInt(u + 8); Label[] table = new Label[max - min + 1]; u += 12; for (int i = 0; i < table.length; ++i) { table[i] = labels[offset + readInt(u)]; u += 4; } mv.visitTableSwitchInsn(min, max, labels[label], table); break; } case ClassWriter.LOOK_INSN: { // skips 0 to 3 padding bytes u = u + 4 - (offset & 3); // reads instruction int label = offset + readInt(u); int len = readInt(u + 4); int[] keys = new int[len]; Label[] values = new Label[len]; u += 8; for (int i = 0; i < len; ++i) { keys[i] = readInt(u); values[i] = labels[offset + readInt(u + 4)]; u += 8; } mv.visitLookupSwitchInsn(labels[label], keys, values); break; } case ClassWriter.VAR_INSN: mv.visitVarInsn(opcode, b[u + 1] & 0xFF); u += 2; break; case ClassWriter.SBYTE_INSN: mv.visitIntInsn(opcode, b[u + 1]); u += 2; break; case ClassWriter.SHORT_INSN: mv.visitIntInsn(opcode, readShort(u + 1)); u += 3; break; case ClassWriter.LDC_INSN: mv.visitLdcInsn(readConst(b[u + 1] & 0xFF, c)); u += 2; break; case ClassWriter.LDCW_INSN: mv.visitLdcInsn(readConst(readUnsignedShort(u + 1), c)); u += 3; break; case ClassWriter.FIELDORMETH_INSN: case ClassWriter.ITFMETH_INSN: { int cpIndex = items[readUnsignedShort(u + 1)]; String iowner = readClass(cpIndex, c); cpIndex = items[readUnsignedShort(cpIndex + 2)]; String iname = readUTF8(cpIndex, c); String idesc = readUTF8(cpIndex + 2, c); if (opcode < Opcodes.INVOKEVIRTUAL) { mv.visitFieldInsn(opcode, iowner, iname, idesc); } else { mv.visitMethodInsn(opcode, iowner, iname, idesc); } if (opcode == Opcodes.INVOKEINTERFACE) { u += 5; } else { u += 3; } break; } case ClassWriter.INDYMETH_INSN: { int cpIndex = items[readUnsignedShort(u + 1)]; int bsmIndex = context.bootstrapMethods[readUnsignedShort(cpIndex)]; Handle bsm = (Handle) readConst(readUnsignedShort(bsmIndex), c); int bsmArgCount = readUnsignedShort(bsmIndex + 2); Object[] bsmArgs = new Object[bsmArgCount]; bsmIndex += 4; for (int i = 0; i < bsmArgCount; i++) { bsmArgs[i] = readConst(readUnsignedShort(bsmIndex), c); bsmIndex += 2; } cpIndex = items[readUnsignedShort(cpIndex + 2)]; String iname = readUTF8(cpIndex, c); String idesc = readUTF8(cpIndex + 2, c); mv.visitInvokeDynamicInsn(iname, idesc, bsm, bsmArgs); u += 5; break; } case ClassWriter.TYPE_INSN: mv.visitTypeInsn(opcode, readClass(u + 1, c)); u += 3; break; case ClassWriter.IINC_INSN: mv.visitIincInsn(b[u + 1] & 0xFF, b[u + 2]); u += 3; break; // case MANA_INSN: default: mv.visitMultiANewArrayInsn(readClass(u + 1, c), b[u + 3] & 0xFF); u += 4; break; } // visit the instruction annotations, if any while (tanns != null && tann < tanns.length && ntoff <= offset) { if (ntoff == offset) { int v = readAnnotationTarget(context, tanns[tann]); readAnnotationValues(v + 2, c, true, mv.visitInsnAnnotation(context.target, context.path, readUTF8(v, c), true)); } ntoff = ++tann >= tanns.length || readUnsignedShort(tanns[tann]) < 0x86 ? -1 : readUnsignedShort(tanns[tann] + 2); } while (itanns != null && itann < itanns.length && nitoff <= offset) { if (nitoff == offset) { int v = readAnnotationTarget(context, itanns[itann]); readAnnotationValues(v + 2, c, true, mv.visitInsnAnnotation(context.target, context.path, readUTF8(v, c), false)); } nitoff = ++itann >= itanns.length || readUnsignedShort(itanns[itann]) < 0x86 ? -1 : readUnsignedShort(itanns[itann] + 2); } } if (labels[codeLength] != null) { mv.visitLabel(labels[codeLength]); } // visits the local variable tables if ((context.flags & SKIP_DEBUG) == 0 && varTable != 0) { int[] typeTable = null; if (varTypeTable != 0) { u = varTypeTable + 2; typeTable = new int[readUnsignedShort(varTypeTable) * 3]; for (int i = typeTable.length; i > 0;) { typeTable[--i] = u + 6; // signature typeTable[--i] = readUnsignedShort(u + 8); // index typeTable[--i] = readUnsignedShort(u); // start u += 10; } } u = varTable + 2; for (int i = readUnsignedShort(varTable); i > 0; --i) { int start = readUnsignedShort(u); int length = readUnsignedShort(u + 2); int index = readUnsignedShort(u + 8); String vsignature = null; if (typeTable != null) { for (int j = 0; j < typeTable.length; j += 3) { if (typeTable[j] == start && typeTable[j + 1] == index) { vsignature = readUTF8(typeTable[j + 2], c); break; } } } mv.visitLocalVariable(readUTF8(u + 4, c), readUTF8(u + 6, c), vsignature, labels[start], labels[start + length], index); u += 10; } } // visits the local variables type annotations if (tanns != null) { for (int i = 0; i < tanns.length; ++i) { if ((readUnsignedShort(tanns[i]) & 0xFC) == 0x80) { int v = readAnnotationTarget(context, tanns[i]); v = readAnnotationValues(v + 2, c, true, mv.visitLocalVariableAnnotation(context.target, context.path, context.start, context.end, context.index, readUTF8(v, c), true)); } } } if (itanns != null) { for (int i = 0; i < itanns.length; ++i) { if ((readUnsignedShort(itanns[i]) & 0xFC) == 0x80) { int v = readAnnotationTarget(context, itanns[i]); v = readAnnotationValues(v + 2, c, true, mv.visitLocalVariableAnnotation(context.target, context.path, context.start, context.end, context.index, readUTF8(v, c), false)); } } } // visits the code attributes while (attributes != null) { Attribute attr = attributes.next; attributes.next = null; mv.visitAttribute(attributes); attributes = attr; } // visits the max stack and max locals values mv.visitMaxs(maxStack, maxLocals); }
ASM4.0在readCode里有个局部变量Label[] labels,同时也指向org.objectweb.asm.Context.labels;是通过调用org.objectweb.asm.ClassReader .readLabel(int, Label[]) 来操作的
ASM2.2.3里边是access方法里边有一个操作Label[] labels局部变量,直接在access内读写的
4.0中的labels数组,是在访问了某些指令的时候,会构造一个label:
1、代码指令类:
if类、goto、jsr的目标地址; goto_w、jsr_w的目标地址; tableswitch、lookupswitch目标地址、默认目标地址;
2、异常表类
start_pc、end_pc、handler_pc
3、code属性的属性
LocalVariableTable,每个变量的start_pc和start_pc + length LineNumberTable,指令索引、行号 未知属性表 StackMapTable,初始帧、栈帧表每一帧,帧类型(2个) RuntimeVisibleTypeAnnotations RuntimeInvisibleTypeAnnotations
接下来看看asm是如何读取常量池信息的,asm根据常量池项对应的常量池索引,根据常量池索引得到其值在class文件type数组的偏移量,然后从class文件的byte数组中读取到相应长度的值,要特别注意的是float和double值的存储是按照ieee的格式存储的,所以这里在解析的时候会进行一次转换:
/** * Reads a numeric or string constant pool item in {@link #b b}. <i>This * method is intended for {@link Attribute} sub classes, and is normally not * needed by class generators or adapters.</i> * * @param item * the index of a constant pool item. * @param buf * buffer to be used to read the item. This buffer must be * sufficiently large. It is not automatically resized. * @return the {@link Integer}, {@link Float}, {@link Long}, {@link Double}, * {@link String}, {@link Type} or {@link Handle} corresponding to * the given constant pool item. */ public Object readConst(final int item, final char[] buf) { int index = items[item]; switch (b[index - 1]) { case ClassWriter.INT://基本类型获取的都是值本身 return new Integer(readInt(index)); case ClassWriter.FLOAT: return new Float(Float.intBitsToFloat(readInt(index))); case ClassWriter.LONG: return new Long(readLong(index)); case ClassWriter.DOUBLE: return new Double(Double.longBitsToDouble(readLong(index))); case ClassWriter.CLASS://class里边存储的是Type类型 return Type.getObjectType(readUTF8(index, buf)); case ClassWriter.STR: return readUTF8(index, buf); case ClassWriter.MTYPE: return Type.getMethodType(readUTF8(index, buf)); default: // case ClassWriter.HANDLE_BASE + [1..9]: int tag = readByte(index); int[] items = this.items; int cpIndex = items[readUnsignedShort(index + 1)]; String owner = readClass(cpIndex, buf); cpIndex = items[readUnsignedShort(cpIndex + 2)]; String name = readUTF8(cpIndex, buf); String desc = readUTF8(cpIndex + 2, buf); return new Handle(tag, owner, name, desc); } }
在MethodNode中,常量值会被转换成一个LdcInsnNode节点存储,节点的cst值就是常量值。
《未完待续》
相关推荐
内容包含ASM4.0中文手册,以及四种ASM常见的字节码操作应用范例,包含最新版本的ASM9.2的jar包,包含asm-9.2.jar,asm-commons-9.2.jar,asm-util-9.2.jar。 学习文章地址 ...
标题中的“asm4.0全家福”指的是ASM库的一个完整版本集合,ASM是一个Java字节码操控和分析框架,主要用于动态生成类或者增强已有类的功能。这个“全家福”包括了ASM库的主要组件,分别是: 1. **asm-4.0**: 这是ASM...
2. **代码分析**:ASM不仅可以生成字节码,还能分析已经存在的字节码,帮助开发者理解类和方法的行为,这对于代码混淆、性能优化以及调试有着重要的作用。 3. **低级别操作**:ASM提供了对类结构的底层访问,包括...
标题中的"asm-tree-4.0.zip_asm4.0"提到了ASM库的特定版本,ASM是一个Java字节码操控和分析框架,主要用于动态代理、字节码转换以及代码分析等场景。ASM 4.0是这个库的一个版本,可能包含了一些针对性能和功能的改进...
ASM 4 使用指南中文版。ASM是Java字节码的工业级库。长期以来一直没有中文版。这下好了,中文版横空出世。感兴趣的同学可以投递简历 mars # oneapm ....ASM 4.0 A Java bytecode engineering library
spring 3.2.5版本源码使用的,构建的时候使用如下描述 因为英文不太好,大概意思可能是什么asm4.0版本使用的spring 在spring4中已经重新包装了asm在spring-core的核心包里,当然我这解释不标准 看下满原文构建的描述...
asm-4.0.jar
ASM作为一款强大的Java字节码操纵框架,不仅具备高效处理字节码的能力,还能广泛应用于各种实际开发场景中,从简单的代码生成到复杂的程序分析和转换。对于希望在不改变源代码的情况下对Java应用程序进行改进的...
标题中的"asm-all-4.0.jar.zip"指的是一个压缩包文件,该文件包含了ASM库的一个集合,版本为4.0。ASM是一个Java字节码操控和分析框架,主要用于动态生成类或者增强已有类的功能。ASM库广泛应用于字节码级别的编程,...
ASM是一个Java字节码操控和分析框架,广泛用于动态代理、代码分析和转换等场景。ASM Util是ASM框架的一个扩展,提供了更多实用工具和功能。 在描述中,我们看到了“asm”、“util”、“4.0_RC1”和“jar.zip包下载...
asm5.1源码 eclipse工程
赠送jar包:asm-4.2.jar; 赠送原API文档:asm-4.2-javadoc.jar; 赠送源代码:asm-4.2-sources.jar; 赠送Maven依赖信息文件:asm-4.2.pom; 包含翻译后的API文档:asm-4.2-javadoc-API文档-中文(简体)版.zip; ...
ASM是一个Java字节码操控和分析框架,常用于动态代理、代码生成以及字节码级别的程序分析和修改。ASM库提供了对Java字节码的低级别访问,使得开发者可以直接操作和构建类文件,这对于理解Java虚拟机的工作原理,或者...
ASM 从类文件中读入信息后,能够改变类行为,分析类信息,甚至能够根据用户要求生成新类。 与 BCEL 和 SERL 不同,ASM 提供了更为现代的编程模型。对于 ASM 来说,Java class 被描述为一棵树;使用 “Visitor” 模式...
《Mader.C.ASM(中国龙语言学机器码式编译器4.0)源码》是关于计算机编程领域的一款特殊编译器的源代码,主要用于将高级语言转化为机器码,以便计算机能够直接执行。这款编译器是4.0版本,意味着它经过了多次迭代和...
ASM是一个Java字节码操控和分析框架,常用于动态代理、代码分析以及转换等场景。ASM库能够直接读取和写入Java类的字节码,使得开发者可以在运行时动态生成和修改类。"asm-4.0_RC1.jar.zip" 是ASM库的4.0_RC1版本的...
2. **代码分析**:通过对字节码的解析,可以进行性能监控、代码安全检查等任务。 3. **字节码优化**:在运行时对代码进行优化,例如去除无用的代码或提升性能。 4. **框架实现**:许多框架如Hibernate、Spring等,都...
ASM源码很好用,可以破解任何软件
- **调试技巧**:通过阅读和分析ASM IDE的源码,可以学习到调试工具的实现方法和调试策略。 - **性能优化**:了解IDE如何优化编译和链接过程,有助于提升自身汇编代码的效率。 - **扩展与定制**:熟悉源码后,...
JavaEE源代码 asm-attrsJavaEE源代码 asm-attrsJavaEE源代码 asm-attrsJavaEE源代码 asm-attrsJavaEE源代码 asm-attrsJavaEE源代码 asm-attrsJavaEE源代码 asm-attrsJavaEE源代码 asm-attrsJavaEE源代码 asm-...