From 5a0eff2b67e869f8fd94c30302c34a175f7e1793 Mon Sep 17 00:00:00 2001 From: Redkale <22250530@qq.com> Date: Wed, 4 Apr 2018 13:46:27 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0asm=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/org/redkale/asm/AnnotationVisitor.java | 10 +- src/org/redkale/asm/AnnotationWriter.java | 2 +- src/org/redkale/asm/Attribute.java | 2 +- src/org/redkale/asm/ClassReader.java | 493 +++++++---- src/org/redkale/asm/ClassVisitor.java | 32 +- src/org/redkale/asm/ClassWriter.java | 294 ++++--- src/org/redkale/asm/CurrentFrame.java | 85 ++ src/org/redkale/asm/FieldVisitor.java | 8 +- src/org/redkale/asm/FieldWriter.java | 40 +- src/org/redkale/asm/Frame.java | 120 ++- src/org/redkale/asm/Item.java | 5 +- src/org/redkale/asm/Label.java | 12 +- src/org/redkale/asm/MethodVisitor.java | 8 +- src/org/redkale/asm/MethodWriter.java | 828 ++++--------------- src/org/redkale/asm/ModuleVisitor.java | 219 +++++ src/org/redkale/asm/ModuleWriter.java | 322 ++++++++ src/org/redkale/asm/Opcodes.java | 63 +- src/org/redkale/asm/Type.java | 11 +- src/org/redkale/asm/TypeReference.java | 908 +++++++++++---------- test/org/redkale/test/asm/AsmCreator.java | 5 +- 20 files changed, 1986 insertions(+), 1481 deletions(-) create mode 100644 src/org/redkale/asm/CurrentFrame.java create mode 100644 src/org/redkale/asm/ModuleVisitor.java create mode 100644 src/org/redkale/asm/ModuleWriter.java diff --git a/src/org/redkale/asm/AnnotationVisitor.java b/src/org/redkale/asm/AnnotationVisitor.java index 4343411ca..0b5157138 100644 --- a/src/org/redkale/asm/AnnotationVisitor.java +++ b/src/org/redkale/asm/AnnotationVisitor.java @@ -70,7 +70,7 @@ public abstract class AnnotationVisitor { /** * The ASM API version implemented by this visitor. The value of this field - * must be one of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. + * must be one of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. */ protected final int api; @@ -85,7 +85,7 @@ public abstract class AnnotationVisitor { * * @param api * the ASM API version implemented by this visitor. Must be one - * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. + * of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. */ public AnnotationVisitor(final int api) { this(api, null); @@ -96,13 +96,13 @@ public abstract class AnnotationVisitor { * * @param api * the ASM API version implemented by this visitor. Must be one - * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. + * of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. * @param av * the annotation visitor to which this visitor must delegate * method calls. May be null. */ public AnnotationVisitor(final int api, final AnnotationVisitor av) { - if (api != Opcodes.ASM4 && api != Opcodes.ASM5) { + if (api < Opcodes.ASM4 || api > Opcodes.ASM6) { throw new IllegalArgumentException(); } this.api = api; @@ -118,7 +118,7 @@ public abstract class AnnotationVisitor { * the actual value, whose type must be {@link Byte}, * {@link Boolean}, {@link Character}, {@link Short}, * {@link Integer} , {@link Long}, {@link Float}, {@link Double}, - * {@link String} or {@link Type} or OBJECT or ARRAY sort. This + * {@link String} or {@link Type} of OBJECT or ARRAY sort. This * value can also be an array of byte, boolean, short, char, int, * long, float or double values (this is equivalent to using * {@link #visitArray visitArray} and visiting each array element diff --git a/src/org/redkale/asm/AnnotationWriter.java b/src/org/redkale/asm/AnnotationWriter.java index d7fafa299..676fc445c 100644 --- a/src/org/redkale/asm/AnnotationWriter.java +++ b/src/org/redkale/asm/AnnotationWriter.java @@ -133,7 +133,7 @@ final class AnnotationWriter extends AnnotationVisitor { */ AnnotationWriter(final ClassWriter cw, final boolean named, final ByteVector bv, final ByteVector parent, final int offset) { - super(Opcodes.ASM5); + super(Opcodes.ASM6); this.cw = cw; this.named = named; this.bv = bv; diff --git a/src/org/redkale/asm/Attribute.java b/src/org/redkale/asm/Attribute.java index 1e823df9f..07e9923e5 100644 --- a/src/org/redkale/asm/Attribute.java +++ b/src/org/redkale/asm/Attribute.java @@ -64,7 +64,7 @@ package org.redkale.asm; * @author Eric Bruneton * @author Eugene Kuleshov */ -public class Attribute { +class Attribute { /** * The type of this attribute. diff --git a/src/org/redkale/asm/ClassReader.java b/src/org/redkale/asm/ClassReader.java index a608c344c..e1db9ddf7 100644 --- a/src/org/redkale/asm/ClassReader.java +++ b/src/org/redkale/asm/ClassReader.java @@ -72,31 +72,6 @@ import java.io.InputStream; */ 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 * attribute won't be visited. This can be used, for example, to retrieve @@ -133,6 +108,21 @@ public class ClassReader { */ 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 not 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. The content of this array must not be * modified. This field is intended for {@link Attribute} sub classes, and @@ -195,8 +185,8 @@ public class ClassReader { 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(); + if (readShort(off + 6) > Opcodes.V10) { + //throw new IllegalArgumentException(); } // parses the constant pool items = new int[readUnsignedShort(off + 8)]; @@ -234,6 +224,8 @@ public class ClassReader { // case ClassWriter.CLASS: // case ClassWriter.STR: // case ClassWriter.MTYPE + // case ClassWriter.PACKAGE: + // case ClassWriter.MODULE: default: size = 3; break; @@ -377,7 +369,9 @@ public class ClassReader { break; // case ClassWriter.STR: // case ClassWriter.CLASS: - // case ClassWriter.MTYPE + // case ClassWriter.MTYPE: + // case ClassWriter.MODULE: + // case ClassWriter.PACKAGE: default: item.set(tag, readUTF8(index, buf), null, null); break; @@ -584,11 +578,14 @@ public class ClassReader { 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(); @@ -607,13 +604,11 @@ public class ClassReader { enclosingName = readUTF8(items[item], c); enclosingDesc = readUTF8(items[item] + 2, c); } - } else if (SIGNATURES && "Signature".equals(attrName)) { + } else if ("Signature".equals(attrName)) { signature = readUTF8(u + 8, c); - } else if (ANNOTATIONS - && "RuntimeVisibleAnnotations".equals(attrName)) { + } else if ("RuntimeVisibleAnnotations".equals(attrName)) { anns = u + 8; - } else if (ANNOTATIONS - && "RuntimeVisibleTypeAnnotations".equals(attrName)) { + } else if ("RuntimeVisibleTypeAnnotations".equals(attrName)) { tanns = u + 8; } else if ("Deprecated".equals(attrName)) { access |= Opcodes.ACC_DEPRECATED; @@ -623,12 +618,16 @@ public class ClassReader { } else if ("SourceDebugExtension".equals(attrName)) { int len = readInt(u + 4); sourceDebug = readUTF(u + 8, len, new char[len]); - } else if (ANNOTATIONS - && "RuntimeInvisibleAnnotations".equals(attrName)) { + } else if ("RuntimeInvisibleAnnotations".equals(attrName)) { ianns = u + 8; - } else if (ANNOTATIONS - && "RuntimeInvisibleTypeAnnotations".equals(attrName)) { + } 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++) { @@ -657,6 +656,12 @@ public class ClassReader { 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, @@ -664,19 +669,19 @@ public class ClassReader { } // visits the class annotations and type annotations - if (ANNOTATIONS && anns != 0) { + 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 (ANNOTATIONS && ianns != 0) { + 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 (ANNOTATIONS && tanns != 0) { + if (tanns != 0) { for (int i = readUnsignedShort(tanns), v = tanns + 2; i > 0; --i) { v = readAnnotationTarget(context, v); v = readAnnotationValues(v + 2, c, true, @@ -684,7 +689,7 @@ public class ClassReader { context.typePath, readUTF8(v, c), true)); } } - if (ANNOTATIONS && itanns != 0) { + if (itanns != 0) { for (int i = readUnsignedShort(itanns), v = itanns + 2; i > 0; --i) { v = readAnnotationTarget(context, v); v = readAnnotationValues(v + 2, c, true, @@ -726,6 +731,120 @@ public class ClassReader { 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. * @@ -762,24 +881,20 @@ public class ClassReader { if ("ConstantValue".equals(attrName)) { int item = readUnsignedShort(u + 8); value = item == 0 ? null : readConst(item, c); - } else if (SIGNATURES && "Signature".equals(attrName)) { + } 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 (ANNOTATIONS - && "RuntimeVisibleAnnotations".equals(attrName)) { + } else if ("RuntimeVisibleAnnotations".equals(attrName)) { anns = u + 8; - } else if (ANNOTATIONS - && "RuntimeVisibleTypeAnnotations".equals(attrName)) { + } else if ("RuntimeVisibleTypeAnnotations".equals(attrName)) { tanns = u + 8; - } else if (ANNOTATIONS - && "RuntimeInvisibleAnnotations".equals(attrName)) { + } else if ("RuntimeInvisibleAnnotations".equals(attrName)) { ianns = u + 8; - } else if (ANNOTATIONS - && "RuntimeInvisibleTypeAnnotations".equals(attrName)) { + } else if ("RuntimeInvisibleTypeAnnotations".equals(attrName)) { itanns = u + 8; } else { Attribute attr = readAttribute(context.attrs, attrName, u + 8, @@ -801,19 +916,19 @@ public class ClassReader { } // visits the field annotations and type annotations - if (ANNOTATIONS && anns != 0) { + 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 (ANNOTATIONS && ianns != 0) { + 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 (ANNOTATIONS && tanns != 0) { + if (tanns != 0) { for (int i = readUnsignedShort(tanns), v = tanns + 2; i > 0; --i) { v = readAnnotationTarget(context, v); v = readAnnotationValues(v + 2, c, true, @@ -821,7 +936,7 @@ public class ClassReader { context.typePath, readUTF8(v, c), true)); } } - if (ANNOTATIONS && itanns != 0) { + if (itanns != 0) { for (int i = readUnsignedShort(itanns), v = itanns + 2; i > 0; --i) { v = readAnnotationTarget(context, v); v = readAnnotationValues(v + 2, c, true, @@ -895,32 +1010,26 @@ public class ClassReader { exceptions[j] = readClass(exception, c); exception += 2; } - } else if (SIGNATURES && "Signature".equals(attrName)) { + } else if ("Signature".equals(attrName)) { signature = readUTF8(u + 8, c); } else if ("Deprecated".equals(attrName)) { context.access |= Opcodes.ACC_DEPRECATED; - } else if (ANNOTATIONS - && "RuntimeVisibleAnnotations".equals(attrName)) { + } else if ("RuntimeVisibleAnnotations".equals(attrName)) { anns = u + 8; - } else if (ANNOTATIONS - && "RuntimeVisibleTypeAnnotations".equals(attrName)) { + } else if ("RuntimeVisibleTypeAnnotations".equals(attrName)) { tanns = u + 8; - } else if (ANNOTATIONS && "AnnotationDefault".equals(attrName)) { + } else if ("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)) { + } else if ("RuntimeInvisibleAnnotations".equals(attrName)) { ianns = u + 8; - } else if (ANNOTATIONS - && "RuntimeInvisibleTypeAnnotations".equals(attrName)) { + } else if ("RuntimeInvisibleTypeAnnotations".equals(attrName)) { itanns = u + 8; - } else if (ANNOTATIONS - && "RuntimeVisibleParameterAnnotations".equals(attrName)) { + } else if ("RuntimeVisibleParameterAnnotations".equals(attrName)) { mpanns = u + 8; - } else if (ANNOTATIONS - && "RuntimeInvisibleParameterAnnotations".equals(attrName)) { + } else if ("RuntimeInvisibleParameterAnnotations".equals(attrName)) { impanns = u + 8; } else if ("MethodParameters".equals(attrName)) { methodParameters = u + 8; @@ -953,7 +1062,7 @@ public class ClassReader { * 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) { + if (mv instanceof MethodWriter) { MethodWriter mw = (MethodWriter) mv; if (mw.cw.cr == this && signature == mw.signature) { boolean sameExceptions = false; @@ -990,26 +1099,26 @@ public class ClassReader { } // visits the method annotations - if (ANNOTATIONS && dann != 0) { + if (dann != 0) { AnnotationVisitor dv = mv.visitAnnotationDefault(); readAnnotationValue(dann, c, null, dv); if (dv != null) { dv.visitEnd(); } } - if (ANNOTATIONS && anns != 0) { + 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 (ANNOTATIONS && ianns != 0) { + 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 (ANNOTATIONS && tanns != 0) { + if (tanns != 0) { for (int i = readUnsignedShort(tanns), v = tanns + 2; i > 0; --i) { v = readAnnotationTarget(context, v); v = readAnnotationValues(v + 2, c, true, @@ -1017,7 +1126,7 @@ public class ClassReader { context.typePath, readUTF8(v, c), true)); } } - if (ANNOTATIONS && itanns != 0) { + if (itanns != 0) { for (int i = readUnsignedShort(itanns), v = itanns + 2; i > 0; --i) { v = readAnnotationTarget(context, v); v = readAnnotationValues(v + 2, c, true, @@ -1025,10 +1134,10 @@ public class ClassReader { context.typePath, readUTF8(v, c), false)); } } - if (ANNOTATIONS && mpanns != 0) { + if (mpanns != 0) { readParameterAnnotations(mv, context, mpanns, true); } - if (ANNOTATIONS && impanns != 0) { + if (impanns != 0) { readParameterAnnotations(mv, context, impanns, false); } @@ -1075,7 +1184,7 @@ public class ClassReader { int codeStart = u; int codeEnd = u + codeLength; Label[] labels = context.labels = new Label[codeLength + 2]; - readLabel(codeLength + 1, labels); + createLabel(codeLength + 1, labels); while (u < codeEnd) { int offset = u - codeStart; int opcode = b[u] & 0xFF; @@ -1085,11 +1194,16 @@ public class ClassReader { u += 1; break; case ClassWriter.LABEL_INSN: - readLabel(offset + readShort(u + 1), labels); + 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: - readLabel(offset + readInt(u + 1), labels); + case ClassWriter.ASM_LABELW_INSN: + createLabel(offset + readInt(u + 1), labels); u += 5; break; case ClassWriter.WIDE_INSN: @@ -1104,9 +1218,9 @@ public class ClassReader { // skips 0 to 3 padding bytes u = u + 4 - (offset & 3); // reads instruction - readLabel(offset + readInt(u), labels); + createLabel(offset + readInt(u), labels); for (int i = readInt(u + 8) - readInt(u + 4) + 1; i > 0; --i) { - readLabel(offset + readInt(u + 12), labels); + createLabel(offset + readInt(u + 12), labels); u += 4; } u += 12; @@ -1115,9 +1229,9 @@ public class ClassReader { // skips 0 to 3 padding bytes u = u + 4 - (offset & 3); // reads instruction - readLabel(offset + readInt(u), labels); + createLabel(offset + readInt(u), labels); for (int i = readInt(u + 4); i > 0; --i) { - readLabel(offset + readInt(u + 12), labels); + createLabel(offset + readInt(u + 12), labels); u += 8; } u += 8; @@ -1147,9 +1261,9 @@ public class ClassReader { // 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); + 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; @@ -1180,13 +1294,9 @@ public class ClassReader { 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; - } + createDebugLabel(label, labels); label += readUnsignedShort(v + 12); - if (labels[label] == null) { - readLabel(label, labels).status |= Label.DEBUG; - } + createDebugLabel(label, labels); v += 10; } } @@ -1196,9 +1306,7 @@ public class ClassReader { 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; - } + createDebugLabel(label, labels); Label l = labels[label]; while (l.line > 0) { if (l.next == null) { @@ -1210,17 +1318,15 @@ public class ClassReader { v += 4; } } - } else if (ANNOTATIONS - && "RuntimeVisibleTypeAnnotations".equals(attrName)) { + } 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 (ANNOTATIONS - && "RuntimeInvisibleTypeAnnotations".equals(attrName)) { + } 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 (FRAMES && "StackMapTable".equals(attrName)) { + } else if ("StackMapTable".equals(attrName)) { if ((context.flags & SKIP_FRAMES) == 0) { stackMap = u + 10; stackMapSize = readInt(u + 4); @@ -1244,7 +1350,7 @@ public class ClassReader { * this by parsing the stack map table without a full decoding * (see below). */ - } else if (FRAMES && "StackMap".equals(attrName)) { + } else if ("StackMap".equals(attrName)) { if ((context.flags & SKIP_FRAMES) == 0) { zip = false; stackMap = u + 10; @@ -1273,7 +1379,7 @@ public class ClassReader { u += 2; // generates the first (implicit) stack map frame - if (FRAMES && stackMap != 0) { + 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 @@ -1306,14 +1412,31 @@ public class ClassReader { int v = readUnsignedShort(i + 1); if (v >= 0 && v < codeLength) { if ((b[codeStart + v] & 0xFF) == Opcodes.NEW) { - readLabel(v, labels); + 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; @@ -1334,7 +1457,7 @@ public class ClassReader { } // visits the frame for this offset, if any - while (FRAMES && frame != null + 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. @@ -1346,6 +1469,9 @@ public class ClassReader { 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); @@ -1354,6 +1480,13 @@ public class ClassReader { 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; @@ -1378,9 +1511,47 @@ public class ClassReader { u += 3; break; case ClassWriter.LABELW_INSN: - mv.visitJumpInsn(opcode - 33, labels[offset + readInt(u + 1)]); + 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 + // with IFNOTxxx GOTO_W L:..., where IFNOTxxx is + // the "opposite" opcode of IFxxx (i.e., IFNE for IFEQ) + // and where 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 GOTO_W 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) { @@ -1636,8 +1807,8 @@ public class ClassReader { 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); + createLabel(start, context.labels); + createLabel(start + length, context.labels); u += 6; } u += 3; @@ -1716,8 +1887,8 @@ public class ClassReader { 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.start[i] = createLabel(start, context.labels); + context.end[i] = createLabel(start + length, context.labels); context.index[i] = readUnsignedShort(u + 4); u += 6; } @@ -2137,7 +2308,7 @@ public class ClassReader { } } frame.offset += delta + 1; - readLabel(frame.offset, labels); + createLabel(frame.offset, labels); return stackMap; } @@ -2190,7 +2361,7 @@ public class ClassReader { v += 2; break; default: // Uninitialized - frame[index] = readLabel(readUnsignedShort(v), labels); + frame[index] = createLabel(readUnsignedShort(v), labels); v += 2; } return v; @@ -2216,6 +2387,39 @@ public class ClassReader { 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. * @@ -2470,6 +2674,20 @@ public class ClassReader { 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}. This method is * intended for {@link Attribute} sub classes, and is normally not needed by @@ -2484,44 +2702,41 @@ public class ClassReader { * @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); + return readStringish(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. + * Reads a module constant pool item in {@link #b b}. This method is + * intended for {@link Attribute} sub classes, and is normally not needed by + * class generators or adapters. * - * @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. + * @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); + public String readModule(final int index, final char[] buf) { + return readStringish(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. + * Reads a module constant pool item in {@link #b b}. This method is + * intended for {@link Attribute} sub classes, and is normally not needed by + * class generators or adapters. * - * @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. + * @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(int index, char[] buf) { - return readUTF8(items[readUnsignedShort(index)], buf); + public String readPackage(final int index, final char[] buf) { + return readStringish(index, buf); } /** @@ -2550,8 +2765,6 @@ public class ClassReader { 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); diff --git a/src/org/redkale/asm/ClassVisitor.java b/src/org/redkale/asm/ClassVisitor.java index 8cc5fd903..b9bd39fe6 100644 --- a/src/org/redkale/asm/ClassVisitor.java +++ b/src/org/redkale/asm/ClassVisitor.java @@ -61,7 +61,7 @@ package org.redkale.asm; /** * A visitor to visit a Java class. The methods of this class must be called in * the following order: visit [ visitSource ] [ - * visitOuterClass ] ( visitAnnotation | + * visitModule ][ visitOuterClass ] ( visitAnnotation | * visitTypeAnnotation | visitAttribute )* ( * visitInnerClass | visitField | visitMethod )* * visitEnd. @@ -72,7 +72,7 @@ public abstract class ClassVisitor { /** * The ASM API version implemented by this visitor. The value of this field - * must be one of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. + * must be one of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. */ protected final int api; @@ -87,7 +87,7 @@ public abstract class ClassVisitor { * * @param api * the ASM API version implemented by this visitor. Must be one - * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. + * of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. */ public ClassVisitor(final int api) { this(api, null); @@ -98,13 +98,13 @@ public abstract class ClassVisitor { * * @param api * the ASM API version implemented by this visitor. Must be one - * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. + * of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. * @param cv * the class visitor to which this visitor must delegate method * calls. May be null. */ public ClassVisitor(final int api, final ClassVisitor cv) { - if (api != Opcodes.ASM4 && api != Opcodes.ASM5) { + if (api < Opcodes.ASM4 || api > Opcodes.ASM6) { throw new IllegalArgumentException(); } this.api = api; @@ -160,6 +160,28 @@ public abstract class ClassVisitor { } } + /** + * Visit the module corresponding to the class. + * @param name + * module name + * @param access + * module flags, among {@code ACC_OPEN}, {@code ACC_SYNTHETIC} + * and {@code ACC_MANDATED}. + * @param version + * module version or null. + * @return a visitor to visit the module values, or null if + * this visitor is not interested in visiting this module. + */ + public ModuleVisitor visitModule(String name, int access, String version) { + if (api < Opcodes.ASM6) { + throw new RuntimeException(); + } + if (cv != null) { + return cv.visitModule(name, access, version); + } + return null; + } + /** * Visits the enclosing class of the class. This method must be called only * if the class has an enclosing class. diff --git a/src/org/redkale/asm/ClassWriter.java b/src/org/redkale/asm/ClassWriter.java index a7aa5b7cf..81f964eb5 100644 --- a/src/org/redkale/asm/ClassWriter.java +++ b/src/org/redkale/asm/ClassWriter.java @@ -87,8 +87,8 @@ public class ClassWriter extends ClassVisitor { * {@link MethodVisitor#visitFrame} method are ignored, and the stack map * frames are recomputed from the methods bytecode. The arguments of the * {@link MethodVisitor#visitMaxs visitMaxs} method are also ignored and - * recomputed from the bytecode. In other words, computeFrames implies - * computeMaxs. + * recomputed from the bytecode. In other words, COMPUTE_FRAMES implies + * COMPUTE_MAXS. * * @see #ClassWriter(int) */ @@ -196,6 +196,27 @@ public class ClassWriter extends ClassVisitor { */ static final int WIDE_INSN = 17; + /** + * The type of the ASM pseudo instructions with an unsigned 2 bytes offset + * label (see Label#resolve). + */ + static final int ASM_LABEL_INSN = 18; + + /** + * The type of the ASM pseudo instructions with a 4 bytes offset label. + */ + static final int ASM_LABELW_INSN = 19; + + /** + * Represents a frame inserted between already existing frames. This kind of + * frame can only be used if the frame content can be computed from the + * previous existing frame and from the instructions between this existing + * frame and the inserted one, without any knowledge of the type hierarchy. + * This kind of frame is only used when an unconditional jump is inserted in + * a method while expanding an ASM pseudo instruction (see ClassReader). + */ + static final int F_INSERT = 256; + /** * The instruction types of all JVM opcodes. */ @@ -284,7 +305,7 @@ public class ClassWriter extends ClassVisitor { /** * The base value for all CONSTANT_MethodHandle constant pool items. * Internally, ASM store the 9 variations of CONSTANT_MethodHandle into 9 - * different items. + * different items (from 21 to 29). */ static final int HANDLE_BASE = 20; @@ -433,6 +454,11 @@ public class ClassWriter extends ClassVisitor { */ private ByteVector sourceDebug; + /** + * The module attribute of this class. + */ + private ModuleWriter moduleWriter; + /** * The constant pool item that contains the name of the enclosing class of * this class. @@ -523,25 +549,19 @@ public class ClassWriter extends ClassVisitor { MethodWriter lastMethod; /** - * true if the maximum stack size and number of local variables - * must be automatically computed. + * Indicates what must be automatically computed. + * + * @see MethodWriter#compute */ - private boolean computeMaxs; + private int compute; /** - * true if the stack map frames must be recomputed from scratch. + * true if some methods have wide forward jumps using ASM pseudo + * instructions, which need to be expanded into sequences of standard + * bytecode instructions. In this case the class is re-read and re-written + * with a ClassReader -> ClassWriter chain to perform this transformation. */ - private boolean computeFrames; - - /** - * true if the stack map tables of this class are invalid. The - * {@link MethodWriter#resizeInstructions} method cannot transform existing - * stack map tables, and so produces potentially invalid classes when it is - * executed. In this case the class is reread and rewritten with the - * {@link #COMPUTE_FRAMES} option (the resizeInstructions method can resize - * stack map tables when this option is used). - */ - boolean invalidFrames; + boolean hasAsmInsns; // ------------------------------------------------------------------------ // Static initializer @@ -552,11 +572,11 @@ public class ClassWriter extends ClassVisitor { */ static { int i; - byte[] b = new byte[220]; + byte[] b = new byte[221]; String s = "AAAAAAAAAAAAAAAABCLMMDDDDDEEEEEEEEEEEEEEEEEEEEAAAAAAAADD" + "DDDEEEEEEEEEEEEEEEEEEEEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAANAAAAAAAAAAAAAAAAAAAAJJJJJJJJJJJJJJJJDOPAA" - + "AAAAGGGGGGGHIFBFAAFFAARQJJKKJJJJJJJJJJJJJJJJJJ"; + + "AAAAGGGGGGGHIFBFAAFFAARQJJKKSSSSSSSSSSSSSSSSSST"; for (i = 0; i < b.length; ++i) { b[i] = (byte) (s.charAt(i) - 'A'); } @@ -610,8 +630,9 @@ public class ClassWriter extends ClassVisitor { // // temporary opcodes used internally by ASM - see Label and // MethodWriter // for (i = 202; i < 220; ++i) { - // b[i] = LABEL_INSN; + // b[i] = ASM_LABEL_INSN; // } + // b[220] = ASM_LABELW_INSN; // // // LDC(_W) instructions // b[Constants.LDC] = LDC_INSN; @@ -644,7 +665,7 @@ public class ClassWriter extends ClassVisitor { * {@link #COMPUTE_FRAMES}. */ public ClassWriter(final int flags) { - super(Opcodes.ASM5); + super(Opcodes.ASM6); index = 1; pool = new ByteVector(); items = new Item[256]; @@ -653,8 +674,9 @@ public class ClassWriter extends ClassVisitor { key2 = new Item(); key3 = new Item(); key4 = new Item(); - this.computeMaxs = (flags & COMPUTE_MAXS) != 0; - this.computeFrames = (flags & COMPUTE_FRAMES) != 0; + this.compute = (flags & COMPUTE_FRAMES) != 0 ? MethodWriter.FRAMES + : ((flags & COMPUTE_MAXS) != 0 ? MethodWriter.MAXS + : MethodWriter.NOTHING); } /** @@ -684,9 +706,9 @@ public class ClassWriter extends ClassVisitor { * @param flags * option flags that can be used to modify the default behavior * of this class. These option flags do not affect methods - * that are copied as is in the new class. This means that the - * maximum stack size nor the stack frames will be computed for - * these methods. See {@link #COMPUTE_MAXS}, + * that are copied as is in the new class. This means that + * neither the maximum stack size nor the stack frames will be + * computed for these methods. See {@link #COMPUTE_MAXS}, * {@link #COMPUTE_FRAMES}. */ public ClassWriter(final ClassReader classReader, final int flags) { @@ -705,9 +727,9 @@ public class ClassWriter extends ClassVisitor { final String[] interfaces) { this.version = version; this.access = access; - this.name = (name == null) ? 0 : newClass(name); + this.name = newClass(name); thisName = name; - if (ClassReader.SIGNATURES && signature != null) { + if (signature != null) { this.signature = newUTF8(signature); } this.superName = superName == null ? 0 : newClass(superName); @@ -731,6 +753,14 @@ public class ClassWriter extends ClassVisitor { } } + @Override + public final ModuleVisitor visitModule(final String name, + final int access, final String version) { + return moduleWriter = new ModuleWriter(this, + newModule(name), access, + version == null ? 0 : newUTF8(version)); + } + @Override public final void visitOuterClass(final String owner, final String name, final String desc) { @@ -743,9 +773,6 @@ public class ClassWriter extends ClassVisitor { @Override public final AnnotationVisitor visitAnnotation(final String desc, final boolean visible) { - if (!ClassReader.ANNOTATIONS) { - return null; - } ByteVector bv = new ByteVector(); // write type, and reserve space for values count bv.putShort(newUTF8(desc)).putShort(0); @@ -763,9 +790,6 @@ public class ClassWriter extends ClassVisitor { @Override public final AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, final String desc, final boolean visible) { - if (!ClassReader.ANNOTATIONS) { - return null; - } ByteVector bv = new ByteVector(); // write target_type and target_info AnnotationWriter.putTarget(typeRef, typePath, bv); @@ -805,7 +829,7 @@ public class ClassWriter extends ClassVisitor { // and equality tests). If so we store the index of this inner class // entry (plus one) in intVal. This hack allows duplicate detection in // O(1) time. - Item nameItem = newClassItem(name); + Item nameItem = newStringishItem(CLASS, name); if (nameItem.intVal == 0) { ++innerClassesCount; innerClasses.putShort(nameItem.index); @@ -830,7 +854,7 @@ public class ClassWriter extends ClassVisitor { public final MethodVisitor visitMethod(final int access, final String name, final String desc, final String signature, final String[] exceptions) { return new MethodWriter(this, access, name, desc, signature, - exceptions, computeMaxs, computeFrames); + exceptions, compute); } @Override @@ -874,7 +898,7 @@ public class ClassWriter extends ClassVisitor { size += 8 + bootstrapMethods.length; newUTF8("BootstrapMethods"); } - if (ClassReader.SIGNATURES && signature != 0) { + if (signature != 0) { ++attributeCount; size += 8; newUTF8("Signature"); @@ -912,26 +936,31 @@ public class ClassWriter extends ClassVisitor { size += 8 + innerClasses.length; newUTF8("InnerClasses"); } - if (ClassReader.ANNOTATIONS && anns != null) { + if (anns != null) { ++attributeCount; size += 8 + anns.getSize(); newUTF8("RuntimeVisibleAnnotations"); } - if (ClassReader.ANNOTATIONS && ianns != null) { + if (ianns != null) { ++attributeCount; size += 8 + ianns.getSize(); newUTF8("RuntimeInvisibleAnnotations"); } - if (ClassReader.ANNOTATIONS && tanns != null) { + if (tanns != null) { ++attributeCount; size += 8 + tanns.getSize(); newUTF8("RuntimeVisibleTypeAnnotations"); } - if (ClassReader.ANNOTATIONS && itanns != null) { + if (itanns != null) { ++attributeCount; size += 8 + itanns.getSize(); newUTF8("RuntimeInvisibleTypeAnnotations"); } + if (moduleWriter != null) { + attributeCount += 1 + moduleWriter.attributeCount; + size += 6 + moduleWriter.size + moduleWriter.attributesSize; + newUTF8("Module"); + } if (attrs != null) { attributeCount += attrs.getCount(); size += attrs.getSize(this, null, 0, -1, -1); @@ -968,7 +997,7 @@ public class ClassWriter extends ClassVisitor { bootstrapMethodsCount); out.putByteArray(bootstrapMethods.data, 0, bootstrapMethods.length); } - if (ClassReader.SIGNATURES && signature != 0) { + if (signature != 0) { out.putShort(newUTF8("Signature")).putInt(2).putShort(signature); } if (sourceFile != 0) { @@ -979,6 +1008,11 @@ public class ClassWriter extends ClassVisitor { out.putShort(newUTF8("SourceDebugExtension")).putInt(len); out.putByteArray(sourceDebug.data, 0, len); } + if (moduleWriter != null) { + out.putShort(newUTF8("Module")); + moduleWriter.put(out); + moduleWriter.putAttributes(out); + } if (enclosingMethodOwner != 0) { out.putShort(newUTF8("EnclosingMethod")).putInt(4); out.putShort(enclosingMethodOwner).putShort(enclosingMethod); @@ -997,41 +1031,46 @@ public class ClassWriter extends ClassVisitor { out.putInt(innerClasses.length + 2).putShort(innerClassesCount); out.putByteArray(innerClasses.data, 0, innerClasses.length); } - if (ClassReader.ANNOTATIONS && anns != null) { + if (anns != null) { out.putShort(newUTF8("RuntimeVisibleAnnotations")); anns.put(out); } - if (ClassReader.ANNOTATIONS && ianns != null) { + if (ianns != null) { out.putShort(newUTF8("RuntimeInvisibleAnnotations")); ianns.put(out); } - if (ClassReader.ANNOTATIONS && tanns != null) { + if (tanns != null) { out.putShort(newUTF8("RuntimeVisibleTypeAnnotations")); tanns.put(out); } - if (ClassReader.ANNOTATIONS && itanns != null) { + if (itanns != null) { out.putShort(newUTF8("RuntimeInvisibleTypeAnnotations")); itanns.put(out); } if (attrs != null) { attrs.put(this, null, 0, -1, -1, out); } - if (invalidFrames) { + if (hasAsmInsns) { + boolean hasFrames = false; + mb = firstMethod; + while (mb != null) { + hasFrames |= mb.frameCount > 0; + mb = (MethodWriter) mb.mv; + } anns = null; ianns = null; attrs = null; - innerClassesCount = 0; - innerClasses = null; - bootstrapMethodsCount = 0; - bootstrapMethods = null; + moduleWriter = null; firstField = null; lastField = null; firstMethod = null; lastMethod = null; - computeMaxs = false; - computeFrames = true; - invalidFrames = false; - new ClassReader(out.data).accept(this, ClassReader.SKIP_FRAMES); + compute = + hasFrames ? MethodWriter.INSERTED_FRAMES : MethodWriter.NOTHING; + hasAsmInsns = false; + new ClassReader(out.data).accept(this, + (hasFrames ? ClassReader.EXPAND_FRAMES : 0) + | ClassReader.EXPAND_ASM_INSNS); return toByteArray(); } return out.data; @@ -1078,16 +1117,16 @@ public class ClassWriter extends ClassVisitor { double val = ((Double) cst).doubleValue(); return newDouble(val); } else if (cst instanceof String) { - return newString((String) cst); + return newStringishItem(STR, (String) cst); } else if (cst instanceof Type) { Type t = (Type) cst; int s = t.getSort(); if (s == Type.OBJECT) { - return newClassItem(t.getInternalName()); + return newStringishItem(CLASS, t.getInternalName()); } else if (s == Type.METHOD) { - return newMethodTypeItem(t.getDescriptor()); + return newStringishItem(MTYPE, t.getDescriptor()); } else { // s == primitive type or array - return newClassItem(t.getDescriptor()); + return newStringishItem(CLASS, t.getDescriptor()); } } else if (cst instanceof Handle) { Handle h = (Handle) cst; @@ -1136,20 +1175,21 @@ public class ClassWriter extends ClassVisitor { } /** - * Adds a class reference to the constant pool of the class being build. + * Adds a string reference, a class reference, a method type, a module + * or a package to the constant pool of the class being build. * Does nothing if the constant pool already contains a similar item. - * This method is intended for {@link Attribute} sub classes, and is - * normally not needed by class generators or adapters. * + * @param type + * a type among STR, CLASS, MTYPE, MODULE or PACKAGE * @param value - * the internal name of the class. - * @return a new or already existing class reference item. + * string value of the reference. + * @return a new or already existing reference item. */ - Item newClassItem(final String value) { - key2.set(CLASS, value, null, null); + Item newStringishItem(final int type, final String value) { + key2.set(type, value, null, null); Item result = get(key2); if (result == null) { - pool.put12(CLASS, newUTF8(value)); + pool.put12(type, newUTF8(value)); result = new Item(index++, key2); put(result); } @@ -1167,72 +1207,7 @@ public class ClassWriter extends ClassVisitor { * @return the index of a new or already existing class reference item. */ public int newClass(final String value) { - return newClassItem(value).index; - } - - /** - * Adds a module name to the constant pool. - * - * Does nothing if the constant pool already contains a similar item. - * This method is intended for {@link Attribute} sub classes, and is - * normally not needed by class generators or adapters. - * - * @param value - * the module name - * @return the index of a new or already existing module reference item. - */ - public int newModule(String value) { - key2.set(MODULE, value, null, null); - Item result = get(key2); - if (result == null) { - pool.put12(MODULE, newUTF8(value)); - result = new Item(index++, key2); - put(result); - } - return result.index; - } - - /** - * Adds a package name to the constant pool. - * - * Does nothing if the constant pool already contains a similar item. - * This method is intended for {@link Attribute} sub classes, and is - * normally not needed by class generators or adapters. - * - * @param value - * the internal name of the package. - * @return the index of a new or already existing package reference item. - */ - public int newPackage(String value) { - key2.set(PACKAGE, value, null, null); - Item result = get(key2); - if (result == null) { - pool.put12(PACKAGE, newUTF8(value)); - result = new Item(index++, key2); - put(result); - } - return result.index; - } - - /** - * Adds a method type reference to the constant pool of the class being - * build. Does nothing if the constant pool already contains a similar item. - * This method is intended for {@link Attribute} sub classes, and is - * normally not needed by class generators or adapters. - * - * @param methodDesc - * method descriptor of the method type. - * @return a new or already existing method type reference item. - */ - Item newMethodTypeItem(final String methodDesc) { - key2.set(MTYPE, methodDesc, null, null); - Item result = get(key2); - if (result == null) { - pool.put12(MTYPE, newUTF8(methodDesc)); - result = new Item(index++, key2); - put(result); - } - return result; + return newStringishItem(CLASS, value).index; } /** @@ -1247,7 +1222,37 @@ public class ClassWriter extends ClassVisitor { * item. */ public int newMethodType(final String methodDesc) { - return newMethodTypeItem(methodDesc).index; + return newStringishItem(MTYPE, methodDesc).index; + } + + /** + * Adds a module reference to the constant pool of the class being + * build. Does nothing if the constant pool already contains a similar item. + * This method is intended for {@link Attribute} sub classes, and is + * normally not needed by class generators or adapters. + * + * @param moduleName + * name of the module. + * @return the index of a new or already existing module reference + * item. + */ + public int newModule(final String moduleName) { + return newStringishItem(MODULE, moduleName).index; + } + + /** + * Adds a package reference to the constant pool of the class being + * build. Does nothing if the constant pool already contains a similar item. + * This method is intended for {@link Attribute} sub classes, and is + * normally not needed by class generators or adapters. + * + * @param packageName + * name of the package in its internal form. + * @return the index of a new or already existing module reference + * item. + */ + public int newPackage(final String packageName) { + return newStringishItem(PACKAGE, packageName).index; } /** @@ -1628,25 +1633,6 @@ public class ClassWriter extends ClassVisitor { return result; } - /** - * Adds a string to the constant pool of the class being build. Does nothing - * if the constant pool already contains a similar item. - * - * @param value - * the String value. - * @return a new or already existing string item. - */ - private Item newString(final String value) { - key2.set(STR, value, null, null); - Item result = get(key2); - if (result == null) { - pool.put12(STR, newUTF8(value)); - result = new Item(index++, key2); - put(result); - } - return result; - } - /** * Adds a name and type to the constant pool of the class being build. Does * nothing if the constant pool already contains a similar item. This diff --git a/src/org/redkale/asm/CurrentFrame.java b/src/org/redkale/asm/CurrentFrame.java new file mode 100644 index 000000000..8df1d8527 --- /dev/null +++ b/src/org/redkale/asm/CurrentFrame.java @@ -0,0 +1,85 @@ +/* + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + */ + +/* + * + * + * + * + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.redkale.asm; + +/** + * Information about the input stack map frame at the "current" instruction of a + * method. This is implemented as a Frame subclass for a "basic block" + * containing only one instruction. + * + * @author Eric Bruneton + */ +class CurrentFrame extends Frame { + + /** + * Sets this CurrentFrame to the input stack map frame of the next "current" + * instruction, i.e. the instruction just after the given one. It is assumed + * that the value of this object when this method is called is the stack map + * frame status just before the given instruction is executed. + */ + @Override + void execute(int opcode, int arg, ClassWriter cw, Item item) { + super.execute(opcode, arg, cw, item); + Frame successor = new Frame(); + merge(cw, successor, 0); + set(successor); + owner.inputStackTop = 0; + } +} diff --git a/src/org/redkale/asm/FieldVisitor.java b/src/org/redkale/asm/FieldVisitor.java index fb0145dab..5876275fe 100644 --- a/src/org/redkale/asm/FieldVisitor.java +++ b/src/org/redkale/asm/FieldVisitor.java @@ -69,7 +69,7 @@ public abstract class FieldVisitor { /** * The ASM API version implemented by this visitor. The value of this field - * must be one of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. + * must be one of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. */ protected final int api; @@ -84,7 +84,7 @@ public abstract class FieldVisitor { * * @param api * the ASM API version implemented by this visitor. Must be one - * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. + * of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. */ public FieldVisitor(final int api) { this(api, null); @@ -95,13 +95,13 @@ public abstract class FieldVisitor { * * @param api * the ASM API version implemented by this visitor. Must be one - * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. + * of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. * @param fv * the field visitor to which this visitor must delegate method * calls. May be null. */ public FieldVisitor(final int api, final FieldVisitor fv) { - if (api != Opcodes.ASM4 && api != Opcodes.ASM5) { + if (api < Opcodes.ASM4 || api > Opcodes.ASM6) { throw new IllegalArgumentException(); } this.api = api; diff --git a/src/org/redkale/asm/FieldWriter.java b/src/org/redkale/asm/FieldWriter.java index f81741d8b..a4ecb06fe 100644 --- a/src/org/redkale/asm/FieldWriter.java +++ b/src/org/redkale/asm/FieldWriter.java @@ -147,7 +147,7 @@ final class FieldWriter extends FieldVisitor { */ FieldWriter(final ClassWriter cw, final int access, final String name, final String desc, final String signature, final Object value) { - super(Opcodes.ASM5); + super(Opcodes.ASM6); if (cw.firstField == null) { cw.firstField = this; } else { @@ -158,7 +158,7 @@ final class FieldWriter extends FieldVisitor { this.access = access; this.name = cw.newUTF8(name); this.desc = cw.newUTF8(desc); - if (ClassReader.SIGNATURES && signature != null) { + if (signature != null) { this.signature = cw.newUTF8(signature); } if (value != null) { @@ -173,9 +173,6 @@ final class FieldWriter extends FieldVisitor { @Override public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) { - if (!ClassReader.ANNOTATIONS) { - return null; - } ByteVector bv = new ByteVector(); // write type, and reserve space for values count bv.putShort(cw.newUTF8(desc)).putShort(0); @@ -193,9 +190,6 @@ final class FieldWriter extends FieldVisitor { @Override public AnnotationVisitor visitTypeAnnotation(final int typeRef, final TypePath typePath, final String desc, final boolean visible) { - if (!ClassReader.ANNOTATIONS) { - return null; - } ByteVector bv = new ByteVector(); // write target_type and target_info AnnotationWriter.putTarget(typeRef, typePath, bv); @@ -249,23 +243,23 @@ final class FieldWriter extends FieldVisitor { cw.newUTF8("Deprecated"); size += 6; } - if (ClassReader.SIGNATURES && signature != 0) { + if (signature != 0) { cw.newUTF8("Signature"); size += 8; } - if (ClassReader.ANNOTATIONS && anns != null) { + if (anns != null) { cw.newUTF8("RuntimeVisibleAnnotations"); size += 8 + anns.getSize(); } - if (ClassReader.ANNOTATIONS && ianns != null) { + if (ianns != null) { cw.newUTF8("RuntimeInvisibleAnnotations"); size += 8 + ianns.getSize(); } - if (ClassReader.ANNOTATIONS && tanns != null) { + if (tanns != null) { cw.newUTF8("RuntimeVisibleTypeAnnotations"); size += 8 + tanns.getSize(); } - if (ClassReader.ANNOTATIONS && itanns != null) { + if (itanns != null) { cw.newUTF8("RuntimeInvisibleTypeAnnotations"); size += 8 + itanns.getSize(); } @@ -299,19 +293,19 @@ final class FieldWriter extends FieldVisitor { if ((access & Opcodes.ACC_DEPRECATED) != 0) { ++attributeCount; } - if (ClassReader.SIGNATURES && signature != 0) { + if (signature != 0) { ++attributeCount; } - if (ClassReader.ANNOTATIONS && anns != null) { + if (anns != null) { ++attributeCount; } - if (ClassReader.ANNOTATIONS && ianns != null) { + if (ianns != null) { ++attributeCount; } - if (ClassReader.ANNOTATIONS && tanns != null) { + if (tanns != null) { ++attributeCount; } - if (ClassReader.ANNOTATIONS && itanns != null) { + if (itanns != null) { ++attributeCount; } if (attrs != null) { @@ -331,23 +325,23 @@ final class FieldWriter extends FieldVisitor { if ((access & Opcodes.ACC_DEPRECATED) != 0) { out.putShort(cw.newUTF8("Deprecated")).putInt(0); } - if (ClassReader.SIGNATURES && signature != 0) { + if (signature != 0) { out.putShort(cw.newUTF8("Signature")); out.putInt(2).putShort(signature); } - if (ClassReader.ANNOTATIONS && anns != null) { + if (anns != null) { out.putShort(cw.newUTF8("RuntimeVisibleAnnotations")); anns.put(out); } - if (ClassReader.ANNOTATIONS && ianns != null) { + if (ianns != null) { out.putShort(cw.newUTF8("RuntimeInvisibleAnnotations")); ianns.put(out); } - if (ClassReader.ANNOTATIONS && tanns != null) { + if (tanns != null) { out.putShort(cw.newUTF8("RuntimeVisibleTypeAnnotations")); tanns.put(out); } - if (ClassReader.ANNOTATIONS && itanns != null) { + if (itanns != null) { out.putShort(cw.newUTF8("RuntimeInvisibleTypeAnnotations")); itanns.put(out); } diff --git a/src/org/redkale/asm/Frame.java b/src/org/redkale/asm/Frame.java index 3857f7672..530c2a8a7 100644 --- a/src/org/redkale/asm/Frame.java +++ b/src/org/redkale/asm/Frame.java @@ -63,7 +63,7 @@ package org.redkale.asm; * * @author Eric Bruneton */ -final class Frame { +class Frame { /* * Frames are computed in a two steps process: during the visit of each @@ -192,7 +192,7 @@ final class Frame { private static final int LOCAL = 0x2000000; /** - * Kind of the the types that are relative to the stack of an input stack + * Kind of the types that are relative to the stack of an input stack * map frame. The value of such types is a position relatively to the top of * this stack. */ @@ -525,7 +525,7 @@ final class Frame { * When the stack map frames are completely computed, this field is the * actual number of types in {@link #outputStack}. */ - private int outputStackTop; + int outputStackTop; /** * Number of types that are initialized in the basic block. @@ -549,6 +549,110 @@ final class Frame { */ private int[] initializations; + /** + * Sets this frame to the given value. + * + * @param cw + * the ClassWriter to which this label belongs. + * @param nLocal + * the number of local variables. + * @param local + * the local variable types. Primitive types are represented by + * {@link Opcodes#TOP}, {@link Opcodes#INTEGER}, + * {@link Opcodes#FLOAT}, {@link Opcodes#LONG}, + * {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or + * {@link Opcodes#UNINITIALIZED_THIS} (long and double are + * represented by a single element). Reference types are + * represented by String objects (representing internal names), + * and uninitialized types by Label objects (this label + * designates the NEW instruction that created this uninitialized + * value). + * @param nStack + * the number of operand stack elements. + * @param stack + * the operand stack types (same format as the "local" array). + */ + final void set(ClassWriter cw, final int nLocal, final Object[] local, + final int nStack, final Object[] stack) { + int i = convert(cw, nLocal, local, inputLocals); + while (i < local.length) { + inputLocals[i++] = TOP; + } + int nStackTop = 0; + for (int j = 0; j < nStack; ++j) { + if (stack[j] == Opcodes.LONG || stack[j] == Opcodes.DOUBLE) { + ++nStackTop; + } + } + inputStack = new int[nStack + nStackTop]; + convert(cw, nStack, stack, inputStack); + outputStackTop = 0; + initializationCount = 0; + } + + /** + * Converts types from the MethodWriter.visitFrame() format to the Frame + * format. + * + * @param cw + * the ClassWriter to which this label belongs. + * @param nInput + * the number of types to convert. + * @param input + * the types to convert. Primitive types are represented by + * {@link Opcodes#TOP}, {@link Opcodes#INTEGER}, + * {@link Opcodes#FLOAT}, {@link Opcodes#LONG}, + * {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or + * {@link Opcodes#UNINITIALIZED_THIS} (long and double are + * represented by a single element). Reference types are + * represented by String objects (representing internal names), + * and uninitialized types by Label objects (this label + * designates the NEW instruction that created this uninitialized + * value). + * @param output + * where to store the converted types. + * @return the number of output elements. + */ + private static int convert(ClassWriter cw, int nInput, Object[] input, + int[] output) { + int i = 0; + for (int j = 0; j < nInput; ++j) { + if (input[j] instanceof Integer) { + output[i++] = BASE | ((Integer) input[j]).intValue(); + if (input[j] == Opcodes.LONG || input[j] == Opcodes.DOUBLE) { + output[i++] = TOP; + } + } else if (input[j] instanceof String) { + output[i++] = type(cw, Type.getObjectType((String) input[j]) + .getDescriptor()); + } else { + output[i++] = UNINITIALIZED + | cw.addUninitializedType("", + ((Label) input[j]).position); + } + } + return i; + } + + /** + * Sets this frame to the value of the given frame. WARNING: after this + * method is called the two frames share the same data structures. It is + * recommended to discard the given frame f to avoid unexpected side + * effects. + * + * @param f + * The new frame value. + */ + final void set(final Frame f) { + inputLocals = f.inputLocals; + inputStack = f.inputStack; + outputLocals = f.outputLocals; + outputStack = f.outputStack; + outputStackTop = f.outputStackTop; + initializationCount = f.initializationCount; + initializations = f.initializations; + } + /** * Returns the output frame local variable type at the given index. * @@ -614,7 +718,7 @@ final class Frame { } // pushes the type on the output stack outputStack[outputStackTop++] = type; - // updates the maximun height reached by the output stack, if needed + // updates the maximum height reached by the output stack, if needed int top = owner.inputStackTop + outputStackTop; if (top > owner.outputStackMax) { owner.outputStackMax = top; @@ -650,7 +754,7 @@ final class Frame { * a type descriptor. * @return the int encoding of the given type. */ - private static int type(final ClassWriter cw, final String desc) { + static int type(final ClassWriter cw, final String desc) { String t; int index = desc.charAt(0) == '(' ? desc.indexOf(')') + 1 : 0; switch (desc.charAt(index)) { @@ -838,7 +942,7 @@ final class Frame { * @param maxLocals * the maximum number of local variables of this method. */ - void initInputFrame(final ClassWriter cw, final int access, + final void initInputFrame(final ClassWriter cw, final int access, final Type[] args, final int maxLocals) { inputLocals = new int[maxLocals]; inputStack = new int[0]; @@ -981,7 +1085,7 @@ final class Frame { case Opcodes.AALOAD: pop(1); t1 = pop(); - push(ELEMENT_OF + t1); + push(t1 == NULL ? t1 : ELEMENT_OF + t1); break; case Opcodes.ISTORE: case Opcodes.FSTORE: @@ -1312,7 +1416,7 @@ final class Frame { * @return true if the input frame of the given label has been * changed by this operation. */ - boolean merge(final ClassWriter cw, final Frame frame, final int edge) { + final boolean merge(final ClassWriter cw, final Frame frame, final int edge) { boolean changed = false; int i, s, dim, kind, t; diff --git a/src/org/redkale/asm/Item.java b/src/org/redkale/asm/Item.java index de8260765..a289647fb 100644 --- a/src/org/redkale/asm/Item.java +++ b/src/org/redkale/asm/Item.java @@ -80,6 +80,7 @@ final class Item { * {@link ClassWriter#STR}, {@link ClassWriter#CLASS}, * {@link ClassWriter#NAME_TYPE}, {@link ClassWriter#FIELD}, * {@link ClassWriter#METH}, {@link ClassWriter#IMETH}, + * {@link ClassWriter#MODULE}, {@link ClassWriter#PACKAGE}, * {@link ClassWriter#MTYPE}, {@link ClassWriter#INDY}. * * MethodHandle constant 9 variations are stored using a range of 9 values @@ -239,12 +240,12 @@ final class Item { this.strVal3 = strVal3; switch (type) { case ClassWriter.CLASS: - case ClassWriter.MODULE: - case ClassWriter.PACKAGE: this.intVal = 0; // intVal of a class must be zero, see visitInnerClass case ClassWriter.UTF8: case ClassWriter.STR: case ClassWriter.MTYPE: + case ClassWriter.MODULE: + case ClassWriter.PACKAGE: case ClassWriter.TYPE_NORMAL: hashCode = 0x7FFFFFFF & (type + strVal1.hashCode()); return; diff --git a/src/org/redkale/asm/Label.java b/src/org/redkale/asm/Label.java index 61f59deba..736d7eca1 100644 --- a/src/org/redkale/asm/Label.java +++ b/src/org/redkale/asm/Label.java @@ -139,7 +139,8 @@ public class Label { /** * Field used to associate user information to a label. Warning: this field * is used by the ASM tree package. In order to use it with the ASM tree - * package you must override the method. + * package you must override the + * {@link org.redkale.asm.tree.MethodNode#getLabelNode} method. */ public Object info; @@ -388,13 +389,12 @@ public class Label { * the position of this label in the bytecode. * @param data * the bytecode of the method. - * @return true if a blank that was left for this label was to + * @return true if a blank that was left for this label was too * small to store the offset. In such a case the corresponding jump * instruction is replaced with a pseudo instruction (using unused * opcodes) using an unsigned two bytes offset. These pseudo - * instructions will need to be replaced with true instructions with - * wider offsets (4 bytes instead of 2). This is done in - * {@link MethodWriter#resizeInstructions}. + * instructions will be replaced with standard bytecode instructions + * with wider offsets (4 bytes instead of 2), in ClassReader. * @throws IllegalArgumentException * if this label has already been resolved, or if it has not * been created by the given code writer. @@ -453,7 +453,7 @@ public class Label { * @return the first label of the series to which this label belongs. */ Label getFirst() { - return !ClassReader.FRAMES || frame == null ? this : frame.owner; + return frame == null ? this : frame.owner; } // ------------------------------------------------------------------------ diff --git a/src/org/redkale/asm/MethodVisitor.java b/src/org/redkale/asm/MethodVisitor.java index 8a3ba1360..8295e8b1e 100644 --- a/src/org/redkale/asm/MethodVisitor.java +++ b/src/org/redkale/asm/MethodVisitor.java @@ -86,7 +86,7 @@ public abstract class MethodVisitor { /** * The ASM API version implemented by this visitor. The value of this field - * must be one of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. + * must be one of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. */ protected final int api; @@ -101,7 +101,7 @@ public abstract class MethodVisitor { * * @param api * the ASM API version implemented by this visitor. Must be one - * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. + * of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. */ public MethodVisitor(final int api) { this(api, null); @@ -112,13 +112,13 @@ public abstract class MethodVisitor { * * @param api * the ASM API version implemented by this visitor. Must be one - * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. + * of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. * @param mv * the method visitor to which this visitor must delegate method * calls. May be null. */ public MethodVisitor(final int api, final MethodVisitor mv) { - if (api != Opcodes.ASM4 && api != Opcodes.ASM5) { + if (api < Opcodes.ASM4 || api > Opcodes.ASM6) { throw new IllegalArgumentException(); } this.api = api; diff --git a/src/org/redkale/asm/MethodWriter.java b/src/org/redkale/asm/MethodWriter.java index 6ed3c39af..19443688e 100644 --- a/src/org/redkale/asm/MethodWriter.java +++ b/src/org/redkale/asm/MethodWriter.java @@ -128,7 +128,19 @@ class MethodWriter extends MethodVisitor { * * @see #compute */ - private static final int FRAMES = 0; + static final int FRAMES = 0; + + /** + * Indicates that the stack map frames of type F_INSERT must be computed. + * The other frames are not (re)computed. They should all be of type F_NEW + * and should be sufficient to compute the content of the F_INSERT frames, + * together with the bytecode instructions between a F_NEW and a F_INSERT + * frame - and without any knowledge of the type hierarchy (by definition of + * F_INSERT). + * + * @see #compute + */ + static final int INSERTED_FRAMES = 1; /** * Indicates that the maximum stack size and number of local variables must @@ -136,14 +148,14 @@ class MethodWriter extends MethodVisitor { * * @see #compute */ - private static final int MAXS = 1; + static final int MAXS = 2; /** * Indicates that nothing must be automatically computed. * * @see #compute */ - private static final int NOTHING = 2; + static final int NOTHING = 3; /** * The class writer to which this method must be added. @@ -277,7 +289,7 @@ class MethodWriter extends MethodVisitor { /** * Number of stack map frames in the StackMapTable attribute. */ - private int frameCount; + int frameCount; /** * The StackMapTable attribute. @@ -383,11 +395,6 @@ class MethodWriter extends MethodVisitor { */ private Attribute cattrs; - /** - * Indicates if some jump instructions are too small and need to be resized. - */ - private boolean resize; - /** * The number of subroutines in this method. */ @@ -409,6 +416,7 @@ class MethodWriter extends MethodVisitor { * Indicates what must be automatically computed. * * @see #FRAMES + * @see #INSERTED_FRAMES * @see #MAXS * @see #NOTHING */ @@ -471,18 +479,13 @@ class MethodWriter extends MethodVisitor { * @param exceptions * the internal names of the method's exceptions. May be * null. - * @param computeMaxs - * true if the maximum stack size and number of local - * variables must be automatically computed. - * @param computeFrames - * true if the stack map tables must be recomputed from - * scratch. + * @param compute + * Indicates what must be automatically computed (see #compute). */ MethodWriter(final ClassWriter cw, final int access, final String name, final String desc, final String signature, - final String[] exceptions, final boolean computeMaxs, - final boolean computeFrames) { - super(Opcodes.ASM5); + final String[] exceptions, final int compute) { + super(Opcodes.ASM6); if (cw.firstMethod == null) { cw.firstMethod = this; } else { @@ -497,9 +500,7 @@ class MethodWriter extends MethodVisitor { this.name = cw.newUTF8(name); this.desc = cw.newUTF8(desc); this.descriptor = desc; - if (ClassReader.SIGNATURES) { - this.signature = signature; - } + this.signature = signature; if (exceptions != null && exceptions.length > 0) { exceptionCount = exceptions.length; this.exceptions = new int[exceptionCount]; @@ -507,8 +508,8 @@ class MethodWriter extends MethodVisitor { this.exceptions[i] = cw.newClass(exceptions[i]); } } - this.compute = computeFrames ? FRAMES : (computeMaxs ? MAXS : NOTHING); - if (computeMaxs || computeFrames) { + this.compute = compute; + if (compute != NOTHING) { // updates maxLocals int size = Type.getArgumentsAndReturnSizes(descriptor) >> 2; if ((access & Opcodes.ACC_STATIC) != 0) { @@ -539,9 +540,6 @@ class MethodWriter extends MethodVisitor { @Override public AnnotationVisitor visitAnnotationDefault() { - if (!ClassReader.ANNOTATIONS) { - return null; - } annd = new ByteVector(); return new AnnotationWriter(cw, false, annd, null, 0); } @@ -549,9 +547,6 @@ class MethodWriter extends MethodVisitor { @Override public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) { - if (!ClassReader.ANNOTATIONS) { - return null; - } ByteVector bv = new ByteVector(); // write type, and reserve space for values count bv.putShort(cw.newUTF8(desc)).putShort(0); @@ -569,9 +564,6 @@ class MethodWriter extends MethodVisitor { @Override public AnnotationVisitor visitTypeAnnotation(final int typeRef, final TypePath typePath, final String desc, final boolean visible) { - if (!ClassReader.ANNOTATIONS) { - return null; - } ByteVector bv = new ByteVector(); // write target_type and target_info AnnotationWriter.putTarget(typeRef, typePath, bv); @@ -592,9 +584,6 @@ class MethodWriter extends MethodVisitor { @Override public AnnotationVisitor visitParameterAnnotation(final int parameter, final String desc, final boolean visible) { - if (!ClassReader.ANNOTATIONS) { - return null; - } ByteVector bv = new ByteVector(); if ("Ljava/lang/Synthetic;".equals(desc)) { // workaround for a bug in javac with synthetic parameters @@ -639,11 +628,33 @@ class MethodWriter extends MethodVisitor { @Override public void visitFrame(final int type, final int nLocal, final Object[] local, final int nStack, final Object[] stack) { - if (!ClassReader.FRAMES || compute == FRAMES) { + if (compute == FRAMES) { return; } - if (type == Opcodes.F_NEW) { + if (compute == INSERTED_FRAMES) { + if (currentBlock.frame == null) { + // This should happen only once, for the implicit first frame + // (which is explicitly visited in ClassReader if the + // EXPAND_ASM_INSNS option is used). + currentBlock.frame = new CurrentFrame(); + currentBlock.frame.owner = currentBlock; + currentBlock.frame.initInputFrame(cw, access, + Type.getArgumentTypes(descriptor), nLocal); + visitImplicitFirstFrame(); + } else { + if (type == Opcodes.F_NEW) { + currentBlock.frame.set(cw, nLocal, local, nStack, stack); + } else { + // In this case type is equal to F_INSERT by hypothesis, and + // currentBlock.frame contains the stack map frame at the + // current instruction, computed from the last F_NEW frame + // and the bytecode instructions in between (via calls to + // CurrentFrame#execute). + } + visitFrame(currentBlock.frame); + } + } else if (type == Opcodes.F_NEW) { if (previousFrame == null) { visitImplicitFirstFrame(); } @@ -651,10 +662,10 @@ class MethodWriter extends MethodVisitor { int frameIndex = startFrame(code.length, nLocal, nStack); for (int i = 0; i < nLocal; ++i) { if (local[i] instanceof String) { - frame[frameIndex++] = Frame.OBJECT - | cw.addType((String) local[i]); + String desc = Type.getObjectType((String) local[i]).getDescriptor(); + frame[frameIndex++] = Frame.type(cw, desc); } else if (local[i] instanceof Integer) { - frame[frameIndex++] = ((Integer) local[i]).intValue(); + frame[frameIndex++] = Frame.BASE | ((Integer) local[i]).intValue(); } else { frame[frameIndex++] = Frame.UNINITIALIZED | cw.addUninitializedType("", @@ -663,10 +674,10 @@ class MethodWriter extends MethodVisitor { } for (int i = 0; i < nStack; ++i) { if (stack[i] instanceof String) { - frame[frameIndex++] = Frame.OBJECT - | cw.addType((String) stack[i]); + String desc = Type.getObjectType((String) stack[i]).getDescriptor(); + frame[frameIndex++] = Frame.type(cw, desc); } else if (stack[i] instanceof Integer) { - frame[frameIndex++] = ((Integer) stack[i]).intValue(); + frame[frameIndex++] = Frame.BASE | ((Integer) stack[i]).intValue(); } else { frame[frameIndex++] = Frame.UNINITIALIZED | cw.addUninitializedType("", @@ -747,7 +758,7 @@ class MethodWriter extends MethodVisitor { // update currentBlock // Label currentBlock = this.currentBlock; if (currentBlock != null) { - if (compute == FRAMES) { + if (compute == FRAMES || compute == INSERTED_FRAMES) { currentBlock.frame.execute(opcode, 0, null, null); } else { // updates current and max stack sizes @@ -770,7 +781,7 @@ class MethodWriter extends MethodVisitor { lastCodeOffset = code.length; // Label currentBlock = this.currentBlock; if (currentBlock != null) { - if (compute == FRAMES) { + if (compute == FRAMES || compute == INSERTED_FRAMES) { currentBlock.frame.execute(opcode, operand, null, null); } else if (opcode != Opcodes.NEWARRAY) { // updates current and max stack sizes only for NEWARRAY @@ -795,7 +806,7 @@ class MethodWriter extends MethodVisitor { lastCodeOffset = code.length; // Label currentBlock = this.currentBlock; if (currentBlock != null) { - if (compute == FRAMES) { + if (compute == FRAMES || compute == INSERTED_FRAMES) { currentBlock.frame.execute(opcode, var, null, null); } else { // updates current and max stack sizes @@ -852,10 +863,10 @@ class MethodWriter extends MethodVisitor { @Override public void visitTypeInsn(final int opcode, final String type) { lastCodeOffset = code.length; - Item i = cw.newClassItem(type); + Item i = cw.newStringishItem(ClassWriter.CLASS, type); // Label currentBlock = this.currentBlock; if (currentBlock != null) { - if (compute == FRAMES) { + if (compute == FRAMES || compute == INSERTED_FRAMES) { currentBlock.frame.execute(opcode, code.length, cw, i); } else if (opcode == Opcodes.NEW) { // updates current and max stack sizes only if opcode == NEW @@ -878,7 +889,7 @@ class MethodWriter extends MethodVisitor { Item i = cw.newFieldItem(owner, name, desc); // Label currentBlock = this.currentBlock; if (currentBlock != null) { - if (compute == FRAMES) { + if (compute == FRAMES || compute == INSERTED_FRAMES) { currentBlock.frame.execute(opcode, 0, cw, i); } else { int size; @@ -918,7 +929,7 @@ class MethodWriter extends MethodVisitor { int argSize = i.intVal; // Label currentBlock = this.currentBlock; if (currentBlock != null) { - if (compute == FRAMES) { + if (compute == FRAMES || compute == INSERTED_FRAMES) { currentBlock.frame.execute(opcode, 0, cw, i); } else { /* @@ -970,7 +981,7 @@ class MethodWriter extends MethodVisitor { int argSize = i.intVal; // Label currentBlock = this.currentBlock; if (currentBlock != null) { - if (compute == FRAMES) { + if (compute == FRAMES || compute == INSERTED_FRAMES) { currentBlock.frame.execute(Opcodes.INVOKEDYNAMIC, 0, cw, i); } else { /* @@ -1004,7 +1015,9 @@ class MethodWriter extends MethodVisitor { } @Override - public void visitJumpInsn(final int opcode, final Label label) { + public void visitJumpInsn(int opcode, final Label label) { + boolean isWide = opcode >= 200; // GOTO_W + opcode = isWide ? opcode - 33 : opcode; lastCodeOffset = code.length; Label nextInsn = null; // Label currentBlock = this.currentBlock; @@ -1019,6 +1032,8 @@ class MethodWriter extends MethodVisitor { // creates a Label for the next basic block nextInsn = new Label(); } + } else if (compute == INSERTED_FRAMES) { + currentBlock.frame.execute(opcode, 0, null, null); } else { if (opcode == Opcodes.JSR) { if ((label.status & Label.SUBROUTINE) == 0) { @@ -1050,8 +1065,8 @@ class MethodWriter extends MethodVisitor { /* * case of a backward jump with an offset < -32768. In this case we * automatically replace GOTO with GOTO_W, JSR with JSR_W and IFxxx - * with IFNOTxxx GOTO_W , where IFNOTxxx is the - * "opposite" opcode of IFxxx (i.e., IFNE for IFEQ) and where + * with IFNOTxxx GOTO_W L:..., where IFNOTxxx is the + * "opposite" opcode of IFxxx (i.e., IFNE for IFEQ) and where * designates the instruction just after the GOTO_W. */ if (opcode == Opcodes.GOTO) { @@ -1067,9 +1082,21 @@ class MethodWriter extends MethodVisitor { code.putByte(opcode <= 166 ? ((opcode + 1) ^ 1) - 1 : opcode ^ 1); code.putShort(8); // jump offset - code.putByte(200); // GOTO_W + // ASM pseudo GOTO_W insn, see ClassReader. We don't use a real + // GOTO_W because we might need to insert a frame just after (as + // the target of the IFNOTxxx jump instruction). + code.putByte(220); + cw.hasAsmInsns = true; } label.put(this, code, code.length - 1, true); + } else if (isWide) { + /* + * case of a GOTO_W or JSR_W specified by the user (normally + * ClassReader when used to resize instructions). In this case we + * keep the original instruction. + */ + code.putByte(opcode + 33); + label.put(this, code, code.length - 1, true); } else { /* * case of a backward jump with an offset >= -32768, or of a forward @@ -1097,7 +1124,7 @@ class MethodWriter extends MethodVisitor { @Override public void visitLabel(final Label label) { // resolves previous forward references to label, if any - resize |= label.resolve(this, code.length, code.data); + cw.hasAsmInsns |= label.resolve(this, code.length, code.data); // updates currentBlock if ((label.status & Label.DEBUG) != 0) { return; @@ -1130,6 +1157,18 @@ class MethodWriter extends MethodVisitor { previousBlock.successor = label; } previousBlock = label; + } else if (compute == INSERTED_FRAMES) { + if (currentBlock == null) { + // This case should happen only once, for the visitLabel call in + // the constructor. Indeed, if compute is equal to + // INSERTED_FRAMES currentBlock can not be set back to null (see + // #noSuccessor). + currentBlock = label; + } else { + // Updates the frame owner so that a correct frame offset is + // computed in visitFrame(Frame). + currentBlock.frame.owner = label; + } } else if (compute == MAXS) { if (currentBlock != null) { // ends current block (with one new successor) @@ -1155,7 +1194,7 @@ class MethodWriter extends MethodVisitor { Item i = cw.newConstItem(cst); // Label currentBlock = this.currentBlock; if (currentBlock != null) { - if (compute == FRAMES) { + if (compute == FRAMES || compute == INSERTED_FRAMES) { currentBlock.frame.execute(Opcodes.LDC, 0, cw, i); } else { int size; @@ -1187,7 +1226,7 @@ class MethodWriter extends MethodVisitor { public void visitIincInsn(final int var, final int increment) { lastCodeOffset = code.length; if (currentBlock != null) { - if (compute == FRAMES) { + if (compute == FRAMES || compute == INSERTED_FRAMES) { currentBlock.frame.execute(Opcodes.IINC, var, null, null); } } @@ -1271,10 +1310,10 @@ class MethodWriter extends MethodVisitor { @Override public void visitMultiANewArrayInsn(final String desc, final int dims) { lastCodeOffset = code.length; - Item i = cw.newClassItem(desc); + Item i = cw.newStringishItem(ClassWriter.CLASS, desc); // Label currentBlock = this.currentBlock; if (currentBlock != null) { - if (compute == FRAMES) { + if (compute == FRAMES || compute == INSERTED_FRAMES) { currentBlock.frame.execute(Opcodes.MULTIANEWARRAY, dims, cw, i); } else { // updates current stack size (max stack size unchanged because @@ -1289,9 +1328,6 @@ class MethodWriter extends MethodVisitor { @Override public AnnotationVisitor visitInsnAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) { - if (!ClassReader.ANNOTATIONS) { - return null; - } ByteVector bv = new ByteVector(); // write target_type and target_info typeRef = (typeRef & 0xFF0000FF) | (lastCodeOffset << 8); @@ -1331,9 +1367,6 @@ class MethodWriter extends MethodVisitor { @Override public AnnotationVisitor visitTryCatchAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) { - if (!ClassReader.ANNOTATIONS) { - return null; - } ByteVector bv = new ByteVector(); // write target_type and target_info AnnotationWriter.putTarget(typeRef, typePath, bv); @@ -1387,9 +1420,6 @@ class MethodWriter extends MethodVisitor { public AnnotationVisitor visitLocalVariableAnnotation(int typeRef, TypePath typePath, Label[] start, Label[] end, int[] index, String desc, boolean visible) { - if (!ClassReader.ANNOTATIONS) { - return null; - } ByteVector bv = new ByteVector(); // write target_type and target_info bv.putByte(typeRef >>> 24).putShort(start.length); @@ -1430,15 +1460,7 @@ class MethodWriter extends MethodVisitor { @Override public void visitMaxs(final int maxStack, final int maxLocals) { - if (resize) { - // replaces the temporary jump opcodes introduced by Label.resolve. - if (ClassReader.RESIZE) { - resizeInstructions(); - } else { - throw new RuntimeException("Method code too large!"); - } - } - if (ClassReader.FRAMES && compute == FRAMES) { + if (compute == FRAMES) { // completes the control flow graph with exception handler blocks Handler handler = firstHandler; while (handler != null) { @@ -1468,8 +1490,8 @@ class MethodWriter extends MethodVisitor { // creates and visits the first (implicit) frame Frame f = labels.frame; - Type[] args = Type.getArgumentTypes(descriptor); - f.initInputFrame(cw, access, args, this.maxLocals); + f.initInputFrame(cw, access, Type.getArgumentTypes(descriptor), + this.maxLocals); visitFrame(f); /* @@ -1717,7 +1739,9 @@ class MethodWriter extends MethodVisitor { } else { currentBlock.outputStackMax = maxStackSize; } - currentBlock = null; + if (compute != INSERTED_FRAMES) { + currentBlock = null; + } } // ------------------------------------------------------------------------ @@ -1789,7 +1813,7 @@ class MethodWriter extends MethodVisitor { if ((access & ACC_CONSTRUCTOR) == 0) { frame[frameIndex++] = Frame.OBJECT | cw.addType(cw.thisName); } else { - frame[frameIndex++] = 6; // Opcodes.UNINITIALIZED_THIS; + frame[frameIndex++] = Frame.UNINITIALIZED_THIS; } } int i = 1; @@ -1801,16 +1825,16 @@ class MethodWriter extends MethodVisitor { case 'B': case 'S': case 'I': - frame[frameIndex++] = 1; // Opcodes.INTEGER; + frame[frameIndex++] = Frame.INTEGER; break; case 'F': - frame[frameIndex++] = 2; // Opcodes.FLOAT; + frame[frameIndex++] = Frame.FLOAT; break; case 'J': - frame[frameIndex++] = 4; // Opcodes.LONG; + frame[frameIndex++] = Frame.LONG; break; case 'D': - frame[frameIndex++] = 3; // Opcodes.DOUBLE; + frame[frameIndex++] = Frame.DOUBLE; break; case '[': while (descriptor.charAt(i) == '[') { @@ -1822,8 +1846,7 @@ class MethodWriter extends MethodVisitor { ++i; } } - frame[frameIndex++] = Frame.OBJECT - | cw.addType(descriptor.substring(j, ++i)); + frame[frameIndex++] = Frame.type(cw, descriptor.substring(j, ++i)); break; case 'L': while (descriptor.charAt(i) != ';') { @@ -2083,11 +2106,11 @@ class MethodWriter extends MethodVisitor { cw.newUTF8(zip ? "StackMapTable" : "StackMap"); size += 8 + stackMap.length; } - if (ClassReader.ANNOTATIONS && ctanns != null) { + if (ctanns != null) { cw.newUTF8("RuntimeVisibleTypeAnnotations"); size += 8 + ctanns.getSize(); } - if (ClassReader.ANNOTATIONS && ictanns != null) { + if (ictanns != null) { cw.newUTF8("RuntimeInvisibleTypeAnnotations"); size += 8 + ictanns.getSize(); } @@ -2111,7 +2134,7 @@ class MethodWriter extends MethodVisitor { cw.newUTF8("Deprecated"); size += 6; } - if (ClassReader.SIGNATURES && signature != null) { + if (signature != null) { cw.newUTF8("Signature"); cw.newUTF8(signature); size += 8; @@ -2120,34 +2143,34 @@ class MethodWriter extends MethodVisitor { cw.newUTF8("MethodParameters"); size += 7 + methodParameters.length; } - if (ClassReader.ANNOTATIONS && annd != null) { + if (annd != null) { cw.newUTF8("AnnotationDefault"); size += 6 + annd.length; } - if (ClassReader.ANNOTATIONS && anns != null) { + if (anns != null) { cw.newUTF8("RuntimeVisibleAnnotations"); size += 8 + anns.getSize(); } - if (ClassReader.ANNOTATIONS && ianns != null) { + if (ianns != null) { cw.newUTF8("RuntimeInvisibleAnnotations"); size += 8 + ianns.getSize(); } - if (ClassReader.ANNOTATIONS && tanns != null) { + if (tanns != null) { cw.newUTF8("RuntimeVisibleTypeAnnotations"); size += 8 + tanns.getSize(); } - if (ClassReader.ANNOTATIONS && itanns != null) { + if (itanns != null) { cw.newUTF8("RuntimeInvisibleTypeAnnotations"); size += 8 + itanns.getSize(); } - if (ClassReader.ANNOTATIONS && panns != null) { + if (panns != null) { cw.newUTF8("RuntimeVisibleParameterAnnotations"); size += 7 + 2 * (panns.length - synthetics); for (int i = panns.length - 1; i >= synthetics; --i) { size += panns[i] == null ? 0 : panns[i].getSize(); } } - if (ClassReader.ANNOTATIONS && ipanns != null) { + if (ipanns != null) { cw.newUTF8("RuntimeInvisibleParameterAnnotations"); size += 7 + 2 * (ipanns.length - synthetics); for (int i = ipanns.length - 1; i >= synthetics; --i) { @@ -2193,31 +2216,31 @@ class MethodWriter extends MethodVisitor { if ((access & Opcodes.ACC_DEPRECATED) != 0) { ++attributeCount; } - if (ClassReader.SIGNATURES && signature != null) { + if (signature != null) { ++attributeCount; } if (methodParameters != null) { ++attributeCount; } - if (ClassReader.ANNOTATIONS && annd != null) { + if (annd != null) { ++attributeCount; } - if (ClassReader.ANNOTATIONS && anns != null) { + if (anns != null) { ++attributeCount; } - if (ClassReader.ANNOTATIONS && ianns != null) { + if (ianns != null) { ++attributeCount; } - if (ClassReader.ANNOTATIONS && tanns != null) { + if (tanns != null) { ++attributeCount; } - if (ClassReader.ANNOTATIONS && itanns != null) { + if (itanns != null) { ++attributeCount; } - if (ClassReader.ANNOTATIONS && panns != null) { + if (panns != null) { ++attributeCount; } - if (ClassReader.ANNOTATIONS && ipanns != null) { + if (ipanns != null) { ++attributeCount; } if (attrs != null) { @@ -2238,10 +2261,10 @@ class MethodWriter extends MethodVisitor { if (stackMap != null) { size += 8 + stackMap.length; } - if (ClassReader.ANNOTATIONS && ctanns != null) { + if (ctanns != null) { size += 8 + ctanns.getSize(); } - if (ClassReader.ANNOTATIONS && ictanns != null) { + if (ictanns != null) { size += 8 + ictanns.getSize(); } if (cattrs != null) { @@ -2273,10 +2296,10 @@ class MethodWriter extends MethodVisitor { if (stackMap != null) { ++attributeCount; } - if (ClassReader.ANNOTATIONS && ctanns != null) { + if (ctanns != null) { ++attributeCount; } - if (ClassReader.ANNOTATIONS && ictanns != null) { + if (ictanns != null) { ++attributeCount; } if (cattrs != null) { @@ -2304,11 +2327,11 @@ class MethodWriter extends MethodVisitor { out.putInt(stackMap.length + 2).putShort(frameCount); out.putByteArray(stackMap.data, 0, stackMap.length); } - if (ClassReader.ANNOTATIONS && ctanns != null) { + if (ctanns != null) { out.putShort(cw.newUTF8("RuntimeVisibleTypeAnnotations")); ctanns.put(out); } - if (ClassReader.ANNOTATIONS && ictanns != null) { + if (ictanns != null) { out.putShort(cw.newUTF8("RuntimeInvisibleTypeAnnotations")); ictanns.put(out); } @@ -2333,7 +2356,7 @@ class MethodWriter extends MethodVisitor { if ((access & Opcodes.ACC_DEPRECATED) != 0) { out.putShort(cw.newUTF8("Deprecated")).putInt(0); } - if (ClassReader.SIGNATURES && signature != null) { + if (signature != null) { out.putShort(cw.newUTF8("Signature")).putInt(2) .putShort(cw.newUTF8(signature)); } @@ -2343,32 +2366,32 @@ class MethodWriter extends MethodVisitor { methodParametersCount); out.putByteArray(methodParameters.data, 0, methodParameters.length); } - if (ClassReader.ANNOTATIONS && annd != null) { + if (annd != null) { out.putShort(cw.newUTF8("AnnotationDefault")); out.putInt(annd.length); out.putByteArray(annd.data, 0, annd.length); } - if (ClassReader.ANNOTATIONS && anns != null) { + if (anns != null) { out.putShort(cw.newUTF8("RuntimeVisibleAnnotations")); anns.put(out); } - if (ClassReader.ANNOTATIONS && ianns != null) { + if (ianns != null) { out.putShort(cw.newUTF8("RuntimeInvisibleAnnotations")); ianns.put(out); } - if (ClassReader.ANNOTATIONS && tanns != null) { + if (tanns != null) { out.putShort(cw.newUTF8("RuntimeVisibleTypeAnnotations")); tanns.put(out); } - if (ClassReader.ANNOTATIONS && itanns != null) { + if (itanns != null) { out.putShort(cw.newUTF8("RuntimeInvisibleTypeAnnotations")); itanns.put(out); } - if (ClassReader.ANNOTATIONS && panns != null) { + if (panns != null) { out.putShort(cw.newUTF8("RuntimeVisibleParameterAnnotations")); AnnotationWriter.put(panns, synthetics, out); } - if (ClassReader.ANNOTATIONS && ipanns != null) { + if (ipanns != null) { out.putShort(cw.newUTF8("RuntimeInvisibleParameterAnnotations")); AnnotationWriter.put(ipanns, synthetics, out); } @@ -2376,569 +2399,4 @@ class MethodWriter extends MethodVisitor { attrs.put(cw, null, 0, -1, -1, out); } } - - // ------------------------------------------------------------------------ - // Utility methods: instruction resizing (used to handle GOTO_W and JSR_W) - // ------------------------------------------------------------------------ - - /** - * Resizes and replaces the temporary instructions inserted by - * {@link Label#resolve} for wide forward jumps, while keeping jump offsets - * and instruction addresses consistent. This may require to resize other - * existing instructions, or even to introduce new instructions: for - * example, increasing the size of an instruction by 2 at the middle of a - * method can increases the offset of an IFEQ instruction from 32766 to - * 32768, in which case IFEQ 32766 must be replaced with IFNEQ 8 GOTO_W - * 32765. This, in turn, may require to increase the size of another jump - * instruction, and so on... All these operations are handled automatically - * by this method. - *

- * This method must be called after all the method that is being built - * has been visited. In particular, the {@link Label Label} objects used - * to construct the method are no longer valid after this method has been - * called. - */ - private void resizeInstructions() { - byte[] b = code.data; // bytecode of the method - int u, v, label; // indexes in b - int i, j; // loop indexes - /* - * 1st step: As explained above, resizing an instruction may require to - * resize another one, which may require to resize yet another one, and - * so on. The first step of the algorithm consists in finding all the - * instructions that need to be resized, without modifying the code. - * This is done by the following "fix point" algorithm: - * - * Parse the code to find the jump instructions whose offset will need - * more than 2 bytes to be stored (the future offset is computed from - * the current offset and from the number of bytes that will be inserted - * or removed between the source and target instructions). For each such - * instruction, adds an entry in (a copy of) the indexes and sizes - * arrays (if this has not already been done in a previous iteration!). - * - * If at least one entry has been added during the previous step, go - * back to the beginning, otherwise stop. - * - * In fact the real algorithm is complicated by the fact that the size - * of TABLESWITCH and LOOKUPSWITCH instructions depends on their - * position in the bytecode (because of padding). In order to ensure the - * convergence of the algorithm, the number of bytes to be added or - * removed from these instructions is over estimated during the previous - * loop, and computed exactly only after the loop is finished (this - * requires another pass to parse the bytecode of the method). - */ - int[] allIndexes = new int[0]; // copy of indexes - int[] allSizes = new int[0]; // copy of sizes - boolean[] resize; // instructions to be resized - int newOffset; // future offset of a jump instruction - - resize = new boolean[code.length]; - - // 3 = loop again, 2 = loop ended, 1 = last pass, 0 = done - int state = 3; - do { - if (state == 3) { - state = 2; - } - u = 0; - while (u < b.length) { - int opcode = b[u] & 0xFF; // opcode of current instruction - int insert = 0; // bytes to be added after this instruction - - switch (ClassWriter.TYPE[opcode]) { - case ClassWriter.NOARG_INSN: - case ClassWriter.IMPLVAR_INSN: - u += 1; - break; - case ClassWriter.LABEL_INSN: - if (opcode > 201) { - // converts temporary opcodes 202 to 217, 218 and - // 219 to IFEQ ... JSR (inclusive), IFNULL and - // IFNONNULL - opcode = opcode < 218 ? opcode - 49 : opcode - 20; - label = u + readUnsignedShort(b, u + 1); - } else { - label = u + readShort(b, u + 1); - } - newOffset = getNewOffset(allIndexes, allSizes, u, label); - if (newOffset < Short.MIN_VALUE - || newOffset > Short.MAX_VALUE) { - if (!resize[u]) { - if (opcode == Opcodes.GOTO || opcode == Opcodes.JSR) { - // two additional bytes will be required to - // replace this GOTO or JSR instruction with - // a GOTO_W or a JSR_W - insert = 2; - } else { - // five additional bytes will be required to - // replace this IFxxx instruction with - // IFNOTxxx GOTO_W , where IFNOTxxx - // is the "opposite" opcode of IFxxx (i.e., - // IFNE for IFEQ) and where designates - // the instruction just after the GOTO_W. - insert = 5; - } - resize[u] = true; - } - } - u += 3; - break; - case ClassWriter.LABELW_INSN: - u += 5; - break; - case ClassWriter.TABL_INSN: - if (state == 1) { - // true number of bytes to be added (or removed) - // from this instruction = (future number of padding - // bytes - current number of padding byte) - - // previously over estimated variation = - // = ((3 - newOffset%4) - (3 - u%4)) - u%4 - // = (-newOffset%4 + u%4) - u%4 - // = -(newOffset & 3) - newOffset = getNewOffset(allIndexes, allSizes, 0, u); - insert = -(newOffset & 3); - } else if (!resize[u]) { - // over estimation of the number of bytes to be - // added to this instruction = 3 - current number - // of padding bytes = 3 - (3 - u%4) = u%4 = u & 3 - insert = u & 3; - resize[u] = true; - } - // skips instruction - u = u + 4 - (u & 3); - u += 4 * (readInt(b, u + 8) - readInt(b, u + 4) + 1) + 12; - break; - case ClassWriter.LOOK_INSN: - if (state == 1) { - // like TABL_INSN - newOffset = getNewOffset(allIndexes, allSizes, 0, u); - insert = -(newOffset & 3); - } else if (!resize[u]) { - // like TABL_INSN - insert = u & 3; - resize[u] = true; - } - // skips instruction - u = u + 4 - (u & 3); - u += 8 * readInt(b, u + 4) + 8; - break; - case ClassWriter.WIDE_INSN: - opcode = b[u + 1] & 0xFF; - if (opcode == Opcodes.IINC) { - u += 6; - } else { - u += 4; - } - 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 ClassWriter.MANA_INSN: - default: - u += 4; - break; - } - if (insert != 0) { - // adds a new (u, insert) entry in the allIndexes and - // allSizes arrays - int[] newIndexes = new int[allIndexes.length + 1]; - int[] newSizes = new int[allSizes.length + 1]; - System.arraycopy(allIndexes, 0, newIndexes, 0, - allIndexes.length); - System.arraycopy(allSizes, 0, newSizes, 0, allSizes.length); - newIndexes[allIndexes.length] = u; - newSizes[allSizes.length] = insert; - allIndexes = newIndexes; - allSizes = newSizes; - if (insert > 0) { - state = 3; - } - } - } - if (state < 3) { - --state; - } - } while (state != 0); - - // 2nd step: - // copies the bytecode of the method into a new bytevector, updates the - // offsets, and inserts (or removes) bytes as requested. - - ByteVector newCode = new ByteVector(code.length); - - u = 0; - while (u < code.length) { - int opcode = b[u] & 0xFF; - switch (ClassWriter.TYPE[opcode]) { - case ClassWriter.NOARG_INSN: - case ClassWriter.IMPLVAR_INSN: - newCode.putByte(opcode); - u += 1; - break; - case ClassWriter.LABEL_INSN: - if (opcode > 201) { - // 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 = u + readUnsignedShort(b, u + 1); - } else { - label = u + readShort(b, u + 1); - } - newOffset = getNewOffset(allIndexes, allSizes, u, label); - if (resize[u]) { - // replaces GOTO with GOTO_W, JSR with JSR_W and IFxxx - // with IFNOTxxx GOTO_W , where IFNOTxxx is - // the "opposite" opcode of IFxxx (i.e., IFNE for IFEQ) - // and where designates the instruction just after - // the GOTO_W. - if (opcode == Opcodes.GOTO) { - newCode.putByte(200); // GOTO_W - } else if (opcode == Opcodes.JSR) { - newCode.putByte(201); // JSR_W - } else { - newCode.putByte(opcode <= 166 ? ((opcode + 1) ^ 1) - 1 - : opcode ^ 1); - newCode.putShort(8); // jump offset - newCode.putByte(200); // GOTO_W - // newOffset now computed from start of GOTO_W - newOffset -= 3; - } - newCode.putInt(newOffset); - } else { - newCode.putByte(opcode); - newCode.putShort(newOffset); - } - u += 3; - break; - case ClassWriter.LABELW_INSN: - label = u + readInt(b, u + 1); - newOffset = getNewOffset(allIndexes, allSizes, u, label); - newCode.putByte(opcode); - newCode.putInt(newOffset); - u += 5; - break; - case ClassWriter.TABL_INSN: - // skips 0 to 3 padding bytes - v = u; - u = u + 4 - (v & 3); - // reads and copies instruction - newCode.putByte(Opcodes.TABLESWITCH); - newCode.putByteArray(null, 0, (4 - newCode.length % 4) % 4); - label = v + readInt(b, u); - u += 4; - newOffset = getNewOffset(allIndexes, allSizes, v, label); - newCode.putInt(newOffset); - j = readInt(b, u); - u += 4; - newCode.putInt(j); - j = readInt(b, u) - j + 1; - u += 4; - newCode.putInt(readInt(b, u - 4)); - for (; j > 0; --j) { - label = v + readInt(b, u); - u += 4; - newOffset = getNewOffset(allIndexes, allSizes, v, label); - newCode.putInt(newOffset); - } - break; - case ClassWriter.LOOK_INSN: - // skips 0 to 3 padding bytes - v = u; - u = u + 4 - (v & 3); - // reads and copies instruction - newCode.putByte(Opcodes.LOOKUPSWITCH); - newCode.putByteArray(null, 0, (4 - newCode.length % 4) % 4); - label = v + readInt(b, u); - u += 4; - newOffset = getNewOffset(allIndexes, allSizes, v, label); - newCode.putInt(newOffset); - j = readInt(b, u); - u += 4; - newCode.putInt(j); - for (; j > 0; --j) { - newCode.putInt(readInt(b, u)); - u += 4; - label = v + readInt(b, u); - u += 4; - newOffset = getNewOffset(allIndexes, allSizes, v, label); - newCode.putInt(newOffset); - } - break; - case ClassWriter.WIDE_INSN: - opcode = b[u + 1] & 0xFF; - if (opcode == Opcodes.IINC) { - newCode.putByteArray(b, u, 6); - u += 6; - } else { - newCode.putByteArray(b, u, 4); - u += 4; - } - break; - case ClassWriter.VAR_INSN: - case ClassWriter.SBYTE_INSN: - case ClassWriter.LDC_INSN: - newCode.putByteArray(b, u, 2); - u += 2; - break; - case ClassWriter.SHORT_INSN: - case ClassWriter.LDCW_INSN: - case ClassWriter.FIELDORMETH_INSN: - case ClassWriter.TYPE_INSN: - case ClassWriter.IINC_INSN: - newCode.putByteArray(b, u, 3); - u += 3; - break; - case ClassWriter.ITFMETH_INSN: - case ClassWriter.INDYMETH_INSN: - newCode.putByteArray(b, u, 5); - u += 5; - break; - // case MANA_INSN: - default: - newCode.putByteArray(b, u, 4); - u += 4; - break; - } - } - - // updates the stack map frame labels - if (compute == FRAMES) { - Label l = labels; - while (l != null) { - /* - * Detects the labels that are just after an IF instruction that - * has been resized with the IFNOT GOTO_W pattern. These labels - * are now the target of a jump instruction (the IFNOT - * instruction). Note that we need the original label position - * here. getNewOffset must therefore never have been called for - * this label. - */ - u = l.position - 3; - if (u >= 0 && resize[u]) { - l.status |= Label.TARGET; - } - getNewOffset(allIndexes, allSizes, l); - l = l.successor; - } - // Update the offsets in the uninitialized types - if (cw.typeTable != null) { - for (i = 0; i < cw.typeTable.length; ++i) { - Item item = cw.typeTable[i]; - if (item != null && item.type == ClassWriter.TYPE_UNINIT) { - item.intVal = getNewOffset(allIndexes, allSizes, 0, - item.intVal); - } - } - } - // The stack map frames are not serialized yet, so we don't need - // to update them. They will be serialized in visitMaxs. - } else if (frameCount > 0) { - /* - * Resizing an existing stack map frame table is really hard. Not - * only the table must be parsed to update the offets, but new - * frames may be needed for jump instructions that were inserted by - * this method. And updating the offsets or inserting frames can - * change the format of the following frames, in case of packed - * frames. In practice the whole table must be recomputed. For this - * the frames are marked as potentially invalid. This will cause the - * whole class to be reread and rewritten with the COMPUTE_FRAMES - * option (see the ClassWriter.toByteArray method). This is not very - * efficient but is much easier and requires much less code than any - * other method I can think of. - */ - cw.invalidFrames = true; - } - // updates the exception handler block labels - Handler h = firstHandler; - while (h != null) { - getNewOffset(allIndexes, allSizes, h.start); - getNewOffset(allIndexes, allSizes, h.end); - getNewOffset(allIndexes, allSizes, h.handler); - h = h.next; - } - // updates the instructions addresses in the - // local var and line number tables - for (i = 0; i < 2; ++i) { - ByteVector bv = i == 0 ? localVar : localVarType; - if (bv != null) { - b = bv.data; - u = 0; - while (u < bv.length) { - label = readUnsignedShort(b, u); - newOffset = getNewOffset(allIndexes, allSizes, 0, label); - writeShort(b, u, newOffset); - label += readUnsignedShort(b, u + 2); - newOffset = getNewOffset(allIndexes, allSizes, 0, label) - - newOffset; - writeShort(b, u + 2, newOffset); - u += 10; - } - } - } - if (lineNumber != null) { - b = lineNumber.data; - u = 0; - while (u < lineNumber.length) { - writeShort( - b, - u, - getNewOffset(allIndexes, allSizes, 0, - readUnsignedShort(b, u))); - u += 4; - } - } - // updates the labels of the other attributes - Attribute attr = cattrs; - while (attr != null) { - Label[] labels = attr.getLabels(); - if (labels != null) { - for (i = labels.length - 1; i >= 0; --i) { - getNewOffset(allIndexes, allSizes, labels[i]); - } - } - attr = attr.next; - } - - // replaces old bytecodes with new ones - code = newCode; - } - - /** - * Reads an unsigned short value in the given byte array. - * - * @param b - * a byte array. - * @param index - * the start index of the value to be read. - * @return the read value. - */ - static int readUnsignedShort(final byte[] b, final int index) { - return ((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF); - } - - /** - * Reads a signed short value in the given byte array. - * - * @param b - * a byte array. - * @param index - * the start index of the value to be read. - * @return the read value. - */ - static short readShort(final byte[] b, final int index) { - return (short) (((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF)); - } - - /** - * Reads a signed int value in the given byte array. - * - * @param b - * a byte array. - * @param index - * the start index of the value to be read. - * @return the read value. - */ - static int readInt(final byte[] b, final int index) { - return ((b[index] & 0xFF) << 24) | ((b[index + 1] & 0xFF) << 16) - | ((b[index + 2] & 0xFF) << 8) | (b[index + 3] & 0xFF); - } - - /** - * Writes a short value in the given byte array. - * - * @param b - * a byte array. - * @param index - * where the first byte of the short value must be written. - * @param s - * the value to be written in the given byte array. - */ - static void writeShort(final byte[] b, final int index, final int s) { - b[index] = (byte) (s >>> 8); - b[index + 1] = (byte) s; - } - - /** - * Computes the future value of a bytecode offset. - *

- * Note: it is possible to have several entries for the same instruction in - * the indexes and sizes: two entries (index=a,size=b) and - * (index=a,size=b') are equivalent to a single entry (index=a,size=b+b'). - * - * @param indexes - * current positions of the instructions to be resized. Each - * instruction must be designated by the index of its last - * byte, plus one (or, in other words, by the index of the - * first byte of the next instruction). - * @param sizes - * the number of bytes to be added to the above - * instructions. More precisely, for each i < len, - * sizes[i] bytes will be added at the end of the - * instruction designated by indexes[i] or, if - * sizes[i] is negative, the last | - * sizes[i]| bytes of the instruction will be removed - * (the instruction size must not become negative or - * null). - * @param begin - * index of the first byte of the source instruction. - * @param end - * index of the first byte of the target instruction. - * @return the future value of the given bytecode offset. - */ - static int getNewOffset(final int[] indexes, final int[] sizes, - final int begin, final int end) { - int offset = end - begin; - for (int i = 0; i < indexes.length; ++i) { - if (begin < indexes[i] && indexes[i] <= end) { - // forward jump - offset += sizes[i]; - } else if (end < indexes[i] && indexes[i] <= begin) { - // backward jump - offset -= sizes[i]; - } - } - return offset; - } - - /** - * Updates the offset of the given label. - * - * @param indexes - * current positions of the instructions to be resized. Each - * instruction must be designated by the index of its last - * byte, plus one (or, in other words, by the index of the - * first byte of the next instruction). - * @param sizes - * the number of bytes to be added to the above - * instructions. More precisely, for each i < len, - * sizes[i] bytes will be added at the end of the - * instruction designated by indexes[i] or, if - * sizes[i] is negative, the last | - * sizes[i]| bytes of the instruction will be removed - * (the instruction size must not become negative or - * null). - * @param label - * the label whose offset must be updated. - */ - static void getNewOffset(final int[] indexes, final int[] sizes, - final Label label) { - if ((label.status & Label.RESIZED) == 0) { - label.position = getNewOffset(indexes, sizes, 0, label.position); - label.status |= Label.RESIZED; - } - } } diff --git a/src/org/redkale/asm/ModuleVisitor.java b/src/org/redkale/asm/ModuleVisitor.java new file mode 100644 index 000000000..cef97f2aa --- /dev/null +++ b/src/org/redkale/asm/ModuleVisitor.java @@ -0,0 +1,219 @@ +/* + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + */ + +/* + * + * + * + * + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.redkale.asm; + +/** + * A visitor to visit a Java module. The methods of this class must be called in + * the following order: visitMainClass | ( visitPackage | + * visitRequire | visitExport | visitOpen | + * visitUse | visitProvide )* visitEnd. + * + * The methods {@link #visitRequire(String, int, String)}, {@link #visitExport(String, int, String...)}, + * {@link #visitOpen(String, int, String...)} and {@link #visitPackage(String)} + * take as parameter a package name or a module name. Unlike the other names which are internal names + * (names separated by slash), module and package names are qualified names (names separated by dot). + * + * @author Remi Forax + */ +public abstract class ModuleVisitor { + /** + * The ASM API version implemented by this visitor. The value of this field + * must be {@link Opcodes#ASM6}. + */ + protected final int api; + + /** + * The module visitor to which this visitor must delegate method calls. May + * be null. + */ + protected ModuleVisitor mv; + + /** + * Constructs a new {@link ModuleVisitor}. + * + * @param api + * the ASM API version implemented by this visitor. Must be {@link Opcodes#ASM6}. + */ + public ModuleVisitor(final int api) { + this(api, null); + } + + /** + * Constructs a new {@link ModuleVisitor}. + * + * @param api + * the ASM API version implemented by this visitor. Must be {@link Opcodes#ASM6}. + * @param mv + * the module visitor to which this visitor must delegate method + * calls. May be null. + */ + public ModuleVisitor(final int api, final ModuleVisitor mv) { + if (api != Opcodes.ASM6) { + throw new IllegalArgumentException(); + } + this.api = api; + this.mv = mv; + } + + /** + * Visit the main class of the current module. + * + * @param mainClass the internal name of the main class of the current module. + */ + public void visitMainClass(String mainClass) { + if (mv != null) { + mv.visitMainClass(mainClass); + } + } + + /** + * Visit a package of the current module. + * + * @param packaze the qualified name of a package. + */ + public void visitPackage(String packaze) { + if (mv != null) { + mv.visitPackage(packaze); + } + } + + /** + * Visits a dependence of the current module. + * + * @param module the qualified name of the dependence. + * @param access the access flag of the dependence among + * ACC_TRANSITIVE, ACC_STATIC_PHASE, ACC_SYNTHETIC + * and ACC_MANDATED. + * @param version the module version at compile time or null. + */ + public void visitRequire(String module, int access, String version) { + if (mv != null) { + mv.visitRequire(module, access, version); + } + } + + /** + * Visit an exported package of the current module. + * + * @param packaze the qualified name of the exported package. + * @param access the access flag of the exported package, + * valid values are among {@code ACC_SYNTHETIC} and + * {@code ACC_MANDATED}. + * @param modules the qualified names of the modules that can access to + * the public classes of the exported package or + * null. + */ + public void visitExport(String packaze, int access, String... modules) { + if (mv != null) { + mv.visitExport(packaze, access, modules); + } + } + + /** + * Visit an open package of the current module. + * + * @param packaze the qualified name of the opened package. + * @param access the access flag of the opened package, + * valid values are among {@code ACC_SYNTHETIC} and + * {@code ACC_MANDATED}. + * @param modules the qualified names of the modules that can use deep + * reflection to the classes of the open package or + * null. + */ + public void visitOpen(String packaze, int access, String... modules) { + if (mv != null) { + mv.visitOpen(packaze, access, modules); + } + } + + /** + * Visit a service used by the current module. + * The name must be the internal name of an interface or a class. + * + * @param service the internal name of the service. + */ + public void visitUse(String service) { + if (mv != null) { + mv.visitUse(service); + } + } + + /** + * Visit an implementation of a service. + * + * @param service the internal name of the service + * @param providers the internal names of the implementations + * of the service (there is at least one provider). + */ + public void visitProvide(String service, String... providers) { + if (mv != null) { + mv.visitProvide(service, providers); + } + } + + /** + * Visits the end of the module. This method, which is the last one to be + * called, is used to inform the visitor that everything have been visited. + */ + public void visitEnd() { + if (mv != null) { + mv.visitEnd(); + } + } +} diff --git a/src/org/redkale/asm/ModuleWriter.java b/src/org/redkale/asm/ModuleWriter.java new file mode 100644 index 000000000..57277cd94 --- /dev/null +++ b/src/org/redkale/asm/ModuleWriter.java @@ -0,0 +1,322 @@ +/* + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + */ + +/* + * + * + * + * + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.redkale.asm; + +/** + * @author Remi Forax + */ +final class ModuleWriter extends ModuleVisitor { + /** + * The class writer to which this Module attribute must be added. + */ + private final ClassWriter cw; + + /** + * size in byte of the Module attribute. + */ + int size; + + /** + * Number of attributes associated with the current module + * (Version, ConcealPackages, etc) + */ + int attributeCount; + + /** + * Size in bytes of the attributes associated with the current module + */ + int attributesSize; + + /** + * module name index in the constant pool + */ + private final int name; + + /** + * module access flags + */ + private final int access; + + /** + * module version index in the constant pool or 0 + */ + private final int version; + + /** + * module main class index in the constant pool or 0 + */ + private int mainClass; + + /** + * number of packages + */ + private int packageCount; + + /** + * The packages in bytecode form. This byte vector only contains + * the items themselves, the number of items is store in packageCount + */ + private ByteVector packages; + + /** + * number of requires items + */ + private int requireCount; + + /** + * The requires items in bytecode form. This byte vector only contains + * the items themselves, the number of items is store in requireCount + */ + private ByteVector requires; + + /** + * number of exports items + */ + private int exportCount; + + /** + * The exports items in bytecode form. This byte vector only contains + * the items themselves, the number of items is store in exportCount + */ + private ByteVector exports; + + /** + * number of opens items + */ + private int openCount; + + /** + * The opens items in bytecode form. This byte vector only contains + * the items themselves, the number of items is store in openCount + */ + private ByteVector opens; + + /** + * number of uses items + */ + private int useCount; + + /** + * The uses items in bytecode form. This byte vector only contains + * the items themselves, the number of items is store in useCount + */ + private ByteVector uses; + + /** + * number of provides items + */ + private int provideCount; + + /** + * The uses provides in bytecode form. This byte vector only contains + * the items themselves, the number of items is store in provideCount + */ + private ByteVector provides; + + ModuleWriter(final ClassWriter cw, final int name, + final int access, final int version) { + super(Opcodes.ASM6); + this.cw = cw; + this.size = 16; // name + access + version + 5 counts + this.name = name; + this.access = access; + this.version = version; + } + + @Override + public void visitMainClass(String mainClass) { + if (this.mainClass == 0) { // protect against several calls to visitMainClass + cw.newUTF8("ModuleMainClass"); + attributeCount++; + attributesSize += 8; + } + this.mainClass = cw.newClass(mainClass); + } + + @Override + public void visitPackage(String packaze) { + if (packages == null) { + // protect against several calls to visitPackage + cw.newUTF8("ModulePackages"); + packages = new ByteVector(); + attributeCount++; + attributesSize += 8; + } + packages.putShort(cw.newPackage(packaze)); + packageCount++; + attributesSize += 2; + } + + @Override + public void visitRequire(String module, int access, String version) { + if (requires == null) { + requires = new ByteVector(); + } + requires.putShort(cw.newModule(module)) + .putShort(access) + .putShort(version == null? 0: cw.newUTF8(version)); + requireCount++; + size += 6; + } + + @Override + public void visitExport(String packaze, int access, String... modules) { + if (exports == null) { + exports = new ByteVector(); + } + exports.putShort(cw.newPackage(packaze)).putShort(access); + if (modules == null) { + exports.putShort(0); + size += 6; + } else { + exports.putShort(modules.length); + for(String module: modules) { + exports.putShort(cw.newModule(module)); + } + size += 6 + 2 * modules.length; + } + exportCount++; + } + + @Override + public void visitOpen(String packaze, int access, String... modules) { + if (opens == null) { + opens = new ByteVector(); + } + opens.putShort(cw.newPackage(packaze)).putShort(access); + if (modules == null) { + opens.putShort(0); + size += 6; + } else { + opens.putShort(modules.length); + for(String module: modules) { + opens.putShort(cw.newModule(module)); + } + size += 6 + 2 * modules.length; + } + openCount++; + } + + @Override + public void visitUse(String service) { + if (uses == null) { + uses = new ByteVector(); + } + uses.putShort(cw.newClass(service)); + useCount++; + size += 2; + } + + @Override + public void visitProvide(String service, String... providers) { + if (provides == null) { + provides = new ByteVector(); + } + provides.putShort(cw.newClass(service)); + provides.putShort(providers.length); + for(String provider: providers) { + provides.putShort(cw.newClass(provider)); + } + provideCount++; + size += 4 + 2 * providers.length; + } + + @Override + public void visitEnd() { + // empty + } + + void putAttributes(ByteVector out) { + if (mainClass != 0) { + out.putShort(cw.newUTF8("ModuleMainClass")).putInt(2).putShort(mainClass); + } + if (packages != null) { + out.putShort(cw.newUTF8("ModulePackages")) + .putInt(2 + 2 * packageCount) + .putShort(packageCount) + .putByteArray(packages.data, 0, packages.length); + } + } + + void put(ByteVector out) { + out.putInt(size); + out.putShort(name).putShort(access).putShort(version); + out.putShort(requireCount); + if (requires != null) { + out.putByteArray(requires.data, 0, requires.length); + } + out.putShort(exportCount); + if (exports != null) { + out.putByteArray(exports.data, 0, exports.length); + } + out.putShort(openCount); + if (opens != null) { + out.putByteArray(opens.data, 0, opens.length); + } + out.putShort(useCount); + if (uses != null) { + out.putByteArray(uses.data, 0, uses.length); + } + out.putShort(provideCount); + if (provides != null) { + out.putByteArray(provides.data, 0, provides.length); + } + } +} diff --git a/src/org/redkale/asm/Opcodes.java b/src/org/redkale/asm/Opcodes.java index 3ffbad8b6..ccb07f345 100644 --- a/src/org/redkale/asm/Opcodes.java +++ b/src/org/redkale/asm/Opcodes.java @@ -1,4 +1,33 @@ /* + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + */ + +/* + * + * + * + * + * * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000-2011 INRIA, France Telecom * All rights reserved. @@ -41,13 +70,13 @@ package org.redkale.asm; * @author Eric Bruneton * @author Eugene Kuleshov */ -@SuppressWarnings("deprecation") // for Integer(int) constructor public interface Opcodes { // ASM API versions int ASM4 = 4 << 16 | 0 << 8 | 0; int ASM5 = 5 << 16 | 0 << 8 | 0; + int ASM6 = 6 << 16 | 0 << 8 | 0; // versions @@ -59,7 +88,8 @@ public interface Opcodes { int V1_6 = 0 << 16 | 50; int V1_7 = 0 << 16 | 51; int V1_8 = 0 << 16 | 52; - int V1_9 = 0 << 16 | 53; + int V9 = 0 << 16 | 53; + int V10 = 0 << 16 | 54; // access flags @@ -70,18 +100,23 @@ public interface Opcodes { int ACC_FINAL = 0x0010; // class, field, method, parameter int ACC_SUPER = 0x0020; // class int ACC_SYNCHRONIZED = 0x0020; // method + int ACC_OPEN = 0x0020; // module + int ACC_TRANSITIVE = 0x0020; // module requires int ACC_VOLATILE = 0x0040; // field int ACC_BRIDGE = 0x0040; // method + int ACC_STATIC_PHASE = 0x0040; // module requires int ACC_VARARGS = 0x0080; // method int ACC_TRANSIENT = 0x0080; // field int ACC_NATIVE = 0x0100; // method int ACC_INTERFACE = 0x0200; // class int ACC_ABSTRACT = 0x0400; // class, method int ACC_STRICT = 0x0800; // method - int ACC_SYNTHETIC = 0x1000; // class, field, method, parameter + int ACC_SYNTHETIC = 0x1000; // class, field, method, parameter, module * int ACC_ANNOTATION = 0x2000; // class int ACC_ENUM = 0x4000; // class(?) field inner - int ACC_MANDATED = 0x8000; // parameter + int ACC_MANDATED = 0x8000; // parameter, module, module * + int ACC_MODULE = 0x8000; // class + // ASM specific pseudo access flags @@ -148,15 +183,17 @@ public interface Opcodes { */ int F_SAME1 = 4; - // For reference comparison purposes, construct new instances - // instead of using valueOf() or autoboxing. - Integer TOP = new Integer(0); - Integer INTEGER = new Integer(1); - Integer FLOAT = new Integer(2); - Integer DOUBLE = new Integer(3); - Integer LONG = new Integer(4); - Integer NULL = new Integer(5); - Integer UNINITIALIZED_THIS = new Integer(6); + // Do not try to change the following code to use auto-boxing, + // these values are compared by reference and not by value + // The constructor of Integer was deprecated in 9 + // but we are stuck with it by backward compatibility + @SuppressWarnings("deprecation") Integer TOP = new Integer(0); + @SuppressWarnings("deprecation") Integer INTEGER = new Integer(1); + @SuppressWarnings("deprecation") Integer FLOAT = new Integer(2); + @SuppressWarnings("deprecation") Integer DOUBLE = new Integer(3); + @SuppressWarnings("deprecation") Integer LONG = new Integer(4); + @SuppressWarnings("deprecation") Integer NULL = new Integer(5); + @SuppressWarnings("deprecation") Integer UNINITIALIZED_THIS = new Integer(6); // opcodes // visit method (- = idem) diff --git a/src/org/redkale/asm/Type.java b/src/org/redkale/asm/Type.java index 00710efc0..cc644bb5c 100644 --- a/src/org/redkale/asm/Type.java +++ b/src/org/redkale/asm/Type.java @@ -406,7 +406,16 @@ public class Type { */ public static Type getReturnType(final String methodDescriptor) { char[] buf = methodDescriptor.toCharArray(); - return getType(buf, methodDescriptor.indexOf(')') + 1); + int off = 1; + while (true) { + char car = buf[off++]; + if (car == ')') { + return getType(buf, off); + } else if (car == 'L') { + while (buf[off++] != ';') { + } + } + } } /** diff --git a/src/org/redkale/asm/TypeReference.java b/src/org/redkale/asm/TypeReference.java index 83bcfadb4..38579e7b5 100644 --- a/src/org/redkale/asm/TypeReference.java +++ b/src/org/redkale/asm/TypeReference.java @@ -1,427 +1,481 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package org.redkale.asm; - -/** - * A reference to a type appearing in a class, field or method declaration, or - * on an instruction. Such a reference designates the part of the class where - * the referenced type is appearing (e.g. an 'extends', 'implements' or 'throws' - * clause, a 'new' instruction, a 'catch' clause, a type cast, a local variable - * declaration, etc). - * - * @author Eric Bruneton - */ -public class TypeReference { - - /** - * The sort of type references that target a type parameter of a generic - * class. See {@link #getSort getSort}. - */ - public final static int CLASS_TYPE_PARAMETER = 0x00; - - /** - * The sort of type references that target a type parameter of a generic - * method. See {@link #getSort getSort}. - */ - public final static int METHOD_TYPE_PARAMETER = 0x01; - - /** - * The sort of type references that target the super class of a class or one - * of the interfaces it implements. See {@link #getSort getSort}. - */ - public final static int CLASS_EXTENDS = 0x10; - - /** - * The sort of type references that target a bound of a type parameter of a - * generic class. See {@link #getSort getSort}. - */ - public final static int CLASS_TYPE_PARAMETER_BOUND = 0x11; - - /** - * The sort of type references that target a bound of a type parameter of a - * generic method. See {@link #getSort getSort}. - */ - public final static int METHOD_TYPE_PARAMETER_BOUND = 0x12; - - /** - * The sort of type references that target the type of a field. See - * {@link #getSort getSort}. - */ - public final static int FIELD = 0x13; - - /** - * The sort of type references that target the return type of a method. See - * {@link #getSort getSort}. - */ - public final static int METHOD_RETURN = 0x14; - - /** - * The sort of type references that target the receiver type of a method. - * See {@link #getSort getSort}. - */ - public final static int METHOD_RECEIVER = 0x15; - - /** - * The sort of type references that target the type of a formal parameter of - * a method. See {@link #getSort getSort}. - */ - public final static int METHOD_FORMAL_PARAMETER = 0x16; - - /** - * The sort of type references that target the type of an exception declared - * in the throws clause of a method. See {@link #getSort getSort}. - */ - public final static int THROWS = 0x17; - - /** - * The sort of type references that target the type of a local variable in a - * method. See {@link #getSort getSort}. - */ - public final static int LOCAL_VARIABLE = 0x40; - - /** - * The sort of type references that target the type of a resource variable - * in a method. See {@link #getSort getSort}. - */ - public final static int RESOURCE_VARIABLE = 0x41; - - /** - * The sort of type references that target the type of the exception of a - * 'catch' clause in a method. See {@link #getSort getSort}. - */ - public final static int EXCEPTION_PARAMETER = 0x42; - - /** - * The sort of type references that target the type declared in an - * 'instanceof' instruction. See {@link #getSort getSort}. - */ - public final static int INSTANCEOF = 0x43; - - /** - * The sort of type references that target the type of the object created by - * a 'new' instruction. See {@link #getSort getSort}. - */ - public final static int NEW = 0x44; - - /** - * The sort of type references that target the receiver type of a - * constructor reference. See {@link #getSort getSort}. - */ - public final static int CONSTRUCTOR_REFERENCE = 0x45; - - /** - * The sort of type references that target the receiver type of a method - * reference. See {@link #getSort getSort}. - */ - public final static int METHOD_REFERENCE = 0x46; - - /** - * The sort of type references that target the type declared in an explicit - * or implicit cast instruction. See {@link #getSort getSort}. - */ - public final static int CAST = 0x47; - - /** - * The sort of type references that target a type parameter of a generic - * constructor in a constructor call. See {@link #getSort getSort}. - */ - public final static int CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT = 0x48; - - /** - * The sort of type references that target a type parameter of a generic - * method in a method call. See {@link #getSort getSort}. - */ - public final static int METHOD_INVOCATION_TYPE_ARGUMENT = 0x49; - - /** - * The sort of type references that target a type parameter of a generic - * constructor in a constructor reference. See {@link #getSort getSort}. - */ - public final static int CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT = 0x4A; - - /** - * The sort of type references that target a type parameter of a generic - * method in a method reference. See {@link #getSort getSort}. - */ - public final static int METHOD_REFERENCE_TYPE_ARGUMENT = 0x4B; - - /** - * The type reference value in Java class file format. - */ - private int value; - - /** - * Creates a new TypeReference. - * - * @param typeRef - * the int encoded value of the type reference, as received in a - * visit method related to type annotations, like - * visitTypeAnnotation. - */ - public TypeReference(int typeRef) { - this.value = typeRef; - } - - /** - * Returns a type reference of the given sort. - * - * @param sort - * {@link #FIELD FIELD}, {@link #METHOD_RETURN METHOD_RETURN}, - * {@link #METHOD_RECEIVER METHOD_RECEIVER}, - * {@link #LOCAL_VARIABLE LOCAL_VARIABLE}, - * {@link #RESOURCE_VARIABLE RESOURCE_VARIABLE}, - * {@link #INSTANCEOF INSTANCEOF}, {@link #NEW NEW}, - * {@link #CONSTRUCTOR_REFERENCE CONSTRUCTOR_REFERENCE}, or - * {@link #METHOD_REFERENCE METHOD_REFERENCE}. - * @return a type reference of the given sort. - */ - public static TypeReference newTypeReference(int sort) { - return new TypeReference(sort << 24); - } - - /** - * Returns a reference to a type parameter of a generic class or method. - * - * @param sort - * {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER} or - * {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER}. - * @param paramIndex - * the type parameter index. - * @return a reference to the given generic class or method type parameter. - */ - public static TypeReference newTypeParameterReference(int sort, - int paramIndex) { - return new TypeReference((sort << 24) | (paramIndex << 16)); - } - - /** - * Returns a reference to a type parameter bound of a generic class or - * method. - * - * @param sort - * {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER} or - * {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER}. - * @param paramIndex - * the type parameter index. - * @param boundIndex - * the type bound index within the above type parameters. - * @return a reference to the given generic class or method type parameter - * bound. - */ - public static TypeReference newTypeParameterBoundReference(int sort, - int paramIndex, int boundIndex) { - return new TypeReference((sort << 24) | (paramIndex << 16) - | (boundIndex << 8)); - } - - /** - * Returns a reference to the super class or to an interface of the - * 'implements' clause of a class. - * - * @param itfIndex - * the index of an interface in the 'implements' clause of a - * class, or -1 to reference the super class of the class. - * @return a reference to the given super type of a class. - */ - public static TypeReference newSuperTypeReference(int itfIndex) { - itfIndex &= 0xFFFF; - return new TypeReference((CLASS_EXTENDS << 24) | (itfIndex << 8)); - } - - /** - * Returns a reference to the type of a formal parameter of a method. - * - * @param paramIndex - * the formal parameter index. - * - * @return a reference to the type of the given method formal parameter. - */ - public static TypeReference newFormalParameterReference(int paramIndex) { - return new TypeReference((METHOD_FORMAL_PARAMETER << 24) - | (paramIndex << 16)); - } - - /** - * Returns a reference to the type of an exception, in a 'throws' clause of - * a method. - * - * @param exceptionIndex - * the index of an exception in a 'throws' clause of a method. - * - * @return a reference to the type of the given exception. - */ - public static TypeReference newExceptionReference(int exceptionIndex) { - return new TypeReference((THROWS << 24) | (exceptionIndex << 8)); - } - - /** - * Returns a reference to the type of the exception declared in a 'catch' - * clause of a method. - * - * @param tryCatchBlockIndex - * the index of a try catch block (using the order in which they - * are visited with visitTryCatchBlock). - * - * @return a reference to the type of the given exception. - */ - public static TypeReference newTryCatchReference(int tryCatchBlockIndex) { - return new TypeReference((EXCEPTION_PARAMETER << 24) - | (tryCatchBlockIndex << 8)); - } - - /** - * Returns a reference to the type of a type argument in a constructor or - * method call or reference. - * - * @param sort - * {@link #CAST CAST}, - * {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT - * CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, - * {@link #METHOD_INVOCATION_TYPE_ARGUMENT - * METHOD_INVOCATION_TYPE_ARGUMENT}, - * {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT - * CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or - * {@link #METHOD_REFERENCE_TYPE_ARGUMENT - * METHOD_REFERENCE_TYPE_ARGUMENT}. - * @param argIndex - * the type argument index. - * - * @return a reference to the type of the given type argument. - */ - public static TypeReference newTypeArgumentReference(int sort, int argIndex) { - return new TypeReference((sort << 24) | argIndex); - } - - /** - * Returns the sort of this type reference. - * - * @return {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER}, - * {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER}, - * {@link #CLASS_EXTENDS CLASS_EXTENDS}, - * {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND}, - * {@link #METHOD_TYPE_PARAMETER_BOUND METHOD_TYPE_PARAMETER_BOUND}, - * {@link #FIELD FIELD}, {@link #METHOD_RETURN METHOD_RETURN}, - * {@link #METHOD_RECEIVER METHOD_RECEIVER}, - * {@link #METHOD_FORMAL_PARAMETER METHOD_FORMAL_PARAMETER}, - * {@link #THROWS THROWS}, {@link #LOCAL_VARIABLE LOCAL_VARIABLE}, - * {@link #RESOURCE_VARIABLE RESOURCE_VARIABLE}, - * {@link #EXCEPTION_PARAMETER EXCEPTION_PARAMETER}, - * {@link #INSTANCEOF INSTANCEOF}, {@link #NEW NEW}, - * {@link #CONSTRUCTOR_REFERENCE CONSTRUCTOR_REFERENCE}, - * {@link #METHOD_REFERENCE METHOD_REFERENCE}, {@link #CAST CAST}, - * {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT - * CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, - * {@link #METHOD_INVOCATION_TYPE_ARGUMENT - * METHOD_INVOCATION_TYPE_ARGUMENT}, - * {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT - * CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or - * {@link #METHOD_REFERENCE_TYPE_ARGUMENT - * METHOD_REFERENCE_TYPE_ARGUMENT}. - */ - public int getSort() { - return value >>> 24; - } - - /** - * Returns the index of the type parameter referenced by this type - * reference. This method must only be used for type references whose sort - * is {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER}, - * {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER}, - * {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND} or - * {@link #METHOD_TYPE_PARAMETER_BOUND METHOD_TYPE_PARAMETER_BOUND}. - * - * @return a type parameter index. - */ - public int getTypeParameterIndex() { - return (value & 0x00FF0000) >> 16; - } - - /** - * Returns the index of the type parameter bound, within the type parameter - * {@link #getTypeParameterIndex}, referenced by this type reference. This - * method must only be used for type references whose sort is - * {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND} or - * {@link #METHOD_TYPE_PARAMETER_BOUND METHOD_TYPE_PARAMETER_BOUND}. - * - * @return a type parameter bound index. - */ - public int getTypeParameterBoundIndex() { - return (value & 0x0000FF00) >> 8; - } - - /** - * Returns the index of the "super type" of a class that is referenced by - * this type reference. This method must only be used for type references - * whose sort is {@link #CLASS_EXTENDS CLASS_EXTENDS}. - * - * @return the index of an interface in the 'implements' clause of a class, - * or -1 if this type reference references the type of the super - * class. - */ - public int getSuperTypeIndex() { - return (short) ((value & 0x00FFFF00) >> 8); - } - - /** - * Returns the index of the formal parameter whose type is referenced by - * this type reference. This method must only be used for type references - * whose sort is {@link #METHOD_FORMAL_PARAMETER METHOD_FORMAL_PARAMETER}. - * - * @return a formal parameter index. - */ - public int getFormalParameterIndex() { - return (value & 0x00FF0000) >> 16; - } - - /** - * Returns the index of the exception, in a 'throws' clause of a method, - * whose type is referenced by this type reference. This method must only be - * used for type references whose sort is {@link #THROWS THROWS}. - * - * @return the index of an exception in the 'throws' clause of a method. - */ - public int getExceptionIndex() { - return (value & 0x00FFFF00) >> 8; - } - - /** - * Returns the index of the try catch block (using the order in which they - * are visited with visitTryCatchBlock), whose 'catch' type is referenced by - * this type reference. This method must only be used for type references - * whose sort is {@link #EXCEPTION_PARAMETER EXCEPTION_PARAMETER} . - * - * @return the index of an exception in the 'throws' clause of a method. - */ - public int getTryCatchBlockIndex() { - return (value & 0x00FFFF00) >> 8; - } - - /** - * Returns the index of the type argument referenced by this type reference. - * This method must only be used for type references whose sort is - * {@link #CAST CAST}, {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT - * CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, - * {@link #METHOD_INVOCATION_TYPE_ARGUMENT METHOD_INVOCATION_TYPE_ARGUMENT}, - * {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT - * CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or - * {@link #METHOD_REFERENCE_TYPE_ARGUMENT METHOD_REFERENCE_TYPE_ARGUMENT}. - * - * @return a type parameter index. - */ - public int getTypeArgumentIndex() { - return value & 0xFF; - } - - /** - * Returns the int encoded value of this type reference, suitable for use in - * visit methods related to type annotations, like visitTypeAnnotation. - * - * @return the int encoded value of this type reference. - */ - public int getValue() { - return value; - } -} +/* + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + */ + +/* + * + * + * + * + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2013 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.redkale.asm; + +/** + * A reference to a type appearing in a class, field or method declaration, or + * on an instruction. Such a reference designates the part of the class where + * the referenced type is appearing (e.g. an 'extends', 'implements' or 'throws' + * clause, a 'new' instruction, a 'catch' clause, a type cast, a local variable + * declaration, etc). + * + * @author Eric Bruneton + */ +public class TypeReference { + + /** + * The sort of type references that target a type parameter of a generic + * class. See {@link #getSort getSort}. + */ + public final static int CLASS_TYPE_PARAMETER = 0x00; + + /** + * The sort of type references that target a type parameter of a generic + * method. See {@link #getSort getSort}. + */ + public final static int METHOD_TYPE_PARAMETER = 0x01; + + /** + * The sort of type references that target the super class of a class or one + * of the interfaces it implements. See {@link #getSort getSort}. + */ + public final static int CLASS_EXTENDS = 0x10; + + /** + * The sort of type references that target a bound of a type parameter of a + * generic class. See {@link #getSort getSort}. + */ + public final static int CLASS_TYPE_PARAMETER_BOUND = 0x11; + + /** + * The sort of type references that target a bound of a type parameter of a + * generic method. See {@link #getSort getSort}. + */ + public final static int METHOD_TYPE_PARAMETER_BOUND = 0x12; + + /** + * The sort of type references that target the type of a field. See + * {@link #getSort getSort}. + */ + public final static int FIELD = 0x13; + + /** + * The sort of type references that target the return type of a method. See + * {@link #getSort getSort}. + */ + public final static int METHOD_RETURN = 0x14; + + /** + * The sort of type references that target the receiver type of a method. + * See {@link #getSort getSort}. + */ + public final static int METHOD_RECEIVER = 0x15; + + /** + * The sort of type references that target the type of a formal parameter of + * a method. See {@link #getSort getSort}. + */ + public final static int METHOD_FORMAL_PARAMETER = 0x16; + + /** + * The sort of type references that target the type of an exception declared + * in the throws clause of a method. See {@link #getSort getSort}. + */ + public final static int THROWS = 0x17; + + /** + * The sort of type references that target the type of a local variable in a + * method. See {@link #getSort getSort}. + */ + public final static int LOCAL_VARIABLE = 0x40; + + /** + * The sort of type references that target the type of a resource variable + * in a method. See {@link #getSort getSort}. + */ + public final static int RESOURCE_VARIABLE = 0x41; + + /** + * The sort of type references that target the type of the exception of a + * 'catch' clause in a method. See {@link #getSort getSort}. + */ + public final static int EXCEPTION_PARAMETER = 0x42; + + /** + * The sort of type references that target the type declared in an + * 'instanceof' instruction. See {@link #getSort getSort}. + */ + public final static int INSTANCEOF = 0x43; + + /** + * The sort of type references that target the type of the object created by + * a 'new' instruction. See {@link #getSort getSort}. + */ + public final static int NEW = 0x44; + + /** + * The sort of type references that target the receiver type of a + * constructor reference. See {@link #getSort getSort}. + */ + public final static int CONSTRUCTOR_REFERENCE = 0x45; + + /** + * The sort of type references that target the receiver type of a method + * reference. See {@link #getSort getSort}. + */ + public final static int METHOD_REFERENCE = 0x46; + + /** + * The sort of type references that target the type declared in an explicit + * or implicit cast instruction. See {@link #getSort getSort}. + */ + public final static int CAST = 0x47; + + /** + * The sort of type references that target a type parameter of a generic + * constructor in a constructor call. See {@link #getSort getSort}. + */ + public final static int CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT = 0x48; + + /** + * The sort of type references that target a type parameter of a generic + * method in a method call. See {@link #getSort getSort}. + */ + public final static int METHOD_INVOCATION_TYPE_ARGUMENT = 0x49; + + /** + * The sort of type references that target a type parameter of a generic + * constructor in a constructor reference. See {@link #getSort getSort}. + */ + public final static int CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT = 0x4A; + + /** + * The sort of type references that target a type parameter of a generic + * method in a method reference. See {@link #getSort getSort}. + */ + public final static int METHOD_REFERENCE_TYPE_ARGUMENT = 0x4B; + + /** + * The type reference value in Java class file format. + */ + private int value; + + /** + * Creates a new TypeReference. + * + * @param typeRef + * the int encoded value of the type reference, as received in a + * visit method related to type annotations, like + * visitTypeAnnotation. + */ + public TypeReference(int typeRef) { + this.value = typeRef; + } + + /** + * Returns a type reference of the given sort. + * + * @param sort + * {@link #FIELD FIELD}, {@link #METHOD_RETURN METHOD_RETURN}, + * {@link #METHOD_RECEIVER METHOD_RECEIVER}, + * {@link #LOCAL_VARIABLE LOCAL_VARIABLE}, + * {@link #RESOURCE_VARIABLE RESOURCE_VARIABLE}, + * {@link #INSTANCEOF INSTANCEOF}, {@link #NEW NEW}, + * {@link #CONSTRUCTOR_REFERENCE CONSTRUCTOR_REFERENCE}, or + * {@link #METHOD_REFERENCE METHOD_REFERENCE}. + * @return a type reference of the given sort. + */ + public static TypeReference newTypeReference(int sort) { + return new TypeReference(sort << 24); + } + + /** + * Returns a reference to a type parameter of a generic class or method. + * + * @param sort + * {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER} or + * {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER}. + * @param paramIndex + * the type parameter index. + * @return a reference to the given generic class or method type parameter. + */ + public static TypeReference newTypeParameterReference(int sort, + int paramIndex) { + return new TypeReference((sort << 24) | (paramIndex << 16)); + } + + /** + * Returns a reference to a type parameter bound of a generic class or + * method. + * + * @param sort + * {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER} or + * {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER}. + * @param paramIndex + * the type parameter index. + * @param boundIndex + * the type bound index within the above type parameters. + * @return a reference to the given generic class or method type parameter + * bound. + */ + public static TypeReference newTypeParameterBoundReference(int sort, + int paramIndex, int boundIndex) { + return new TypeReference((sort << 24) | (paramIndex << 16) + | (boundIndex << 8)); + } + + /** + * Returns a reference to the super class or to an interface of the + * 'implements' clause of a class. + * + * @param itfIndex + * the index of an interface in the 'implements' clause of a + * class, or -1 to reference the super class of the class. + * @return a reference to the given super type of a class. + */ + public static TypeReference newSuperTypeReference(int itfIndex) { + itfIndex &= 0xFFFF; + return new TypeReference((CLASS_EXTENDS << 24) | (itfIndex << 8)); + } + + /** + * Returns a reference to the type of a formal parameter of a method. + * + * @param paramIndex + * the formal parameter index. + * + * @return a reference to the type of the given method formal parameter. + */ + public static TypeReference newFormalParameterReference(int paramIndex) { + return new TypeReference((METHOD_FORMAL_PARAMETER << 24) + | (paramIndex << 16)); + } + + /** + * Returns a reference to the type of an exception, in a 'throws' clause of + * a method. + * + * @param exceptionIndex + * the index of an exception in a 'throws' clause of a method. + * + * @return a reference to the type of the given exception. + */ + public static TypeReference newExceptionReference(int exceptionIndex) { + return new TypeReference((THROWS << 24) | (exceptionIndex << 8)); + } + + /** + * Returns a reference to the type of the exception declared in a 'catch' + * clause of a method. + * + * @param tryCatchBlockIndex + * the index of a try catch block (using the order in which they + * are visited with visitTryCatchBlock). + * + * @return a reference to the type of the given exception. + */ + public static TypeReference newTryCatchReference(int tryCatchBlockIndex) { + return new TypeReference((EXCEPTION_PARAMETER << 24) + | (tryCatchBlockIndex << 8)); + } + + /** + * Returns a reference to the type of a type argument in a constructor or + * method call or reference. + * + * @param sort + * {@link #CAST CAST}, + * {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT + * CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, + * {@link #METHOD_INVOCATION_TYPE_ARGUMENT + * METHOD_INVOCATION_TYPE_ARGUMENT}, + * {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT + * CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or + * {@link #METHOD_REFERENCE_TYPE_ARGUMENT + * METHOD_REFERENCE_TYPE_ARGUMENT}. + * @param argIndex + * the type argument index. + * + * @return a reference to the type of the given type argument. + */ + public static TypeReference newTypeArgumentReference(int sort, int argIndex) { + return new TypeReference((sort << 24) | argIndex); + } + + /** + * Returns the sort of this type reference. + * + * @return {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER}, + * {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER}, + * {@link #CLASS_EXTENDS CLASS_EXTENDS}, + * {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND}, + * {@link #METHOD_TYPE_PARAMETER_BOUND METHOD_TYPE_PARAMETER_BOUND}, + * {@link #FIELD FIELD}, {@link #METHOD_RETURN METHOD_RETURN}, + * {@link #METHOD_RECEIVER METHOD_RECEIVER}, + * {@link #METHOD_FORMAL_PARAMETER METHOD_FORMAL_PARAMETER}, + * {@link #THROWS THROWS}, {@link #LOCAL_VARIABLE LOCAL_VARIABLE}, + * {@link #RESOURCE_VARIABLE RESOURCE_VARIABLE}, + * {@link #EXCEPTION_PARAMETER EXCEPTION_PARAMETER}, + * {@link #INSTANCEOF INSTANCEOF}, {@link #NEW NEW}, + * {@link #CONSTRUCTOR_REFERENCE CONSTRUCTOR_REFERENCE}, + * {@link #METHOD_REFERENCE METHOD_REFERENCE}, {@link #CAST CAST}, + * {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT + * CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, + * {@link #METHOD_INVOCATION_TYPE_ARGUMENT + * METHOD_INVOCATION_TYPE_ARGUMENT}, + * {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT + * CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or + * {@link #METHOD_REFERENCE_TYPE_ARGUMENT + * METHOD_REFERENCE_TYPE_ARGUMENT}. + */ + public int getSort() { + return value >>> 24; + } + + /** + * Returns the index of the type parameter referenced by this type + * reference. This method must only be used for type references whose sort + * is {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER}, + * {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER}, + * {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND} or + * {@link #METHOD_TYPE_PARAMETER_BOUND METHOD_TYPE_PARAMETER_BOUND}. + * + * @return a type parameter index. + */ + public int getTypeParameterIndex() { + return (value & 0x00FF0000) >> 16; + } + + /** + * Returns the index of the type parameter bound, within the type parameter + * {@link #getTypeParameterIndex}, referenced by this type reference. This + * method must only be used for type references whose sort is + * {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND} or + * {@link #METHOD_TYPE_PARAMETER_BOUND METHOD_TYPE_PARAMETER_BOUND}. + * + * @return a type parameter bound index. + */ + public int getTypeParameterBoundIndex() { + return (value & 0x0000FF00) >> 8; + } + + /** + * Returns the index of the "super type" of a class that is referenced by + * this type reference. This method must only be used for type references + * whose sort is {@link #CLASS_EXTENDS CLASS_EXTENDS}. + * + * @return the index of an interface in the 'implements' clause of a class, + * or -1 if this type reference references the type of the super + * class. + */ + public int getSuperTypeIndex() { + return (short) ((value & 0x00FFFF00) >> 8); + } + + /** + * Returns the index of the formal parameter whose type is referenced by + * this type reference. This method must only be used for type references + * whose sort is {@link #METHOD_FORMAL_PARAMETER METHOD_FORMAL_PARAMETER}. + * + * @return a formal parameter index. + */ + public int getFormalParameterIndex() { + return (value & 0x00FF0000) >> 16; + } + + /** + * Returns the index of the exception, in a 'throws' clause of a method, + * whose type is referenced by this type reference. This method must only be + * used for type references whose sort is {@link #THROWS THROWS}. + * + * @return the index of an exception in the 'throws' clause of a method. + */ + public int getExceptionIndex() { + return (value & 0x00FFFF00) >> 8; + } + + /** + * Returns the index of the try catch block (using the order in which they + * are visited with visitTryCatchBlock), whose 'catch' type is referenced by + * this type reference. This method must only be used for type references + * whose sort is {@link #EXCEPTION_PARAMETER EXCEPTION_PARAMETER} . + * + * @return the index of an exception in the 'throws' clause of a method. + */ + public int getTryCatchBlockIndex() { + return (value & 0x00FFFF00) >> 8; + } + + /** + * Returns the index of the type argument referenced by this type reference. + * This method must only be used for type references whose sort is + * {@link #CAST CAST}, {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT + * CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, + * {@link #METHOD_INVOCATION_TYPE_ARGUMENT METHOD_INVOCATION_TYPE_ARGUMENT}, + * {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT + * CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or + * {@link #METHOD_REFERENCE_TYPE_ARGUMENT METHOD_REFERENCE_TYPE_ARGUMENT}. + * + * @return a type parameter index. + */ + public int getTypeArgumentIndex() { + return value & 0xFF; + } + + /** + * Returns the int encoded value of this type reference, suitable for use in + * visit methods related to type annotations, like visitTypeAnnotation. + * + * @return the int encoded value of this type reference. + */ + public int getValue() { + return value; + } +} diff --git a/test/org/redkale/test/asm/AsmCreator.java b/test/org/redkale/test/asm/AsmCreator.java index 3a507c62c..c7bcad7b9 100644 --- a/test/org/redkale/test/asm/AsmCreator.java +++ b/test/org/redkale/test/asm/AsmCreator.java @@ -16,8 +16,8 @@ public class AsmCreator { public static void main(String[] args) throws Throwable { boolean realasm = false; //从http://forge.ow2.org/projects/asm/ 下载最新asm的src放在 srcasmroot 目录下 - File srcasmroot = new File("D:/JAVA/JDK源码/JDK9源码/java.base/jdk/internal/org/objectweb/asm"); - if(realasm) srcasmroot = new File("D:/JAVA/JDK源码/org/objectweb/asm"); + File srcasmroot = new File("D:/JAVA/JDK源码/jdk/internal/org/objectweb/asm"); + if (realasm) srcasmroot = new File("D:/JAVA/JDK源码/org/objectweb/asm"); File destasmroot = new File("D:/Java-Projects/RedkaleProject/src/org/redkale/asm"); String line = null; LineNumberReader txtin = new LineNumberReader(new FileReader(new File(destasmroot, "asm.txt"))); @@ -32,5 +32,6 @@ public class AsmCreator { out.write(content.replace("jdk.internal.org.objectweb", "org.redkale").replace("org.objectweb", "org.redkale").getBytes()); out.close(); } + //需要屏蔽ClassReader中判断checks the class version的部分 } }