TAP5-2588: upgrade ASM to 6.0
Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/74324b31 Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/74324b31 Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/74324b31 Branch: refs/heads/master Commit: 74324b3130c9f74c1684a08171b7a2ca56532fe1 Parents: 95a548e Author: Jochen Kemnade <jkemn...@apache.org> Authored: Fri Oct 6 15:20:03 2017 +0200 Committer: Jochen Kemnade <jkemn...@apache.org> Committed: Fri Oct 6 15:59:01 2017 +0200 ---------------------------------------------------------------------- .../internal/plastic/asm/AnnotationVisitor.java | 10 +- .../internal/plastic/asm/AnnotationWriter.java | 2 +- .../internal/plastic/asm/ClassReader.java | 480 ++++++++--- .../internal/plastic/asm/ClassVisitor.java | 32 +- .../internal/plastic/asm/ClassWriter.java | 295 ++++--- .../internal/plastic/asm/CurrentFrame.java | 56 ++ .../internal/plastic/asm/FieldVisitor.java | 8 +- .../internal/plastic/asm/FieldWriter.java | 40 +- .../tapestry5/internal/plastic/asm/Frame.java | 118 ++- .../tapestry5/internal/plastic/asm/Handle.java | 62 +- .../tapestry5/internal/plastic/asm/Item.java | 5 + .../tapestry5/internal/plastic/asm/Label.java | 15 +- .../internal/plastic/asm/MethodVisitor.java | 8 +- .../internal/plastic/asm/MethodWriter.java | 830 ++++-------------- .../internal/plastic/asm/ModuleVisitor.java | 190 +++++ .../internal/plastic/asm/ModuleWriter.java | 293 +++++++ .../tapestry5/internal/plastic/asm/Opcodes.java | 29 +- .../tapestry5/internal/plastic/asm/Type.java | 25 +- .../plastic/asm/commons/AdviceAdapter.java | 16 +- .../plastic/asm/commons/AnalyzerAdapter.java | 8 +- .../plastic/asm/commons/AnnotationRemapper.java | 79 ++ .../plastic/asm/commons/ClassRemapper.java | 158 ++++ .../plastic/asm/commons/CodeSizeEvaluator.java | 2 +- .../plastic/asm/commons/FieldRemapper.java | 71 ++ .../plastic/asm/commons/GeneratorAdapter.java | 6 +- .../plastic/asm/commons/InstructionAdapter.java | 4 +- .../plastic/asm/commons/JSRInlinerAdapter.java | 6 +- .../asm/commons/LocalVariablesSorter.java | 20 +- .../plastic/asm/commons/MethodRemapper.java | 225 +++++ .../asm/commons/ModuleHashesAttribute.java | 126 +++ .../plastic/asm/commons/ModuleRemapper.java | 106 +++ .../asm/commons/ModuleResolutionAttribute.java | 106 +++ .../asm/commons/ModuleTargetAttribute.java | 81 ++ .../internal/plastic/asm/commons/Remapper.java | 45 +- .../asm/commons/RemappingAnnotationAdapter.java | 4 +- .../asm/commons/RemappingClassAdapter.java | 10 +- .../asm/commons/RemappingFieldAdapter.java | 4 +- .../asm/commons/RemappingMethodAdapter.java | 28 +- .../asm/commons/RemappingSignatureAdapter.java | 4 +- .../asm/commons/SerialVersionUIDAdder.java | 11 +- .../plastic/asm/commons/SignatureRemapper.java | 159 ++++ .../plastic/asm/commons/StaticInitMerger.java | 2 +- .../asm/commons/TryCatchBlockSorter.java | 2 +- .../optimizer/AnnotationConstantsCollector.java | 147 ---- .../asm/optimizer/ClassConstantsCollector.java | 198 ----- .../plastic/asm/optimizer/ClassOptimizer.java | 260 ------ .../plastic/asm/optimizer/Constant.java | 323 ------- .../plastic/asm/optimizer/ConstantPool.java | 251 ------ .../asm/optimizer/FieldConstantsCollector.java | 89 -- .../plastic/asm/optimizer/JarOptimizer.java | 235 ----- .../asm/optimizer/MethodConstantsCollector.java | 224 ----- .../plastic/asm/optimizer/MethodOptimizer.java | 178 ---- .../plastic/asm/optimizer/NameMapping.java | 114 --- .../plastic/asm/optimizer/Shrinker.java | 282 ------ .../plastic/asm/optimizer/jdk1.2.2_017.txt.gz | Bin 113814 -> 0 bytes .../plastic/asm/optimizer/jdk1.3.1_19.txt.gz | Bin 128067 -> 0 bytes .../asm/optimizer/shrink-annotations.properties | 53 -- .../asm/optimizer/shrink-frames.properties | 62 -- .../asm/optimizer/shrink-resize.properties | 37 - .../asm/optimizer/shrink-signatures.properties | 43 - .../asm/optimizer/shrink-writer.properties | 66 -- .../plastic/asm/optimizer/shrink.properties | 381 --------- .../plastic/asm/signature/SignatureReader.java | 8 +- .../plastic/asm/signature/SignatureVisitor.java | 6 +- .../plastic/asm/signature/SignatureWriter.java | 6 +- .../plastic/asm/tree/AbstractInsnNode.java | 4 +- .../plastic/asm/tree/AnnotationNode.java | 82 +- .../internal/plastic/asm/tree/ClassNode.java | 92 +- .../plastic/asm/tree/FieldInsnNode.java | 8 +- .../internal/plastic/asm/tree/FieldNode.java | 28 +- .../plastic/asm/tree/InnerClassNode.java | 8 +- .../internal/plastic/asm/tree/InsnList.java | 23 +- .../plastic/asm/tree/InvokeDynamicInsnNode.java | 2 +- .../internal/plastic/asm/tree/LdcInsnNode.java | 2 +- .../asm/tree/LocalVariableAnnotationNode.java | 6 +- .../plastic/asm/tree/MethodInsnNode.java | 12 +- .../internal/plastic/asm/tree/MethodNode.java | 44 +- .../plastic/asm/tree/ModuleExportNode.java | 82 ++ .../internal/plastic/asm/tree/ModuleNode.java | 251 ++++++ .../plastic/asm/tree/ModuleOpenNode.java | 82 ++ .../plastic/asm/tree/ModuleProvideNode.java | 74 ++ .../plastic/asm/tree/ModuleRequireNode.java | 87 ++ .../asm/tree/MultiANewArrayInsnNode.java | 4 +- .../plastic/asm/tree/ParameterNode.java | 4 +- .../plastic/asm/tree/TryCatchBlockNode.java | 4 +- .../plastic/asm/tree/TypeAnnotationNode.java | 4 +- .../internal/plastic/asm/tree/TypeInsnNode.java | 4 +- .../asm/tree/analysis/BasicInterpreter.java | 2 +- .../asm/tree/analysis/BasicVerifier.java | 2 +- .../asm/tree/analysis/SimpleVerifier.java | 2 +- .../asm/tree/analysis/SourceInterpreter.java | 2 +- .../internal/plastic/asm/util/ASMifiable.java | 2 +- .../internal/plastic/asm/util/ASMifier.java | 226 ++++- .../asm/util/CheckAnnotationAdapter.java | 2 +- .../plastic/asm/util/CheckClassAdapter.java | 72 +- .../plastic/asm/util/CheckFieldAdapter.java | 4 +- .../plastic/asm/util/CheckMethodAdapter.java | 14 +- .../plastic/asm/util/CheckModuleAdapter.java | 151 ++++ .../plastic/asm/util/CheckSignatureAdapter.java | 38 +- .../internal/plastic/asm/util/Printer.java | 855 +++++++++++++++++-- .../internal/plastic/asm/util/Textifiable.java | 2 +- .../internal/plastic/asm/util/Textifier.java | 164 +++- .../asm/util/TraceAnnotationVisitor.java | 2 +- .../plastic/asm/util/TraceClassVisitor.java | 27 +- .../plastic/asm/util/TraceFieldVisitor.java | 2 +- .../plastic/asm/util/TraceMethodVisitor.java | 2 +- .../plastic/asm/util/TraceModuleVisitor.java | 101 +++ .../plastic/asm/util/TraceSignatureVisitor.java | 18 +- .../plastic/asm/xml/ASMContentHandler.java | 125 ++- .../internal/plastic/asm/xml/Processor.java | 52 +- .../plastic/asm/xml/SAXAnnotationAdapter.java | 20 +- .../plastic/asm/xml/SAXClassAdapter.java | 74 +- .../plastic/asm/xml/SAXCodeAdapter.java | 8 +- .../plastic/asm/xml/SAXFieldAdapter.java | 2 +- .../plastic/asm/xml/SAXModuleAdapter.java | 137 +++ .../internal/plastic/asm/xml/asm-xml.dtd | 16 +- .../plastic/AbstractAnnotationBuilder.java | 14 +- 117 files changed, 5418 insertions(+), 4371 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/74324b31/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/AnnotationVisitor.java ---------------------------------------------------------------------- diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/AnnotationVisitor.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/AnnotationVisitor.java index 1102d54..a3df31b 100644 --- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/AnnotationVisitor.java +++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/AnnotationVisitor.java @@ -41,7 +41,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; @@ -56,7 +56,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); @@ -67,13 +67,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; @@ -89,7 +89,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 http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/74324b31/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/AnnotationWriter.java ---------------------------------------------------------------------- diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/AnnotationWriter.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/AnnotationWriter.java index 679aa66..d0d2d4a 100644 --- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/AnnotationWriter.java +++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/AnnotationWriter.java @@ -104,7 +104,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; http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/74324b31/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/ClassReader.java ---------------------------------------------------------------------- diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/ClassReader.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/ClassReader.java index c334984..6d810e0 100644 --- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/ClassReader.java +++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/ClassReader.java @@ -44,31 +44,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>CODE</code> * attribute won't be visited. This can be used, for example, to retrieve * annotations for methods and method parameters. @@ -105,6 +80,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 <i>not</i> converted into GOTO and JSR, to make sure that + * infinite loops where a GOTO_W is replaced with a GOTO in ClassReader and + * converted back to a GOTO_W in ClassWriter cannot occur. + */ + static final int EXPAND_ASM_INSNS = 256; + + /** * The class to be parsed. <i>The content of this array must not be * modified. This field is intended for {@link Attribute} sub classes, and * is normally not needed by class generators or adapters.</i> @@ -166,7 +156,7 @@ 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_8) { + if (readShort(off + 6) > Opcodes.V9) { throw new IllegalArgumentException(); } // parses the constant pool @@ -205,6 +195,8 @@ public class ClassReader { // case ClassWriter.CLASS: // case ClassWriter.STR: // case ClassWriter.MTYPE + // case ClassWriter.PACKAGE: + // case ClassWriter.MODULE: default: size = 3; break; @@ -348,7 +340,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; @@ -555,11 +549,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(); @@ -578,13 +575,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; @@ -594,12 +589,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++) { @@ -628,6 +627,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, @@ -635,19 +640,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, @@ -655,7 +660,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, @@ -698,6 +703,120 @@ public class ClassReader { } /** + * Reads the module attribute and visit it. + * + * @param classVisitor + * the current class visitor + * @param context + * information about the class being parsed. + * @param u + * start offset of the module attribute in the class file. + * @param mainClass + * name of the main class of a module or null. + * @param packages + * start offset of the concealed package attribute. + */ + private void readModule(final ClassVisitor classVisitor, + final Context context, int u, + final String mainClass, int packages) { + + char[] buffer = context.buffer; + + // reads module name, flags and version + String name = readModule(u, buffer); + int flags = readUnsignedShort(u + 2); + String version = readUTF8(u + 4, buffer); + u += 6; + + ModuleVisitor mv = classVisitor.visitModule(name, flags, version); + if (mv == null) { + return; + } + + // module attributes (main class, packages) + if (mainClass != null) { + mv.visitMainClass(mainClass); + } + + if (packages != 0) { + for (int i = readUnsignedShort(packages - 2); i > 0; --i) { + String packaze = readPackage(packages, buffer); + mv.visitPackage(packaze); + packages += 2; + } + } + + // reads requires + u += 2; + for (int i = readUnsignedShort(u - 2); i > 0; --i) { + String module = readModule(u, buffer); + int access = readUnsignedShort(u + 2); + String requireVersion = readUTF8(u + 4, buffer); + mv.visitRequire(module, access, requireVersion); + u += 6; + } + + // reads exports + u += 2; + for (int i = readUnsignedShort(u - 2); i > 0; --i) { + String export = readPackage(u, buffer); + int access = readUnsignedShort(u + 2); + int exportToCount = readUnsignedShort(u + 4); + u += 6; + String[] tos = null; + if (exportToCount != 0) { + tos = new String[exportToCount]; + for (int j = 0; j < tos.length; ++j) { + tos[j] = readModule(u, buffer); + u += 2; + } + } + mv.visitExport(export, access, tos); + } + + // reads opens + u += 2; + for (int i = readUnsignedShort(u - 2); i > 0; --i) { + String open = readPackage(u, buffer); + int access = readUnsignedShort(u + 2); + int openToCount = readUnsignedShort(u + 4); + u += 6; + String[] tos = null; + if (openToCount != 0) { + tos = new String[openToCount]; + for (int j = 0; j < tos.length; ++j) { + tos[j] = readModule(u, buffer); + u += 2; + } + } + mv.visitOpen(open, access, tos); + } + + // read uses + u += 2; + for (int i = readUnsignedShort(u - 2); i > 0; --i) { + mv.visitUse(readClass(u, buffer)); + u += 2; + } + + // read provides + u += 2; + for (int i = readUnsignedShort(u - 2); i > 0; --i) { + String service = readClass(u, buffer); + int provideWithCount = readUnsignedShort(u + 2); + u += 4; + String[] withs = new String[provideWithCount]; + for (int j = 0; j < withs.length; ++j) { + withs[j] = readClass(u, buffer); + u += 2; + } + mv.visitProvide(service, withs); + } + + mv.visitEnd(); + } + + /** * Reads a field and makes the given visitor visit it. * * @param classVisitor @@ -733,24 +852,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, @@ -772,19 +887,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, @@ -792,7 +907,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, @@ -866,32 +981,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; @@ -924,7 +1033,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; @@ -961,26 +1070,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, @@ -988,7 +1097,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, @@ -996,10 +1105,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); } @@ -1046,7 +1155,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; @@ -1056,11 +1165,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: @@ -1075,9 +1189,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; @@ -1086,9 +1200,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; @@ -1118,9 +1232,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; @@ -1151,13 +1265,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; } } @@ -1167,9 +1277,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) { @@ -1181,17 +1289,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); @@ -1215,7 +1321,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; @@ -1244,7 +1350,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 @@ -1277,14 +1383,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; @@ -1305,7 +1428,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. @@ -1317,6 +1440,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); @@ -1325,6 +1451,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; @@ -1349,9 +1482,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 + // <l> with IFNOTxxx <L> GOTO_W <l> L:..., where IFNOTxxx is + // the "opposite" opcode of IFxxx (i.e., IFNE for IFEQ) + // and where <L> designates the instruction just after + // the GOTO_W. + if (opcode == Opcodes.GOTO || opcode == Opcodes.JSR) { + mv.visitJumpInsn(opcode + 33, target); + } else { + opcode = opcode <= 166 ? ((opcode + 1) ^ 1) - 1 + : opcode ^ 1; + Label endif = createLabel(offset + 3, labels); + mv.visitJumpInsn(opcode, endif); + mv.visitJumpInsn(200, target); // GOTO_W + // endif designates the instruction just after GOTO_W, + // and is visited as part of the next instruction. Since + // it is a jump target, we need to insert a frame here. + insertFrame = true; + } + u += 3; + break; + } + case ClassWriter.ASM_LABELW_INSN: { + // replaces the pseudo GOTO_W instruction with a real one. + mv.visitJumpInsn(200, labels[offset + readInt(u + 1)]); + // The instruction just after is a jump target (because pseudo + // GOTO_W are used in patterns IFNOTxxx <L> GOTO_W <l> L:..., + // see MethodWriter), so we need to insert a frame here. + insertFrame = true; + u += 5; + break; + } case ClassWriter.WIDE_INSN: opcode = b[u + 1] & 0xFF; if (opcode == Opcodes.IINC) { @@ -1607,8 +1778,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; @@ -1687,8 +1858,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; } @@ -2108,7 +2279,7 @@ public class ClassReader { } } frame.offset += delta + 1; - readLabel(frame.offset, labels); + createLabel(frame.offset, labels); return stackMap; } @@ -2161,7 +2332,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; @@ -2188,6 +2359,39 @@ public class ClassReader { } /** + * Creates a label without the Label.DEBUG flag set, for the given offset. + * The label is created with a call to {@link #readLabel} and its + * Label.DEBUG flag is cleared. + * + * @param offset + * a bytecode offset in a method. + * @param labels + * the already created labels, indexed by their offset. + * @return a Label without the Label.DEBUG flag set. + */ + private Label createLabel(int offset, Label[] labels) { + Label label = readLabel(offset, labels); + label.status &= ~Label.DEBUG; + return label; + } + + /** + * Creates a label with the Label.DEBUG flag set, if there is no already + * existing label for the given offset (otherwise does nothing). The label + * is created with a call to {@link #readLabel}. + * + * @param offset + * a bytecode offset in a method. + * @param labels + * the already created labels, indexed by their offset. + */ + private void createDebugLabel(int offset, Label[] labels) { + if (labels[offset] == null) { + readLabel(offset, labels).status |= Label.DEBUG; + } + } + + /** * Returns the start index of the attribute_info structure of this class. * * @return the start index of the attribute_info structure of this class. @@ -2442,6 +2646,20 @@ public class ClassReader { } /** + * Read a stringish constant item (CONSTANT_Class, CONSTANT_String, + * CONSTANT_MethodType, CONSTANT_Module or CONSTANT_Package + * @param index + * @param buf + * @return + */ + private String readStringish(final int index, final char[] buf) { + // computes the start index of the item in b + // and reads the CONSTANT_Utf8 item designated by + // the first two bytes of this item + return readUTF8(items[readUnsignedShort(index)], buf); + } + + /** * Reads a class constant pool item in {@link #b b}. <i>This method is * intended for {@link Attribute} sub classes, and is normally not needed by * class generators or adapters.</i> @@ -2455,10 +2673,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 module constant pool item in {@link #b b}. <i>This method is + * intended for {@link Attribute} sub classes, and is normally not needed by + * class generators or adapters.</i> + * + * @param index + * the start index of an unsigned short value in {@link #b b}, + * whose value is the index of a module constant pool item. + * @param buf + * buffer to be used to read the item. This buffer must be + * sufficiently large. It is not automatically resized. + * @return the String corresponding to the specified module item. + */ + public String readModule(final int index, final char[] buf) { + return readStringish(index, buf); + } + + /** + * Reads a module constant pool item in {@link #b b}. <i>This method is + * intended for {@link Attribute} sub classes, and is normally not needed by + * class generators or adapters.</i> + * + * @param index + * the start index of an unsigned short value in {@link #b b}, + * whose value is the index of a module constant pool item. + * @param buf + * buffer to be used to read the item. This buffer must be + * sufficiently large. It is not automatically resized. + * @return the String corresponding to the specified module item. + */ + public String readPackage(final int index, final char[] buf) { + return readStringish(index, buf); } /** @@ -2496,11 +2745,12 @@ public class ClassReader { int tag = readByte(index); int[] items = this.items; int cpIndex = items[readUnsignedShort(index + 1)]; + boolean itf = b[cpIndex - 1] == ClassWriter.IMETH; String owner = readClass(cpIndex, buf); cpIndex = items[readUnsignedShort(cpIndex + 2)]; String name = readUTF8(cpIndex, buf); String desc = readUTF8(cpIndex + 2, buf); - return new Handle(tag, owner, name, desc); + return new Handle(tag, owner, name, desc, itf); } } } http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/74324b31/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/ClassVisitor.java ---------------------------------------------------------------------- diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/ClassVisitor.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/ClassVisitor.java index 8c8e29b..b5751d4 100644 --- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/ClassVisitor.java +++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/ClassVisitor.java @@ -32,7 +32,7 @@ package org.apache.tapestry5.internal.plastic.asm; /** * A visitor to visit a Java class. The methods of this class must be called in * the following order: <tt>visit</tt> [ <tt>visitSource</tt> ] [ - * <tt>visitOuterClass</tt> ] ( <tt>visitAnnotation</tt> | + * <tt>visitModule</tt> ][ <tt>visitOuterClass</tt> ] ( <tt>visitAnnotation</tt> | * <tt>visitTypeAnnotation</tt> | <tt>visitAttribute</tt> )* ( * <tt>visitInnerClass</tt> | <tt>visitField</tt> | <tt>visitMethod</tt> )* * <tt>visitEnd</tt>. @@ -43,7 +43,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; @@ -58,7 +58,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); @@ -69,13 +69,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; @@ -130,6 +130,28 @@ public abstract class ClassVisitor { cv.visitSource(source, debug); } } + + /** + * 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 <tt>null</tt> 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 http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/74324b31/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/ClassWriter.java ---------------------------------------------------------------------- diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/ClassWriter.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/ClassWriter.java index da87f36..fa40875 100644 --- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/ClassWriter.java +++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/ClassWriter.java @@ -58,8 +58,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) */ @@ -168,6 +168,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. */ static final byte[] TYPE; @@ -243,9 +264,19 @@ public class ClassWriter extends ClassVisitor { static final int INDY = 18; /** + * The type of CONSTANT_Module constant pool items. + */ + static final int MODULE = 19; + + /** + * The type of CONSTANT_Package constant pool items. + */ + static final int PACKAGE = 20; + + /** * 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; @@ -395,6 +426,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. */ @@ -484,25 +520,19 @@ public class ClassWriter extends ClassVisitor { MethodWriter lastMethod; /** - * <tt>true</tt> if the maximum stack size and number of local variables - * must be automatically computed. - */ - private boolean computeMaxs; - - /** - * <tt>true</tt> if the stack map frames must be recomputed from scratch. + * Indicates what must be automatically computed. + * + * @see MethodWriter#compute */ - private boolean computeFrames; + private int compute; /** - * <tt>true</tt> 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). + * <tt>true</tt> 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. */ - boolean invalidFrames; + boolean hasAsmInsns; // ------------------------------------------------------------------------ // Static initializer @@ -513,11 +543,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'); } @@ -571,8 +601,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; @@ -605,7 +636,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]; @@ -614,8 +645,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); } /** @@ -645,9 +677,9 @@ public class ClassWriter extends ClassVisitor { * @param flags * option flags that can be used to modify the default behavior * of this class. <i>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</i>. 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</i>. See {@link #COMPUTE_MAXS}, * {@link #COMPUTE_FRAMES}. */ public ClassWriter(final ClassReader classReader, final int flags) { @@ -668,7 +700,7 @@ public class ClassWriter extends ClassVisitor { this.access = access; 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); @@ -693,6 +725,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) { enclosingMethodOwner = newClass(owner); @@ -704,9 +744,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); @@ -724,9 +761,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); @@ -766,7 +800,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); @@ -791,7 +825,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 @@ -835,7 +869,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"); @@ -873,26 +907,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); @@ -929,7 +968,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) { @@ -940,6 +979,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); @@ -958,41 +1002,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; @@ -1039,20 +1088,20 @@ 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; - return newHandleItem(h.tag, h.owner, h.name, h.desc); + return newHandleItem(h.tag, h.owner, h.name, h.desc, h.itf); } else { throw new IllegalArgumentException("value " + cst); } @@ -1097,20 +1146,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. - * <i>This method is intended for {@link Attribute} sub classes, and is - * normally not needed by class generators or adapters.</i> * + * @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); } @@ -1128,7 +1178,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; + return newStringishItem(CLASS, value).index; } /** @@ -1139,32 +1189,41 @@ public class ClassWriter extends ClassVisitor { * * @param methodDesc * method descriptor of the method type. - * @return a new or already existing method type reference item. + * @return the index of 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; + public int newMethodType(final String methodDesc) { + return newStringishItem(MTYPE, methodDesc).index; } - + /** - * Adds a method type reference to the constant pool of the class being + * Adds a module reference to the constant pool of the class being * build. Does nothing if the constant pool already contains a similar item. * <i>This method is intended for {@link Attribute} sub classes, and is * normally not needed by class generators or adapters.</i> * - * @param methodDesc - * method descriptor of the method type. - * @return the index of a new or already existing method type reference + * @param moduleName + * name of the module. + * @return the index of a new or already existing module reference * item. */ - public int newMethodType(final String methodDesc) { - return newMethodTypeItem(methodDesc).index; + 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. + * <i>This method is intended for {@link Attribute} sub classes, and is + * normally not needed by class generators or adapters.</i> + * + * @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; } /** @@ -1187,10 +1246,12 @@ public class ClassWriter extends ClassVisitor { * the name of the field or method. * @param desc * the descriptor of the field or method. + * @param itf + * true if the owner is an interface. * @return a new or an already existing method type reference item. */ Item newHandleItem(final int tag, final String owner, final String name, - final String desc) { + final String desc, final boolean itf) { key4.set(HANDLE_BASE + tag, owner, name, desc); Item result = get(key4); if (result == null) { @@ -1199,8 +1260,7 @@ public class ClassWriter extends ClassVisitor { } else { put112(HANDLE, tag, - newMethod(owner, name, desc, - tag == Opcodes.H_INVOKEINTERFACE)); + newMethod(owner, name, desc, itf)); } result = new Item(index++, key4); put(result); @@ -1230,13 +1290,47 @@ public class ClassWriter extends ClassVisitor { * the descriptor of the field or method. * @return the index of a new or already existing method type reference * item. + * + * @deprecated this method is superseded by + * {@link #newHandle(int, String, String, String, boolean)}. */ + @Deprecated public int newHandle(final int tag, final String owner, final String name, final String desc) { - return newHandleItem(tag, owner, name, desc).index; + return newHandle(tag, owner, name, desc, tag == Opcodes.H_INVOKEINTERFACE); } /** + * Adds a handle to the constant pool of the class being build. Does nothing + * if the constant pool already contains a similar item. <i>This method is + * intended for {@link Attribute} sub classes, and is normally not needed by + * class generators or adapters.</i> + * + * @param tag + * the kind of this handle. Must be {@link Opcodes#H_GETFIELD}, + * {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, + * {@link Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL}, + * {@link Opcodes#H_INVOKESTATIC}, + * {@link Opcodes#H_INVOKESPECIAL}, + * {@link Opcodes#H_NEWINVOKESPECIAL} or + * {@link Opcodes#H_INVOKEINTERFACE}. + * @param owner + * the internal name of the field or method owner class. + * @param name + * the name of the field or method. + * @param desc + * the descriptor of the field or method. + * @param itf + * true if the owner is an interface. + * @return the index of a new or already existing method type reference + * item. + */ + public int newHandle(final int tag, final String owner, final String name, + final String desc, final boolean itf) { + return newHandleItem(tag, owner, name, desc, itf).index; + } + + /** * Adds an invokedynamic reference to the constant pool of the class being * build. Does nothing if the constant pool already contains a similar item. * <i>This method is intended for {@link Attribute} sub classes, and is @@ -1265,7 +1359,7 @@ public class ClassWriter extends ClassVisitor { int hashCode = bsm.hashCode(); bootstrapMethods.putShort(newHandle(bsm.tag, bsm.owner, bsm.name, - bsm.desc)); + bsm.desc, bsm.isInterface())); int argsLength = bsmArgs.length; bootstrapMethods.putShort(argsLength); @@ -1511,25 +1605,6 @@ public class ClassWriter extends ClassVisitor { } /** - * 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. <i>This * method is intended for {@link Attribute} sub classes, and is normally not http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/74324b31/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/CurrentFrame.java ---------------------------------------------------------------------- diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/CurrentFrame.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/CurrentFrame.java new file mode 100644 index 0000000..457a4eb --- /dev/null +++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/CurrentFrame.java @@ -0,0 +1,56 @@ +/*** + * 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.apache.tapestry5.internal.plastic.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; + } +} http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/74324b31/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/FieldVisitor.java ---------------------------------------------------------------------- diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/FieldVisitor.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/FieldVisitor.java index 107af8f..9dbca0b 100644 --- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/FieldVisitor.java +++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/FieldVisitor.java @@ -40,7 +40,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; @@ -55,7 +55,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); @@ -66,13 +66,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;