< prev index next >

src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassReader.java

Print this page
rev 47452 : imported patch jdk-new-asmv6.patch

*** 71,105 **** * @author Eugene Kuleshov */ public class ClassReader { /** - * True to enable signatures support. - */ - static final boolean SIGNATURES = true; - - /** - * True to enable annotations support. - */ - static final boolean ANNOTATIONS = true; - - /** - * True to enable stack map frames support. - */ - static final boolean FRAMES = true; - - /** - * True to enable bytecode writing support. - */ - static final boolean WRITER = true; - - /** - * True to enable JSR_W and GOTO_W support. - */ - static final boolean RESIZE = true; - - /** * Flag to skip method code. If this class is set <code>CODE</code> * attribute won't be visited. This can be used, for example, to retrieve * annotations for methods and method parameters. */ public static final int SKIP_CODE = 1; --- 71,80 ----
*** 132,141 **** --- 107,131 ---- * ClassWriter which degrades performances quite a lot). */ public static final int EXPAND_FRAMES = 8; /** + * Flag to expand the ASM pseudo instructions into an equivalent sequence of + * standard bytecode instructions. When resolving a forward jump it may + * happen that the signed 2 bytes offset reserved for it is not sufficient + * to store the bytecode offset. In this case the jump instruction is + * replaced with a temporary ASM pseudo instruction using an unsigned 2 + * bytes offset (see Label#resolve). This internal flag is used to re-read + * classes containing such instructions, in order to replace them with + * standard instructions. In addition, when this flag is used, GOTO_W and + * JSR_W are <i>not</i> converted into GOTO and JSR, to make sure that + * infinite loops where a GOTO_W is replaced with a GOTO in ClassReader and + * converted back to a GOTO_W in ClassWriter cannot occur. + */ + static final int EXPAND_ASM_INSNS = 256; + + /** * The class to be parsed. <i>The content of this array must not be * modified. This field is intended for {@link Attribute} sub classes, and * is normally not needed by class generators or adapters.</i> */ public final byte[] b;
*** 193,203 **** * the length of the class data. */ public ClassReader(final byte[] b, final int off, final int len) { this.b = b; // checks the class version ! if (readShort(off + 6) > Opcodes.V1_9) { throw new IllegalArgumentException(); } // parses the constant pool items = new int[readUnsignedShort(off + 8)]; int n = items.length; --- 183,193 ---- * the length of the class data. */ public ClassReader(final byte[] b, final int off, final int len) { this.b = b; // checks the class version ! if (readShort(off + 6) > Opcodes.V9) { throw new IllegalArgumentException(); } // parses the constant pool items = new int[readUnsignedShort(off + 8)]; int n = items.length;
*** 232,241 **** --- 222,233 ---- size = 4; break; // case ClassWriter.CLASS: // case ClassWriter.STR: // case ClassWriter.MTYPE + // case ClassWriter.PACKAGE: + // case ClassWriter.MODULE: default: size = 3; break; } index += size;
*** 375,385 **** item.set(readUTF8(nameType, buf), readUTF8(nameType + 2, buf), readUnsignedShort(index)); break; // case ClassWriter.STR: // case ClassWriter.CLASS: ! // case ClassWriter.MTYPE default: item.set(tag, readUTF8(index, buf), null, null); break; } --- 367,379 ---- item.set(readUTF8(nameType, buf), readUTF8(nameType + 2, buf), readUnsignedShort(index)); break; // case ClassWriter.STR: // case ClassWriter.CLASS: ! // case ClassWriter.MTYPE: ! // case ClassWriter.MODULE: ! // case ClassWriter.PACKAGE: default: item.set(tag, readUTF8(index, buf), null, null); break; }
*** 582,596 **** --- 576,593 ---- String sourceFile = null; String sourceDebug = null; String enclosingOwner = null; String enclosingName = null; String enclosingDesc = null; + String moduleMainClass = null; int anns = 0; int ianns = 0; int tanns = 0; int itanns = 0; int innerClasses = 0; + int module = 0; + int packages = 0; Attribute attributes = null; u = getAttributes(); for (int i = readUnsignedShort(u); i > 0; --i) { String attrName = readUTF8(u + 2, c);
*** 605,636 **** int item = readUnsignedShort(u + 10); if (item != 0) { enclosingName = readUTF8(items[item], c); enclosingDesc = readUTF8(items[item] + 2, c); } ! } else if (SIGNATURES && "Signature".equals(attrName)) { signature = readUTF8(u + 8, c); ! } else if (ANNOTATIONS ! && "RuntimeVisibleAnnotations".equals(attrName)) { anns = u + 8; ! } else if (ANNOTATIONS ! && "RuntimeVisibleTypeAnnotations".equals(attrName)) { tanns = u + 8; } else if ("Deprecated".equals(attrName)) { access |= Opcodes.ACC_DEPRECATED; } else if ("Synthetic".equals(attrName)) { access |= Opcodes.ACC_SYNTHETIC | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE; } else if ("SourceDebugExtension".equals(attrName)) { int len = readInt(u + 4); sourceDebug = readUTF(u + 8, len, new char[len]); ! } else if (ANNOTATIONS ! && "RuntimeInvisibleAnnotations".equals(attrName)) { ianns = u + 8; ! } else if (ANNOTATIONS ! && "RuntimeInvisibleTypeAnnotations".equals(attrName)) { itanns = u + 8; } else if ("BootstrapMethods".equals(attrName)) { int[] bootstrapMethods = new int[readUnsignedShort(u + 8)]; for (int j = 0, v = u + 10; j < bootstrapMethods.length; j++) { bootstrapMethods[j] = v; v += 2 + readUnsignedShort(v + 2) << 1; --- 602,635 ---- int item = readUnsignedShort(u + 10); if (item != 0) { enclosingName = readUTF8(items[item], c); enclosingDesc = readUTF8(items[item] + 2, c); } ! } else if ("Signature".equals(attrName)) { signature = readUTF8(u + 8, c); ! } else if ("RuntimeVisibleAnnotations".equals(attrName)) { anns = u + 8; ! } else if ("RuntimeVisibleTypeAnnotations".equals(attrName)) { tanns = u + 8; } else if ("Deprecated".equals(attrName)) { access |= Opcodes.ACC_DEPRECATED; } else if ("Synthetic".equals(attrName)) { access |= Opcodes.ACC_SYNTHETIC | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE; } else if ("SourceDebugExtension".equals(attrName)) { int len = readInt(u + 4); sourceDebug = readUTF(u + 8, len, new char[len]); ! } else if ("RuntimeInvisibleAnnotations".equals(attrName)) { ianns = u + 8; ! } else if ("RuntimeInvisibleTypeAnnotations".equals(attrName)) { itanns = u + 8; + } else if ("Module".equals(attrName)) { + module = u + 8; + } else if ("ModuleMainClass".equals(attrName)) { + moduleMainClass = readClass(u + 8, c); + } else if ("ModulePackages".equals(attrName)) { + packages = u + 10; } else if ("BootstrapMethods".equals(attrName)) { int[] bootstrapMethods = new int[readUnsignedShort(u + 8)]; for (int j = 0, v = u + 10; j < bootstrapMethods.length; j++) { bootstrapMethods[j] = v; v += 2 + readUnsignedShort(v + 2) << 1;
*** 655,692 **** if ((flags & SKIP_DEBUG) == 0 && (sourceFile != null || sourceDebug != null)) { classVisitor.visitSource(sourceFile, sourceDebug); } // visits the outer class if (enclosingOwner != null) { classVisitor.visitOuterClass(enclosingOwner, enclosingName, enclosingDesc); } // visits the class annotations and type annotations ! if (ANNOTATIONS && anns != 0) { for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) { v = readAnnotationValues(v + 2, c, true, classVisitor.visitAnnotation(readUTF8(v, c), true)); } } ! if (ANNOTATIONS && ianns != 0) { for (int i = readUnsignedShort(ianns), v = ianns + 2; i > 0; --i) { v = readAnnotationValues(v + 2, c, true, classVisitor.visitAnnotation(readUTF8(v, c), false)); } } ! if (ANNOTATIONS && tanns != 0) { for (int i = readUnsignedShort(tanns), v = tanns + 2; i > 0; --i) { v = readAnnotationTarget(context, v); v = readAnnotationValues(v + 2, c, true, classVisitor.visitTypeAnnotation(context.typeRef, context.typePath, readUTF8(v, c), true)); } } ! if (ANNOTATIONS && itanns != 0) { for (int i = readUnsignedShort(itanns), v = itanns + 2; i > 0; --i) { v = readAnnotationTarget(context, v); v = readAnnotationValues(v + 2, c, true, classVisitor.visitTypeAnnotation(context.typeRef, context.typePath, readUTF8(v, c), false)); --- 654,697 ---- if ((flags & SKIP_DEBUG) == 0 && (sourceFile != null || sourceDebug != null)) { classVisitor.visitSource(sourceFile, sourceDebug); } + // visits the module info and associated attributes + if (module != 0) { + readModule(classVisitor, context, module, + moduleMainClass, packages); + } + // visits the outer class if (enclosingOwner != null) { classVisitor.visitOuterClass(enclosingOwner, enclosingName, enclosingDesc); } // visits the class annotations and type annotations ! if (anns != 0) { for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) { v = readAnnotationValues(v + 2, c, true, classVisitor.visitAnnotation(readUTF8(v, c), true)); } } ! if (ianns != 0) { for (int i = readUnsignedShort(ianns), v = ianns + 2; i > 0; --i) { v = readAnnotationValues(v + 2, c, true, classVisitor.visitAnnotation(readUTF8(v, c), false)); } } ! if (tanns != 0) { for (int i = readUnsignedShort(tanns), v = tanns + 2; i > 0; --i) { v = readAnnotationTarget(context, v); v = readAnnotationValues(v + 2, c, true, classVisitor.visitTypeAnnotation(context.typeRef, context.typePath, readUTF8(v, c), true)); } } ! if (itanns != 0) { for (int i = readUnsignedShort(itanns), v = itanns + 2; i > 0; --i) { v = readAnnotationTarget(context, v); v = readAnnotationValues(v + 2, c, true, classVisitor.visitTypeAnnotation(context.typeRef, context.typePath, readUTF8(v, c), false));
*** 725,734 **** --- 730,853 ---- // visits the end of the class classVisitor.visitEnd(); } /** + * Reads the module attribute and visit it. + * + * @param classVisitor + * the current class visitor + * @param context + * information about the class being parsed. + * @param u + * start offset of the module attribute in the class file. + * @param mainClass + * name of the main class of a module or null. + * @param packages + * start offset of the concealed package attribute. + */ + private void readModule(final ClassVisitor classVisitor, + final Context context, int u, + final String mainClass, int packages) { + + char[] buffer = context.buffer; + + // reads module name, flags and version + String name = readModule(u, buffer); + int flags = readUnsignedShort(u + 2); + String version = readUTF8(u + 4, buffer); + u += 6; + + ModuleVisitor mv = classVisitor.visitModule(name, flags, version); + if (mv == null) { + return; + } + + // module attributes (main class, packages) + if (mainClass != null) { + mv.visitMainClass(mainClass); + } + + if (packages != 0) { + for (int i = readUnsignedShort(packages - 2); i > 0; --i) { + String packaze = readPackage(packages, buffer); + mv.visitPackage(packaze); + packages += 2; + } + } + + // reads requires + u += 2; + for (int i = readUnsignedShort(u - 2); i > 0; --i) { + String module = readModule(u, buffer); + int access = readUnsignedShort(u + 2); + String requireVersion = readUTF8(u + 4, buffer); + mv.visitRequire(module, access, requireVersion); + u += 6; + } + + // reads exports + u += 2; + for (int i = readUnsignedShort(u - 2); i > 0; --i) { + String export = readPackage(u, buffer); + int access = readUnsignedShort(u + 2); + int exportToCount = readUnsignedShort(u + 4); + u += 6; + String[] tos = null; + if (exportToCount != 0) { + tos = new String[exportToCount]; + for (int j = 0; j < tos.length; ++j) { + tos[j] = readModule(u, buffer); + u += 2; + } + } + mv.visitExport(export, access, tos); + } + + // reads opens + u += 2; + for (int i = readUnsignedShort(u - 2); i > 0; --i) { + String open = readPackage(u, buffer); + int access = readUnsignedShort(u + 2); + int openToCount = readUnsignedShort(u + 4); + u += 6; + String[] tos = null; + if (openToCount != 0) { + tos = new String[openToCount]; + for (int j = 0; j < tos.length; ++j) { + tos[j] = readModule(u, buffer); + u += 2; + } + } + mv.visitOpen(open, access, tos); + } + + // read uses + u += 2; + for (int i = readUnsignedShort(u - 2); i > 0; --i) { + mv.visitUse(readClass(u, buffer)); + u += 2; + } + + // read provides + u += 2; + for (int i = readUnsignedShort(u - 2); i > 0; --i) { + String service = readClass(u, buffer); + int provideWithCount = readUnsignedShort(u + 2); + u += 4; + String[] withs = new String[provideWithCount]; + for (int j = 0; j < withs.length; ++j) { + withs[j] = readClass(u, buffer); + u += 2; + } + mv.visitProvide(service, withs); + } + + mv.visitEnd(); + } + + /** * Reads a field and makes the given visitor visit it. * * @param classVisitor * the visitor that must visit the field. * @param context
*** 760,787 **** // tests are sorted in decreasing frequency order // (based on frequencies observed on typical classes) if ("ConstantValue".equals(attrName)) { int item = readUnsignedShort(u + 8); value = item == 0 ? null : readConst(item, c); ! } else if (SIGNATURES && "Signature".equals(attrName)) { signature = readUTF8(u + 8, c); } else if ("Deprecated".equals(attrName)) { access |= Opcodes.ACC_DEPRECATED; } else if ("Synthetic".equals(attrName)) { access |= Opcodes.ACC_SYNTHETIC | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE; ! } else if (ANNOTATIONS ! && "RuntimeVisibleAnnotations".equals(attrName)) { anns = u + 8; ! } else if (ANNOTATIONS ! && "RuntimeVisibleTypeAnnotations".equals(attrName)) { tanns = u + 8; ! } else if (ANNOTATIONS ! && "RuntimeInvisibleAnnotations".equals(attrName)) { ianns = u + 8; ! } else if (ANNOTATIONS ! && "RuntimeInvisibleTypeAnnotations".equals(attrName)) { itanns = u + 8; } else { Attribute attr = readAttribute(context.attrs, attrName, u + 8, readInt(u + 4), c, -1, null); if (attr != null) { --- 879,902 ---- // tests are sorted in decreasing frequency order // (based on frequencies observed on typical classes) if ("ConstantValue".equals(attrName)) { int item = readUnsignedShort(u + 8); value = item == 0 ? null : readConst(item, c); ! } else if ("Signature".equals(attrName)) { signature = readUTF8(u + 8, c); } else if ("Deprecated".equals(attrName)) { access |= Opcodes.ACC_DEPRECATED; } else if ("Synthetic".equals(attrName)) { access |= Opcodes.ACC_SYNTHETIC | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE; ! } else if ("RuntimeVisibleAnnotations".equals(attrName)) { anns = u + 8; ! } else if ("RuntimeVisibleTypeAnnotations".equals(attrName)) { tanns = u + 8; ! } else if ("RuntimeInvisibleAnnotations".equals(attrName)) { ianns = u + 8; ! } else if ("RuntimeInvisibleTypeAnnotations".equals(attrName)) { itanns = u + 8; } else { Attribute attr = readAttribute(context.attrs, attrName, u + 8, readInt(u + 4), c, -1, null); if (attr != null) {
*** 799,829 **** if (fv == null) { return u; } // visits the field annotations and type annotations ! if (ANNOTATIONS && anns != 0) { for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) { v = readAnnotationValues(v + 2, c, true, fv.visitAnnotation(readUTF8(v, c), true)); } } ! if (ANNOTATIONS && ianns != 0) { for (int i = readUnsignedShort(ianns), v = ianns + 2; i > 0; --i) { v = readAnnotationValues(v + 2, c, true, fv.visitAnnotation(readUTF8(v, c), false)); } } ! if (ANNOTATIONS && tanns != 0) { for (int i = readUnsignedShort(tanns), v = tanns + 2; i > 0; --i) { v = readAnnotationTarget(context, v); v = readAnnotationValues(v + 2, c, true, fv.visitTypeAnnotation(context.typeRef, context.typePath, readUTF8(v, c), true)); } } ! if (ANNOTATIONS && itanns != 0) { for (int i = readUnsignedShort(itanns), v = itanns + 2; i > 0; --i) { v = readAnnotationTarget(context, v); v = readAnnotationValues(v + 2, c, true, fv.visitTypeAnnotation(context.typeRef, context.typePath, readUTF8(v, c), false)); --- 914,944 ---- if (fv == null) { return u; } // visits the field annotations and type annotations ! if (anns != 0) { for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) { v = readAnnotationValues(v + 2, c, true, fv.visitAnnotation(readUTF8(v, c), true)); } } ! if (ianns != 0) { for (int i = readUnsignedShort(ianns), v = ianns + 2; i > 0; --i) { v = readAnnotationValues(v + 2, c, true, fv.visitAnnotation(readUTF8(v, c), false)); } } ! if (tanns != 0) { for (int i = readUnsignedShort(tanns), v = tanns + 2; i > 0; --i) { v = readAnnotationTarget(context, v); v = readAnnotationValues(v + 2, c, true, fv.visitTypeAnnotation(context.typeRef, context.typePath, readUTF8(v, c), true)); } } ! if (itanns != 0) { for (int i = readUnsignedShort(itanns), v = itanns + 2; i > 0; --i) { v = readAnnotationTarget(context, v); v = readAnnotationValues(v + 2, c, true, fv.visitTypeAnnotation(context.typeRef, context.typePath, readUTF8(v, c), false));
*** 893,928 **** exception = u + 10; for (int j = 0; j < exceptions.length; ++j) { exceptions[j] = readClass(exception, c); exception += 2; } ! } else if (SIGNATURES && "Signature".equals(attrName)) { signature = readUTF8(u + 8, c); } else if ("Deprecated".equals(attrName)) { context.access |= Opcodes.ACC_DEPRECATED; ! } else if (ANNOTATIONS ! && "RuntimeVisibleAnnotations".equals(attrName)) { anns = u + 8; ! } else if (ANNOTATIONS ! && "RuntimeVisibleTypeAnnotations".equals(attrName)) { tanns = u + 8; ! } else if (ANNOTATIONS && "AnnotationDefault".equals(attrName)) { dann = u + 8; } else if ("Synthetic".equals(attrName)) { context.access |= Opcodes.ACC_SYNTHETIC | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE; ! } else if (ANNOTATIONS ! && "RuntimeInvisibleAnnotations".equals(attrName)) { ianns = u + 8; ! } else if (ANNOTATIONS ! && "RuntimeInvisibleTypeAnnotations".equals(attrName)) { itanns = u + 8; ! } else if (ANNOTATIONS ! && "RuntimeVisibleParameterAnnotations".equals(attrName)) { mpanns = u + 8; ! } else if (ANNOTATIONS ! && "RuntimeInvisibleParameterAnnotations".equals(attrName)) { impanns = u + 8; } else if ("MethodParameters".equals(attrName)) { methodParameters = u + 8; } else { Attribute attr = readAttribute(context.attrs, attrName, u + 8, --- 1008,1037 ---- exception = u + 10; for (int j = 0; j < exceptions.length; ++j) { exceptions[j] = readClass(exception, c); exception += 2; } ! } else if ("Signature".equals(attrName)) { signature = readUTF8(u + 8, c); } else if ("Deprecated".equals(attrName)) { context.access |= Opcodes.ACC_DEPRECATED; ! } else if ("RuntimeVisibleAnnotations".equals(attrName)) { anns = u + 8; ! } else if ("RuntimeVisibleTypeAnnotations".equals(attrName)) { tanns = u + 8; ! } else if ("AnnotationDefault".equals(attrName)) { dann = u + 8; } else if ("Synthetic".equals(attrName)) { context.access |= Opcodes.ACC_SYNTHETIC | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE; ! } else if ("RuntimeInvisibleAnnotations".equals(attrName)) { ianns = u + 8; ! } else if ("RuntimeInvisibleTypeAnnotations".equals(attrName)) { itanns = u + 8; ! } else if ("RuntimeVisibleParameterAnnotations".equals(attrName)) { mpanns = u + 8; ! } else if ("RuntimeInvisibleParameterAnnotations".equals(attrName)) { impanns = u + 8; } else if ("MethodParameters".equals(attrName)) { methodParameters = u + 8; } else { Attribute attr = readAttribute(context.attrs, attrName, u + 8,
*** 951,961 **** * have not been changed, then it is possible to skip all visit events * and just copy the original code of the method to the writer (the * access, name and descriptor can have been changed, this is not * important since they are not copied as is from the reader). */ ! if (WRITER && mv instanceof MethodWriter) { MethodWriter mw = (MethodWriter) mv; if (mw.cw.cr == this && signature == mw.signature) { boolean sameExceptions = false; if (exceptions == null) { sameExceptions = mw.exceptionCount == 0; --- 1060,1070 ---- * have not been changed, then it is possible to skip all visit events * and just copy the original code of the method to the writer (the * access, name and descriptor can have been changed, this is not * important since they are not copied as is from the reader). */ ! if (mv instanceof MethodWriter) { MethodWriter mw = (MethodWriter) mv; if (mw.cw.cr == this && signature == mw.signature) { boolean sameExceptions = false; if (exceptions == null) { sameExceptions = mw.exceptionCount == 0;
*** 988,1036 **** mv.visitParameter(readUTF8(v, c), readUnsignedShort(v + 2)); } } // visits the method annotations ! if (ANNOTATIONS && dann != 0) { AnnotationVisitor dv = mv.visitAnnotationDefault(); readAnnotationValue(dann, c, null, dv); if (dv != null) { dv.visitEnd(); } } ! if (ANNOTATIONS && anns != 0) { for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) { v = readAnnotationValues(v + 2, c, true, mv.visitAnnotation(readUTF8(v, c), true)); } } ! if (ANNOTATIONS && ianns != 0) { for (int i = readUnsignedShort(ianns), v = ianns + 2; i > 0; --i) { v = readAnnotationValues(v + 2, c, true, mv.visitAnnotation(readUTF8(v, c), false)); } } ! if (ANNOTATIONS && tanns != 0) { for (int i = readUnsignedShort(tanns), v = tanns + 2; i > 0; --i) { v = readAnnotationTarget(context, v); v = readAnnotationValues(v + 2, c, true, mv.visitTypeAnnotation(context.typeRef, context.typePath, readUTF8(v, c), true)); } } ! if (ANNOTATIONS && itanns != 0) { for (int i = readUnsignedShort(itanns), v = itanns + 2; i > 0; --i) { v = readAnnotationTarget(context, v); v = readAnnotationValues(v + 2, c, true, mv.visitTypeAnnotation(context.typeRef, context.typePath, readUTF8(v, c), false)); } } ! if (ANNOTATIONS && mpanns != 0) { readParameterAnnotations(mv, context, mpanns, true); } ! if (ANNOTATIONS && impanns != 0) { readParameterAnnotations(mv, context, impanns, false); } // visits the method attributes while (attributes != null) { --- 1097,1145 ---- mv.visitParameter(readUTF8(v, c), readUnsignedShort(v + 2)); } } // visits the method annotations ! if (dann != 0) { AnnotationVisitor dv = mv.visitAnnotationDefault(); readAnnotationValue(dann, c, null, dv); if (dv != null) { dv.visitEnd(); } } ! if (anns != 0) { for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) { v = readAnnotationValues(v + 2, c, true, mv.visitAnnotation(readUTF8(v, c), true)); } } ! if (ianns != 0) { for (int i = readUnsignedShort(ianns), v = ianns + 2; i > 0; --i) { v = readAnnotationValues(v + 2, c, true, mv.visitAnnotation(readUTF8(v, c), false)); } } ! if (tanns != 0) { for (int i = readUnsignedShort(tanns), v = tanns + 2; i > 0; --i) { v = readAnnotationTarget(context, v); v = readAnnotationValues(v + 2, c, true, mv.visitTypeAnnotation(context.typeRef, context.typePath, readUTF8(v, c), true)); } } ! if (itanns != 0) { for (int i = readUnsignedShort(itanns), v = itanns + 2; i > 0; --i) { v = readAnnotationTarget(context, v); v = readAnnotationValues(v + 2, c, true, mv.visitTypeAnnotation(context.typeRef, context.typePath, readUTF8(v, c), false)); } } ! if (mpanns != 0) { readParameterAnnotations(mv, context, mpanns, true); } ! if (impanns != 0) { readParameterAnnotations(mv, context, impanns, false); } // visits the method attributes while (attributes != null) {
*** 1073,1097 **** // reads the bytecode to find the labels int codeStart = u; int codeEnd = u + codeLength; Label[] labels = context.labels = new Label[codeLength + 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) { --- 1182,1211 ---- // reads the bytecode to find the labels int codeStart = u; int codeEnd = u + codeLength; Label[] labels = context.labels = new Label[codeLength + 2]; ! createLabel(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: ! createLabel(offset + readShort(u + 1), labels); u += 3; break; + case ClassWriter.ASM_LABEL_INSN: + createLabel(offset + readUnsignedShort(u + 1), labels); + u += 3; + break; case ClassWriter.LABELW_INSN: ! case ClassWriter.ASM_LABELW_INSN: ! createLabel(offset + readInt(u + 1), labels); u += 5; break; case ClassWriter.WIDE_INSN: opcode = b[u + 1] & 0xFF; if (opcode == Opcodes.IINC) {
*** 1102,1125 **** 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: --- 1216,1239 ---- break; case ClassWriter.TABL_INSN: // skips 0 to 3 padding bytes u = u + 4 - (offset & 3); // reads instruction ! createLabel(offset + readInt(u), labels); for (int i = readInt(u + 8) - readInt(u + 4) + 1; i > 0; --i) { ! createLabel(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 ! createLabel(offset + readInt(u), labels); for (int i = readInt(u + 4); i > 0; --i) { ! createLabel(offset + readInt(u + 12), labels); u += 8; } u += 8; break; case ClassWriter.VAR_INSN:
*** 1145,1157 **** } } // 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; --- 1259,1271 ---- } } // reads the try catch entries to find the labels, and also visits them for (int i = readUnsignedShort(u); i > 0; --i) { ! Label start = createLabel(readUnsignedShort(u + 2), labels); ! Label end = createLabel(readUnsignedShort(u + 4), labels); ! Label handler = createLabel(readUnsignedShort(u + 6), labels); String type = readUTF8(items[readUnsignedShort(u + 8)], c); mv.visitTryCatchBlock(start, end, handler, type); u += 8; } u += 2;
*** 1178,1206 **** 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; ! } Label l = labels[label]; while (l.line > 0) { if (l.next == null) { l.next = new Label(); } --- 1292,1314 ---- 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); ! createDebugLabel(label, labels); label += readUnsignedShort(v + 12); ! createDebugLabel(label, labels); 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); ! createDebugLabel(label, labels); Label l = labels[label]; while (l.line > 0) { if (l.next == null) { l.next = new Label(); }
*** 1208,1228 **** } l.line = readUnsignedShort(v + 12); v += 4; } } ! } else if (ANNOTATIONS ! && "RuntimeVisibleTypeAnnotations".equals(attrName)) { tanns = readTypeAnnotations(mv, context, u + 8, true); ntoff = tanns.length == 0 || readByte(tanns[0]) < 0x43 ? -1 : readUnsignedShort(tanns[0] + 1); ! } else if (ANNOTATIONS ! && "RuntimeInvisibleTypeAnnotations".equals(attrName)) { itanns = readTypeAnnotations(mv, context, u + 8, false); nitoff = itanns.length == 0 || readByte(itanns[0]) < 0x43 ? -1 : readUnsignedShort(itanns[0] + 1); ! } else if (FRAMES && "StackMapTable".equals(attrName)) { if ((context.flags & SKIP_FRAMES) == 0) { stackMap = u + 10; stackMapSize = readInt(u + 4); frameCount = readUnsignedShort(u + 8); } --- 1316,1334 ---- } l.line = readUnsignedShort(v + 12); v += 4; } } ! } else if ("RuntimeVisibleTypeAnnotations".equals(attrName)) { tanns = readTypeAnnotations(mv, context, u + 8, true); ntoff = tanns.length == 0 || readByte(tanns[0]) < 0x43 ? -1 : readUnsignedShort(tanns[0] + 1); ! } else if ("RuntimeInvisibleTypeAnnotations".equals(attrName)) { itanns = readTypeAnnotations(mv, context, u + 8, false); nitoff = itanns.length == 0 || readByte(itanns[0]) < 0x43 ? -1 : readUnsignedShort(itanns[0] + 1); ! } else if ("StackMapTable".equals(attrName)) { if ((context.flags & SKIP_FRAMES) == 0) { stackMap = u + 10; stackMapSize = readInt(u + 4); frameCount = readUnsignedShort(u + 8); }
*** 1242,1252 **** /* * 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); --- 1348,1358 ---- /* * 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 ("StackMap".equals(attrName)) { if ((context.flags & SKIP_FRAMES) == 0) { zip = false; stackMap = u + 10; stackMapSize = readInt(u + 4); frameCount = readUnsignedShort(u + 8);
*** 1271,1281 **** u += 6 + readInt(u + 4); } u += 2; // generates the first (implicit) stack map frame ! if (FRAMES && stackMap != 0) { /* * 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 */ --- 1377,1387 ---- u += 6 + readInt(u + 4); } u += 2; // generates the first (implicit) stack map frame ! if (stackMap != 0) { /* * 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 */
*** 1304,1321 **** 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 --- 1410,1444 ---- 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) { ! createLabel(v, labels); } } } } } + if ((context.flags & EXPAND_ASM_INSNS) != 0 + && (context.flags & EXPAND_FRAMES) != 0) { + // Expanding the ASM pseudo instructions can introduce F_INSERT + // frames, even if the method does not currently have any frame. + // Also these inserted frames must be computed by simulating the + // effect of the bytecode instructions one by one, starting from the + // first one and the last existing frame (or the implicit first + // one). Finally, due to the way MethodWriter computes this (with + // the compute = INSERTED_FRAMES option), MethodWriter needs to know + // maxLocals before the first instruction is visited. For all these + // reasons we always visit the implicit first frame in this case + // (passing only maxLocals - the rest can be and is computed in + // MethodWriter). + mv.visitFrame(Opcodes.F_NEW, maxLocals, null, 0, null); + } // visits the instructions + int opcodeDelta = (context.flags & EXPAND_ASM_INSNS) == 0 ? -33 : 0; + boolean insertFrame = false; u = codeStart; while (u < codeEnd) { int offset = u - codeStart; // visits the label and line number for this offset, if any
*** 1332,1342 **** } } } // visits the frame 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 (frame.offset != -1) { if (!zip || unzip) { --- 1455,1465 ---- } } } // visits the frame for this offset, if any ! while (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 (frame.offset != -1) { if (!zip || unzip) {
*** 1344,1361 **** --- 1467,1494 ---- frame.local, frame.stackCount, frame.stack); } else { mv.visitFrame(frame.mode, frame.localDiff, frame.local, frame.stackCount, frame.stack); } + // if there is already a frame for this offset, there is no + // need to insert a new one. + insertFrame = false; } if (frameCount > 0) { stackMap = readFrame(stackMap, zip, unzip, frame); --frameCount; } else { frame = null; } } + // inserts a frame for this offset, if requested by setting + // insertFrame to true during the previous iteration. The actual + // frame content will be computed in MethodWriter. + if (insertFrame) { + mv.visitFrame(ClassWriter.F_INSERT, 0, null, 0, null); + insertFrame = false; + } // visits the instruction at this offset int opcode = b[u] & 0xFF; switch (ClassWriter.TYPE[opcode]) { case ClassWriter.NOARG_INSN:
*** 1376,1388 **** 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; --- 1509,1559 ---- case ClassWriter.LABEL_INSN: mv.visitJumpInsn(opcode, labels[offset + readShort(u + 1)]); u += 3; break; case ClassWriter.LABELW_INSN: ! mv.visitJumpInsn(opcode + opcodeDelta, labels[offset ! + readInt(u + 1)]); u += 5; break; + case ClassWriter.ASM_LABEL_INSN: { + // changes temporary opcodes 202 to 217 (inclusive), 218 + // and 219 to IFEQ ... JSR (inclusive), IFNULL and + // IFNONNULL + opcode = opcode < 218 ? opcode - 49 : opcode - 20; + Label target = labels[offset + readUnsignedShort(u + 1)]; + // replaces GOTO with GOTO_W, JSR with JSR_W and IFxxx + // <l> with IFNOTxxx <L> GOTO_W <l> L:..., where IFNOTxxx is + // the "opposite" opcode of IFxxx (i.e., IFNE for IFEQ) + // and where <L> designates the instruction just after + // the GOTO_W. + if (opcode == Opcodes.GOTO || opcode == Opcodes.JSR) { + mv.visitJumpInsn(opcode + 33, target); + } else { + opcode = opcode <= 166 ? ((opcode + 1) ^ 1) - 1 + : opcode ^ 1; + Label endif = createLabel(offset + 3, labels); + mv.visitJumpInsn(opcode, endif); + mv.visitJumpInsn(200, target); // GOTO_W + // endif designates the instruction just after GOTO_W, + // and is visited as part of the next instruction. Since + // it is a jump target, we need to insert a frame here. + insertFrame = true; + } + u += 3; + break; + } + case ClassWriter.ASM_LABELW_INSN: { + // replaces the pseudo GOTO_W instruction with a real one. + mv.visitJumpInsn(200, labels[offset + readInt(u + 1)]); + // The instruction just after is a jump target (because pseudo + // GOTO_W are used in patterns IFNOTxxx <L> GOTO_W <l> L:..., + // see MethodWriter), so we need to insert a frame here. + insertFrame = true; + 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;
*** 1634,1645 **** case 0x40: // LOCAL_VARIABLE case 0x41: // RESOURCE_VARIABLE for (int j = readUnsignedShort(u + 1); j > 0; --j) { int start = readUnsignedShort(u + 3); int length = readUnsignedShort(u + 5); ! readLabel(start, context.labels); ! readLabel(start + length, context.labels); u += 6; } u += 3; break; case 0x47: // CAST --- 1805,1816 ---- case 0x40: // LOCAL_VARIABLE case 0x41: // RESOURCE_VARIABLE for (int j = readUnsignedShort(u + 1); j > 0; --j) { int start = readUnsignedShort(u + 3); int length = readUnsignedShort(u + 5); ! createLabel(start, context.labels); ! createLabel(start + length, context.labels); u += 6; } u += 3; break; case 0x47: // CAST
*** 1714,1725 **** context.index = new int[n]; u += 3; for (int i = 0; i < n; ++i) { int start = readUnsignedShort(u); int length = readUnsignedShort(u + 2); ! context.start[i] = readLabel(start, context.labels); ! context.end[i] = readLabel(start + length, context.labels); context.index[i] = readUnsignedShort(u + 4); u += 6; } break; } --- 1885,1896 ---- context.index = new int[n]; u += 3; for (int i = 0; i < n; ++i) { int start = readUnsignedShort(u); int length = readUnsignedShort(u + 2); ! context.start[i] = createLabel(start, context.labels); ! context.end[i] = createLabel(start + length, context.labels); context.index[i] = readUnsignedShort(u + 4); u += 6; } break; }
*** 2135,2145 **** labels); } } } frame.offset += delta + 1; ! readLabel(frame.offset, labels); return stackMap; } /** * Reads a stack map frame type and stores it at the given index in the --- 2306,2316 ---- labels); } } } frame.offset += delta + 1; ! createLabel(frame.offset, labels); return stackMap; } /** * Reads a stack map frame type and stores it at the given index in the
*** 2188,2198 **** case 7: // Object frame[index] = readClass(v, buf); v += 2; break; default: // Uninitialized ! frame[index] = readLabel(readUnsignedShort(v), labels); v += 2; } return v; } --- 2359,2369 ---- case 7: // Object frame[index] = readClass(v, buf); v += 2; break; default: // Uninitialized ! frame[index] = createLabel(readUnsignedShort(v), labels); v += 2; } return v; }
*** 2215,2224 **** --- 2386,2428 ---- } return labels[offset]; } /** + * Creates a label without the Label.DEBUG flag set, for the given offset. + * The label is created with a call to {@link #readLabel} and its + * Label.DEBUG flag is cleared. + * + * @param offset + * a bytecode offset in a method. + * @param labels + * the already created labels, indexed by their offset. + * @return a Label without the Label.DEBUG flag set. + */ + private Label createLabel(int offset, Label[] labels) { + Label label = readLabel(offset, labels); + label.status &= ~Label.DEBUG; + return label; + } + + /** + * Creates a label with the Label.DEBUG flag set, if there is no already + * existing label for the given offset (otherwise does nothing). The label + * is created with a call to {@link #readLabel}. + * + * @param offset + * a bytecode offset in a method. + * @param labels + * the already created labels, indexed by their offset. + */ + private void createDebugLabel(int offset, Label[] labels) { + if (labels[offset] == null) { + readLabel(offset, labels).status |= Label.DEBUG; + } + } + + /** * Returns the start index of the attribute_info structure of this class. * * @return the start index of the attribute_info structure of this class. */ private int getAttributes() {
*** 2469,2478 **** --- 2673,2696 ---- } return new String(buf, 0, strLen); } /** + * Read a stringish constant item (CONSTANT_Class, CONSTANT_String, + * CONSTANT_MethodType, CONSTANT_Module or CONSTANT_Package + * @param index + * @param buf + * @return + */ + private String readStringish(final int index, final char[] buf) { + // computes the start index of the item in b + // and reads the CONSTANT_Utf8 item designated by + // the first two bytes of this item + return readUTF8(items[readUnsignedShort(index)], buf); + } + + /** * Reads a class 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 index
*** 2482,2529 **** * buffer to be used to read the item. This buffer must be * sufficiently large. It is not automatically resized. * @return the String corresponding to the specified class item. */ public String readClass(final int index, final char[] buf) { ! // computes the start index of the CONSTANT_Class item in b ! // and reads the CONSTANT_Utf8 item designated by ! // the first two bytes of this CONSTANT_Class item ! return readUTF8(items[readUnsignedShort(index)], buf); } /** ! * Reads a CONSTANT_Module_info item in {@code b}. This method is intended ! * for {@link Attribute} sub classes, and is normally not needed by class ! * generators or adapters.</i> * * @param index * the start index of an unsigned short value in {@link #b b}, * whose value is the index of a module 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 String corresponding to the specified module item. */ ! public String readModule(int index, char[] buf) { ! return readUTF8(items[readUnsignedShort(index)], buf); } /** ! * Reads a CONSTANT_Package_info item in {@code b}. This method is ! * intended for {@link Attribute} sub slasses, and is normally not needed ! * by class generators or adapters.</i> * * @param index * the start index of an unsigned short value in {@link #b b}, ! * whose value is the index of a package 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 String corresponding to the specified package item. */ ! public String readPackage(int index, char[] buf) { ! return readUTF8(items[readUnsignedShort(index)], buf); } /** * 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 --- 2700,2744 ---- * buffer to be used to read the item. This buffer must be * sufficiently large. It is not automatically resized. * @return the String corresponding to the specified class item. */ public String readClass(final int index, final char[] buf) { ! return readStringish(index, buf); } /** ! * Reads a module 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 index * the start index of an unsigned short value in {@link #b b}, * whose value is the index of a module 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 String corresponding to the specified module item. */ ! public String readModule(final int index, final char[] buf) { ! return readStringish(index, buf); } /** ! * Reads a module 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 index * the start index of an unsigned short value in {@link #b b}, ! * whose value is the index of a module 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 String corresponding to the specified module item. */ ! public String readPackage(final int index, final char[] buf) { ! return readStringish(index, buf); } /** * 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
*** 2548,2559 **** case ClassWriter.LONG: return readLong(index); case ClassWriter.DOUBLE: return Double.longBitsToDouble(readLong(index)); case ClassWriter.CLASS: - case ClassWriter.MODULE: - case ClassWriter.PACKAGE: return Type.getObjectType(readUTF8(index, buf)); case ClassWriter.STR: return readUTF8(index, buf); case ClassWriter.MTYPE: return Type.getMethodType(readUTF8(index, buf)); --- 2763,2772 ----
< prev index next >