--- old/src/java.base/share/classes/java/lang/Module.java Fri Oct 27 09:23:25 2017 +++ new/src/java.base/share/classes/java/lang/Module.java Fri Oct 27 09:23:25 2017 @@ -57,8 +57,6 @@ import jdk.internal.loader.BuiltinClassLoader; import jdk.internal.loader.BootLoader; import jdk.internal.loader.ClassLoaders; -import jdk.internal.misc.JavaLangAccess; -import jdk.internal.misc.SharedSecrets; import jdk.internal.module.IllegalAccessLogger; import jdk.internal.module.ModuleLoaderMap; import jdk.internal.module.ServicesCatalog; @@ -68,6 +66,7 @@ import jdk.internal.org.objectweb.asm.ClassReader; import jdk.internal.org.objectweb.asm.ClassVisitor; import jdk.internal.org.objectweb.asm.ClassWriter; +import jdk.internal.org.objectweb.asm.ModuleVisitor; import jdk.internal.org.objectweb.asm.Opcodes; import jdk.internal.reflect.CallerSensitive; import jdk.internal.reflect.Reflection; @@ -1432,7 +1431,7 @@ ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES); - ClassVisitor cv = new ClassVisitor(Opcodes.ASM5, cw) { + ClassVisitor cv = new ClassVisitor(Opcodes.ASM6, cw) { @Override public void visit(int version, int access, @@ -1458,6 +1457,11 @@ public void visitAttribute(Attribute attr) { // drop non-annotation attributes } + @Override + public ModuleVisitor visitModule(String name, int flags, String version) { + // drop Module attribute + return null; + } }; ClassReader cr = new ClassReader(in); --- old/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java Fri Oct 27 09:23:27 2017 +++ new/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java Fri Oct 27 09:23:27 2017 @@ -31,9 +31,7 @@ import java.lang.module.ModuleDescriptor.Version; import java.util.ArrayList; import java.util.Collections; -import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.Set; import jdk.internal.org.objectweb.asm.Attribute; @@ -40,10 +38,12 @@ import jdk.internal.org.objectweb.asm.ClassReader; import jdk.internal.org.objectweb.asm.ClassVisitor; import jdk.internal.org.objectweb.asm.ClassWriter; +import jdk.internal.org.objectweb.asm.ModuleVisitor; import jdk.internal.org.objectweb.asm.Opcodes; +import jdk.internal.org.objectweb.asm.commons.ModuleHashesAttribute; +import jdk.internal.org.objectweb.asm.commons.ModuleResolutionAttribute; +import jdk.internal.org.objectweb.asm.commons.ModuleTargetAttribute; -import static jdk.internal.module.ClassFileAttributes.*; - /** * Utility class to extend a module-info.class with additional attributes. */ @@ -133,43 +133,6 @@ } /** - * A ClassVisitor that supports adding class file attributes. If an - * attribute already exists then the first occurrence of the attribute - * is replaced. - */ - private static class AttributeAddingClassVisitor extends ClassVisitor { - private Map attrs = new HashMap<>(); - - AttributeAddingClassVisitor(int api, ClassVisitor cv) { - super(api, cv); - } - - void addAttribute(Attribute attr) { - attrs.put(attr.type, attr); - } - - @Override - public void visitAttribute(Attribute attr) { - String name = attr.type; - Attribute replacement = attrs.get(name); - if (replacement != null) { - attr = replacement; - attrs.remove(name); - } - super.visitAttribute(attr); - } - - /** - * Adds any remaining attributes that weren't replaced to the - * class file. - */ - void finish() { - attrs.values().forEach(a -> super.visitAttribute(a)); - attrs.clear(); - } - } - - /** * Outputs the modified module-info.class to the given output stream. * Once this method has been called then the Extender object should * be discarded. @@ -185,38 +148,86 @@ * be discarded. */ public byte[] toByteArray() throws IOException { - ClassWriter cw - = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES); + ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + + ClassWriter.COMPUTE_FRAMES); - AttributeAddingClassVisitor cv - = new AttributeAddingClassVisitor(Opcodes.ASM5, cw); - ClassReader cr = new ClassReader(in); - if (packages != null) - cv.addAttribute(new ModulePackagesAttribute(packages)); - if (mainClass != null) - cv.addAttribute(new ModuleMainClassAttribute(mainClass)); - if (targetPlatform != null) - cv.addAttribute(new ModuleTargetAttribute(targetPlatform)); - if (hashes != null) - cv.addAttribute(new ModuleHashesAttribute(hashes)); - if (moduleResolution != null) - cv.addAttribute(new ModuleResolutionAttribute(moduleResolution.value())); + ClassVisitor cv = new ClassVisitor(Opcodes.ASM6, cw) { + @Override + public ModuleVisitor visitModule(String name, int flags, String version) { + Version v = ModuleInfoExtender.this.version; + String vs = (v != null) ? v.toString() : version; + ModuleVisitor mv = super.visitModule(name, flags, vs); - List attrs = new ArrayList<>(); + // ModuleMainClass attribute + if (mainClass != null) { + mv.visitMainClass(mainClass.replace('.', '/')); + } - // prototypes of attributes that should be parsed - attrs.add(new ModuleAttribute(version)); - attrs.add(new ModulePackagesAttribute()); - attrs.add(new ModuleMainClassAttribute()); + // ModulePackages attribute + if (packages != null) { + packages.forEach(pn -> mv.visitPackage(pn.replace('.', '/'))); + } + + return new ModuleVisitor(Opcodes.ASM6, mv) { + public void visitMainClass(String existingMainClass) { + // skip main class if there is a new value + if (mainClass == null) { + super.visitMainClass(existingMainClass); + } + } + public void visitPackage(String existingPackage) { + // skip packages if there is a new set of packages + if (packages == null) { + super.visitPackage(existingPackage); + } + } + }; + } + @Override + public void visitAttribute(Attribute attr) { + String name = attr.type; + // drop existing attributes if there are replacements + if (name.equals(ClassFileConstants.MODULE_TARGET) + && targetPlatform != null) + return; + if (name.equals(ClassFileConstants.MODULE_RESOLUTION) + && moduleResolution != null) + return; + if (name.equals(ClassFileConstants.MODULE_HASHES) + && hashes != null) + return; + + super.visitAttribute(attr); + + } + }; + + List attrs = new ArrayList<>(); attrs.add(new ModuleTargetAttribute()); + attrs.add(new ModuleResolutionAttribute()); attrs.add(new ModuleHashesAttribute()); - cr.accept(cv, attrs.toArray(new Attribute[0]), 0); - // add any attributes that didn't replace previous attributes - cv.finish(); + // add ModuleTarget, ModuleResolution and ModuleHashes attributes + if (targetPlatform != null) { + cw.visitAttribute(new ModuleTargetAttribute(targetPlatform)); + } + if (moduleResolution != null) { + int flags = moduleResolution.value(); + cw.visitAttribute(new ModuleResolutionAttribute(flags)); + } + if (hashes != null) { + String algorithm = hashes.algorithm(); + List names = new ArrayList<>(); + List values = new ArrayList<>(); + for (String name : hashes.names()) { + names.add(name); + values.add(hashes.hashFor(name)); + } + cw.visitAttribute(new ModuleHashesAttribute(algorithm, names, values)); + } return cw.toByteArray(); } --- old/src/java.base/share/classes/jdk/internal/module/ModuleInfoWriter.java Fri Oct 27 09:23:29 2017 +++ new/src/java.base/share/classes/jdk/internal/module/ModuleInfoWriter.java Fri Oct 27 09:23:28 2017 @@ -28,14 +28,15 @@ import java.io.OutputStream; import java.lang.module.ModuleDescriptor; import java.nio.ByteBuffer; +import java.util.Map; import java.util.stream.Stream; import jdk.internal.org.objectweb.asm.ClassWriter; +import jdk.internal.org.objectweb.asm.ModuleVisitor; import jdk.internal.org.objectweb.asm.Opcodes; +import jdk.internal.org.objectweb.asm.commons.ModuleTargetAttribute; +import static jdk.internal.org.objectweb.asm.Opcodes.*; -import static jdk.internal.module.ClassFileAttributes.*; -import static jdk.internal.module.ClassFileConstants.ACC_MODULE; - /** * Utility class to write a ModuleDescriptor as a module-info.class. */ @@ -42,6 +43,35 @@ public final class ModuleInfoWriter { + private static final Map + MODULE_MODS_TO_FLAGS = Map.of( + ModuleDescriptor.Modifier.OPEN, ACC_OPEN, + ModuleDescriptor.Modifier.SYNTHETIC, ACC_SYNTHETIC, + ModuleDescriptor.Modifier.MANDATED, ACC_MANDATED + ); + + private static final Map + REQUIRES_MODS_TO_FLAGS = Map.of( + ModuleDescriptor.Requires.Modifier.TRANSITIVE, ACC_TRANSITIVE, + ModuleDescriptor.Requires.Modifier.STATIC, ACC_STATIC_PHASE, + ModuleDescriptor.Requires.Modifier.SYNTHETIC, ACC_SYNTHETIC, + ModuleDescriptor.Requires.Modifier.MANDATED, ACC_MANDATED + ); + + private static final Map + EXPORTS_MODS_TO_FLAGS = Map.of( + ModuleDescriptor.Exports.Modifier.SYNTHETIC, ACC_SYNTHETIC, + ModuleDescriptor.Exports.Modifier.MANDATED, ACC_MANDATED + ); + + private static final Map + OPENS_MODS_TO_FLAGS = Map.of( + ModuleDescriptor.Opens.Modifier.SYNTHETIC, ACC_SYNTHETIC, + ModuleDescriptor.Opens.Modifier.MANDATED, ACC_MANDATED + ); + + private static final String[] EMPTY_STRING_ARRAY = new String[0]; + private ModuleInfoWriter() { } /** @@ -50,24 +80,75 @@ */ private static byte[] toModuleInfo(ModuleDescriptor md, ModuleTarget target) { ClassWriter cw = new ClassWriter(0); - cw.visit(Opcodes.V1_9, ACC_MODULE, "module-info", null, null, null); - cw.visitAttribute(new ModuleAttribute(md)); + cw.visit(Opcodes.V9, ACC_MODULE, "module-info", null, null, null); - // for tests: write the ModulePackages attribute when there are packages - // that aren't exported or open + int moduleFlags = md.modifiers().stream() + .map(MODULE_MODS_TO_FLAGS::get) + .reduce(0, (x, y) -> (x | y)); + String vs = md.rawVersion().orElse(null); + ModuleVisitor mv = cw.visitModule(md.name(), moduleFlags, vs); + + // requires + for (ModuleDescriptor.Requires r : md.requires()) { + int flags = r.modifiers().stream() + .map(REQUIRES_MODS_TO_FLAGS::get) + .reduce(0, (x, y) -> (x | y)); + vs = r.rawCompiledVersion().orElse(null); + mv.visitRequire(r.name(), flags, vs); + } + + // exports + for (ModuleDescriptor.Exports e : md.exports()) { + int flags = e.modifiers().stream() + .map(EXPORTS_MODS_TO_FLAGS::get) + .reduce(0, (x, y) -> (x | y)); + String[] targets = e.targets().toArray(EMPTY_STRING_ARRAY); + mv.visitExport(e.source().replace('.', '/'), flags, targets); + } + + // opens + for (ModuleDescriptor.Opens opens : md.opens()) { + int flags = opens.modifiers().stream() + .map(OPENS_MODS_TO_FLAGS::get) + .reduce(0, (x, y) -> (x | y)); + String[] targets = opens.targets().toArray(EMPTY_STRING_ARRAY); + mv.visitOpen(opens.source().replace('.', '/'), flags, targets); + } + + // uses + md.uses().stream().map(sn -> sn.replace('.', '/')).forEach(mv::visitUse); + + // provides + for (ModuleDescriptor.Provides p : md.provides()) { + mv.visitProvide(p.service().replace('.', '/'), + p.providers() + .stream() + .map(pn -> pn.replace('.', '/')) + .toArray(String[]::new)); + } + + // add the ModulePackages attribute when there are packages that aren't + // exported or open Stream exported = md.exports().stream() .map(ModuleDescriptor.Exports::source); Stream open = md.opens().stream() .map(ModuleDescriptor.Opens::source); long exportedOrOpen = Stream.concat(exported, open).distinct().count(); - if (md.packages().size() > exportedOrOpen) - cw.visitAttribute(new ModulePackagesAttribute(md.packages())); + if (md.packages().size() > exportedOrOpen) { + md.packages().stream() + .map(pn -> pn.replace('.', '/')) + .forEach(mv::visitPackage); + } - // write ModuleMainClass if the module has a main class - md.mainClass().ifPresent(mc -> cw.visitAttribute(new ModuleMainClassAttribute(mc))); + // ModuleMainClass attribute + md.mainClass() + .map(mc -> mc.replace('.', '/')) + .ifPresent(mv::visitMainClass); - // write ModuleTarget if there is a target platform - if (target != null) { + mv.visitEnd(); + + // write ModuleTarget attribute if there is a target platform + if (target != null && target.targetPlatform().length() > 0) { cw.visitAttribute(new ModuleTargetAttribute(target.targetPlatform())); } --- old/src/java.base/share/classes/jdk/internal/org/objectweb/asm/AnnotationVisitor.java Fri Oct 27 09:23:30 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/AnnotationVisitor.java Fri Oct 27 09:23:30 2017 @@ -70,7 +70,7 @@ /** * 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 @@ * * @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 @@ * * @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 @@ * 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 --- old/src/java.base/share/classes/jdk/internal/org/objectweb/asm/AnnotationWriter.java Fri Oct 27 09:23:32 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/AnnotationWriter.java Fri Oct 27 09:23:31 2017 @@ -133,7 +133,7 @@ */ 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; --- old/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassReader.java Fri Oct 27 09:23:34 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassReader.java Fri Oct 27 09:23:33 2017 @@ -73,31 +73,6 @@ 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 * annotations for methods and method parameters. @@ -134,6 +109,21 @@ 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 * is normally not needed by class generators or adapters. @@ -195,7 +185,7 @@ 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) { + if (readShort(off + 6) > Opcodes.V9) { throw new IllegalArgumentException(); } // parses the constant pool @@ -234,6 +224,8 @@ // case ClassWriter.CLASS: // case ClassWriter.STR: // case ClassWriter.MTYPE + // case ClassWriter.PACKAGE: + // case ClassWriter.MODULE: default: size = 3; break; @@ -377,7 +369,9 @@ 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 @@ 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 @@ 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 @@ } 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 @@ 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 @@ } // 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 @@ 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, @@ -727,6 +732,120 @@ } /** + * 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 @@ -762,7 +881,7 @@ 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; @@ -769,17 +888,13 @@ } 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 @@ } // 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 @@ 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 @@ 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 @@ * 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,7 +1099,7 @@ } // visits the method annotations - if (ANNOTATIONS && dann != 0) { + if (dann != 0) { AnnotationVisitor dv = mv.visitAnnotationDefault(); readAnnotationValue(dann, c, null, dv); if (dv != null) { @@ -997,19 +1106,19 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ // 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 @@ // 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 @@ // 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 @@ 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 @@ 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 @@ 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 @@ * 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 @@ 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 @@ 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 @@ } // 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ } } frame.offset += delta + 1; - readLabel(frame.offset, labels); + createLabel(frame.offset, labels); return stackMap; } @@ -2190,7 +2361,7 @@ v += 2; break; default: // Uninitialized - frame[index] = readLabel(readUnsignedShort(v), labels); + frame[index] = createLabel(readUnsignedShort(v), labels); v += 2; } return v; @@ -2217,6 +2388,39 @@ } /** + * 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. @@ -2471,6 +2675,20 @@ } /** + * 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 * class generators or adapters. @@ -2484,44 +2702,41 @@ * @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 @@ 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); --- old/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassVisitor.java Fri Oct 27 09:23:35 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassVisitor.java Fri Oct 27 09:23:35 2017 @@ -61,7 +61,7 @@ /** * 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 @@ /** * 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 @@ * * @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 @@ * * @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 @@ } } + /** + * 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. --- old/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassWriter.java Fri Oct 27 09:23:37 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassWriter.java Fri Oct 27 09:23:37 2017 @@ -87,8 +87,8 @@ * {@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) */ @@ -197,6 +197,27 @@ 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; @@ -284,7 +305,7 @@ /** * 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; @@ -434,6 +455,11 @@ 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,26 +549,20 @@ 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; + boolean hasAsmInsns; - /** - * 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; - // ------------------------------------------------------------------------ // Static initializer // ------------------------------------------------------------------------ @@ -552,11 +572,11 @@ */ 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 @@ // // 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 @@ * {@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 @@ 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 @@ * @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 @@ 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); @@ -732,6 +754,14 @@ } @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); @@ -743,9 +773,6 @@ @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 @@ @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 @@ // 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 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 @@ size += 8 + bootstrapMethods.length; newUTF8("BootstrapMethods"); } - if (ClassReader.SIGNATURES && signature != 0) { + if (signature != 0) { ++attributeCount; size += 8; newUTF8("Signature"); @@ -912,26 +936,31 @@ 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 @@ 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 @@ 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,19 +1031,19 @@ 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); } @@ -1016,22 +1050,27 @@ 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 @@ 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 @@ } /** - * 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,87 +1207,52 @@ * @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; } /** - * Adds a module name to the constant pool. - * - * Does nothing if the constant pool already contains a similar item. + * 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 value - * the module name - * @return the index of a new or already existing module reference item. + * @param methodDesc + * method descriptor of the method type. + * @return the index of a new or already existing method type 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; + public int newMethodType(final String methodDesc) { + return newStringishItem(MTYPE, methodDesc).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 + * 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 methodDesc - * method descriptor of the method type. - * @return a new or already existing method type reference item. + * @param moduleName + * name of the module. + * @return the index of a new or already existing module 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 newModule(final String moduleName) { + return newStringishItem(MODULE, moduleName).index; } /** - * Adds a method type reference to the constant pool of the class being + * 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 methodDesc - * method descriptor of the method type. - * @return the index of a new or already existing method type reference + * @param packageName + * name of the package in its internal form. + * @return the index of a new or already existing module reference * item. */ - public int newMethodType(final String methodDesc) { - return newMethodTypeItem(methodDesc).index; + public int newPackage(final String packageName) { + return newStringishItem(PACKAGE, packageName).index; } /** @@ -1625,25 +1630,6 @@ index += 2; put(result); } - 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; } --- old/src/java.base/share/classes/jdk/internal/org/objectweb/asm/FieldVisitor.java Fri Oct 27 09:23:39 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/FieldVisitor.java Fri Oct 27 09:23:38 2017 @@ -69,7 +69,7 @@ /** * 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 @@ * * @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 @@ * * @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; --- old/src/java.base/share/classes/jdk/internal/org/objectweb/asm/FieldWriter.java Fri Oct 27 09:23:40 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/FieldWriter.java Fri Oct 27 09:23:40 2017 @@ -147,7 +147,7 @@ */ 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 @@ 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 @@ @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 @@ @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 @@ 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 @@ 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 @@ 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); } --- old/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Frame.java Fri Oct 27 09:23:42 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Frame.java Fri Oct 27 09:23:41 2017 @@ -63,7 +63,7 @@ * * @author Eric Bruneton */ -final class Frame { +class Frame { /* * Frames are computed in a two steps process: during the visit of each @@ -525,7 +525,7 @@ * 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. @@ -550,6 +550,110 @@ 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. * * @param local @@ -614,7 +718,7 @@ } // 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 @@ * 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 @@ * @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 @@ 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 @@ * @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; --- old/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Item.java Fri Oct 27 09:23:43 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Item.java Fri Oct 27 09:23:43 2017 @@ -80,6 +80,7 @@ * {@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 @@ 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; --- old/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Label.java Fri Oct 27 09:23:45 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Label.java Fri Oct 27 09:23:45 2017 @@ -389,13 +389,12 @@ * 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. @@ -454,7 +453,7 @@ * @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; } // ------------------------------------------------------------------------ --- old/src/java.base/share/classes/jdk/internal/org/objectweb/asm/MethodVisitor.java Fri Oct 27 09:23:46 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/MethodVisitor.java Fri Oct 27 09:23:46 2017 @@ -86,7 +86,7 @@ /** * 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 @@ * * @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 @@ * * @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; --- old/src/java.base/share/classes/jdk/internal/org/objectweb/asm/MethodWriter.java Fri Oct 27 09:23:48 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/MethodWriter.java Fri Oct 27 09:23:48 2017 @@ -128,15 +128,27 @@ * * @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 * be automatically computed. * * @see #compute */ - private static final int MAXS = 1; + static final int MAXS = 2; /** * Indicates that nothing must be automatically computed. @@ -143,7 +155,7 @@ * * @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 @@ /** * Number of stack map frames in the StackMapTable attribute. */ - private int frameCount; + int frameCount; /** * The StackMapTable attribute. @@ -384,11 +396,6 @@ 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. */ private int subroutines; @@ -409,6 +416,7 @@ * Indicates what must be automatically computed. * * @see #FRAMES + * @see #INSERTED_FRAMES * @see #MAXS * @see #NOTHING */ @@ -471,18 +479,13 @@ * @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 @@ 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 @@ 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 @@ @Override public AnnotationVisitor visitAnnotationDefault() { - if (!ClassReader.ANNOTATIONS) { - return null; - } annd = new ByteVector(); return new AnnotationWriter(cw, false, annd, null, 0); } @@ -549,9 +547,6 @@ @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 @@ @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 @@ @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 @@ @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 @@ 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 @@ } 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 @@ // 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 @@ 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 @@ 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 @@ @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 @@ 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 @@ 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 @@ 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 @@ } @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 @@ // 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 @@ /* * 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 @@ 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 @@ @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 @@ 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 @@ 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 @@ 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 @@ @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 @@ @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 @@ @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 @@ 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 @@ @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 @@ // 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 @@ } else { currentBlock.outputStackMax = maxStackSize; } - currentBlock = null; + if (compute != INSERTED_FRAMES) { + currentBlock = null; + } } // ------------------------------------------------------------------------ @@ -1789,7 +1813,7 @@ 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 @@ 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 @@ ++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 @@ 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 @@ cw.newUTF8("Deprecated"); size += 6; } - if (ClassReader.SIGNATURES && signature != null) { + if (signature != null) { cw.newUTF8("Signature"); cw.newUTF8(signature); size += 8; @@ -2120,27 +2143,27 @@ 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) { @@ -2147,7 +2170,7 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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; - } - } } --- old/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Opcodes.java Fri Oct 27 09:23:50 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Opcodes.java Fri Oct 27 09:23:49 2017 @@ -70,7 +70,6 @@ * @author Eric Bruneton * @author Eugene Kuleshov */ -@SuppressWarnings("deprecation") // for Integer(int) constructor public interface Opcodes { // ASM API versions @@ -77,6 +76,7 @@ int ASM4 = 4 << 16 | 0 << 8 | 0; int ASM5 = 5 << 16 | 0 << 8 | 0; + int ASM6 = 6 << 16 | 0 << 8 | 0; // versions @@ -88,7 +88,7 @@ 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; // access flags @@ -99,8 +99,11 @@ 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 @@ -107,11 +110,13 @@ 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 int ACC_DEPRECATED = 0x20000; // class, field, method @@ -177,15 +182,17 @@ */ 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) --- old/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Type.java Fri Oct 27 09:23:52 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Type.java Fri Oct 27 09:23:51 2017 @@ -406,7 +406,16 @@ */ 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++] != ';') { + } + } + } } /** --- old/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/AdviceAdapter.java Fri Oct 27 09:23:53 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/AdviceAdapter.java Fri Oct 27 09:23:53 2017 @@ -112,7 +112,7 @@ * * @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 adapter delegates calls. * @param access --- old/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/AnalyzerAdapter.java Fri Oct 27 09:23:55 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/AnalyzerAdapter.java Fri Oct 27 09:23:54 2017 @@ -170,7 +170,7 @@ */ public AnalyzerAdapter(final String owner, final int access, final String name, final String desc, final MethodVisitor mv) { - this(Opcodes.ASM5, owner, access, name, desc, mv); + this(Opcodes.ASM6, owner, access, name, desc, mv); if (getClass() != AnalyzerAdapter.class) { throw new IllegalStateException(); } @@ -181,7 +181,7 @@ * * @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 owner * the owner's class name. * @param access @@ -690,6 +690,8 @@ t1 = pop(); if (t1 instanceof String) { pushDesc(((String) t1).substring(1)); + } else if (t1 == Opcodes.NULL) { + push(t1); } else { push("java/lang/Object"); } --- old/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/AnnotationRemapper.java Fri Oct 27 09:23:56 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/AnnotationRemapper.java Fri Oct 27 09:23:56 2017 @@ -73,7 +73,7 @@ public AnnotationRemapper(final AnnotationVisitor av, final Remapper remapper) { - this(Opcodes.ASM5, av, remapper); + this(Opcodes.ASM6, av, remapper); } protected AnnotationRemapper(final int api, final AnnotationVisitor av, --- old/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/ClassRemapper.java Fri Oct 27 09:23:58 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/ClassRemapper.java Fri Oct 27 09:23:57 2017 @@ -59,10 +59,14 @@ package jdk.internal.org.objectweb.asm.commons; +import java.util.List; + import jdk.internal.org.objectweb.asm.AnnotationVisitor; +import jdk.internal.org.objectweb.asm.Attribute; import jdk.internal.org.objectweb.asm.ClassVisitor; import jdk.internal.org.objectweb.asm.FieldVisitor; import jdk.internal.org.objectweb.asm.MethodVisitor; +import jdk.internal.org.objectweb.asm.ModuleVisitor; import jdk.internal.org.objectweb.asm.Opcodes; import jdk.internal.org.objectweb.asm.TypePath; @@ -78,7 +82,7 @@ protected String className; public ClassRemapper(final ClassVisitor cv, final Remapper remapper) { - this(Opcodes.ASM5, cv, remapper); + this(Opcodes.ASM6, cv, remapper); } protected ClassRemapper(final int api, final ClassVisitor cv, @@ -97,6 +101,12 @@ } @Override + public ModuleVisitor visitModule(String name, int flags, String version) { + ModuleVisitor mv = super.visitModule(remapper.mapModuleName(name), flags, version); + return mv == null ? null : createModuleRemapper(mv); + } + + @Override public AnnotationVisitor visitAnnotation(String desc, boolean visible) { AnnotationVisitor av = super.visitAnnotation(remapper.mapDesc(desc), visible); @@ -112,6 +122,18 @@ } @Override + public void visitAttribute(Attribute attr) { + if (attr instanceof ModuleHashesAttribute) { + ModuleHashesAttribute hashesAttr = new ModuleHashesAttribute(); + List modules = hashesAttr.modules; + for(int i = 0; i < modules.size(); i++) { + modules.set(i, remapper.mapModuleName(modules.get(i))); + } + } + super.visitAttribute(attr); + } + + @Override public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) { FieldVisitor fv = super.visitField(access, @@ -158,4 +180,8 @@ protected AnnotationVisitor createAnnotationRemapper(AnnotationVisitor av) { return new AnnotationRemapper(av, remapper); } + + protected ModuleVisitor createModuleRemapper(ModuleVisitor mv) { + return new ModuleRemapper(mv, remapper); + } } --- old/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/CodeSizeEvaluator.java Fri Oct 27 09:24:00 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/CodeSizeEvaluator.java Fri Oct 27 09:23:59 2017 @@ -75,7 +75,7 @@ private int maxSize; public CodeSizeEvaluator(final MethodVisitor mv) { - this(Opcodes.ASM5, mv); + this(Opcodes.ASM6, mv); } protected CodeSizeEvaluator(final int api, final MethodVisitor mv) { --- old/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/FieldRemapper.java Fri Oct 27 09:24:01 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/FieldRemapper.java Fri Oct 27 09:24:01 2017 @@ -74,7 +74,7 @@ private final Remapper remapper; public FieldRemapper(final FieldVisitor fv, final Remapper remapper) { - this(Opcodes.ASM5, fv, remapper); + this(Opcodes.ASM6, fv, remapper); } protected FieldRemapper(final int api, final FieldVisitor fv, --- old/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/GeneratorAdapter.java Fri Oct 27 09:24:03 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/GeneratorAdapter.java Fri Oct 27 09:24:02 2017 @@ -289,7 +289,7 @@ */ public GeneratorAdapter(final MethodVisitor mv, final int access, final String name, final String desc) { - this(Opcodes.ASM5, mv, access, name, desc); + this(Opcodes.ASM6, mv, access, name, desc); if (getClass() != GeneratorAdapter.class) { throw new IllegalStateException(); } @@ -300,7 +300,7 @@ * * @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 adapter delegates calls. * @param access --- old/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/InstructionAdapter.java Fri Oct 27 09:24:04 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/InstructionAdapter.java Fri Oct 27 09:24:04 2017 @@ -86,7 +86,7 @@ * If a subclass calls this constructor. */ public InstructionAdapter(final MethodVisitor mv) { - this(Opcodes.ASM5, mv); + this(Opcodes.ASM6, mv); if (getClass() != InstructionAdapter.class) { throw new IllegalStateException(); } @@ -97,7 +97,7 @@ * * @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 adapter delegates calls. */ --- old/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/JSRInlinerAdapter.java Fri Oct 27 09:24:06 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/JSRInlinerAdapter.java Fri Oct 27 09:24:05 2017 @@ -142,7 +142,7 @@ public JSRInlinerAdapter(final MethodVisitor mv, final int access, final String name, final String desc, final String signature, final String[] exceptions) { - this(Opcodes.ASM5, mv, access, name, desc, signature, exceptions); + this(Opcodes.ASM6, mv, access, name, desc, signature, exceptions); if (getClass() != JSRInlinerAdapter.class) { throw new IllegalStateException(); } @@ -153,7 +153,7 @@ * * @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 MethodVisitor to send the resulting inlined * method code to (use null for none). --- old/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/LocalVariablesSorter.java Fri Oct 27 09:24:07 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/LocalVariablesSorter.java Fri Oct 27 09:24:07 2017 @@ -120,7 +120,7 @@ */ public LocalVariablesSorter(final int access, final String desc, final MethodVisitor mv) { - this(Opcodes.ASM5, access, desc, mv); + this(Opcodes.ASM6, access, desc, mv); if (getClass() != LocalVariablesSorter.class) { throw new IllegalStateException(); } @@ -131,7 +131,7 @@ * * @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 access * access flags of the adapted method. * @param desc --- old/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/MethodRemapper.java Fri Oct 27 09:24:09 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/MethodRemapper.java Fri Oct 27 09:24:09 2017 @@ -76,7 +76,7 @@ protected final Remapper remapper; public MethodRemapper(final MethodVisitor mv, final Remapper remapper) { - this(Opcodes.ASM5, mv, remapper); + this(Opcodes.ASM6, mv, remapper); } protected MethodRemapper(final int api, final MethodVisitor mv, @@ -122,18 +122,20 @@ } private Object[] remapEntries(int n, Object[] entries) { - for (int i = 0; i < n; i++) { - if (entries[i] instanceof String) { - Object[] newEntries = new Object[n]; - if (i > 0) { - System.arraycopy(entries, 0, newEntries, 0, i); + if (entries != null) { + for (int i = 0; i < n; i++) { + if (entries[i] instanceof String) { + Object[] newEntries = new Object[n]; + if (i > 0) { + System.arraycopy(entries, 0, newEntries, 0, i); + } + do { + Object t = entries[i]; + newEntries[i++] = t instanceof String ? remapper + .mapType((String) t) : t; + } while (i < n); + return newEntries; } - do { - Object t = entries[i]; - newEntries[i++] = t instanceof String ? remapper - .mapType((String) t) : t; - } while (i < n); - return newEntries; } } return entries; --- old/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/Remapper.java Fri Oct 27 09:24:11 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/Remapper.java Fri Oct 27 09:24:10 2017 @@ -255,6 +255,28 @@ } /** + * Map package name to the new name. Subclasses can override. + * + * @param name name of the package + * @return new name of the package + */ + public String mapPackageName(String name) { + String fakeName = map(name + ".FakeClassName"); + int index; + return fakeName == null || (index = fakeName.lastIndexOf('.')) == -1 ? name: fakeName.substring(0, index); + } + + /** + * Map module name to the new name. Subclasses can override. + * + * @param name name of the module + * @return new name of the module + */ + public String mapModuleName(String name) { + return name; + } + + /** * Map type name to the new name. Subclasses can override. * * @param typeName --- old/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingAnnotationAdapter.java Fri Oct 27 09:24:12 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingAnnotationAdapter.java Fri Oct 27 09:24:12 2017 @@ -75,7 +75,7 @@ public RemappingAnnotationAdapter(final AnnotationVisitor av, final Remapper remapper) { - this(Opcodes.ASM5, av, remapper); + this(Opcodes.ASM6, av, remapper); } protected RemappingAnnotationAdapter(final int api, --- old/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingClassAdapter.java Fri Oct 27 09:24:14 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingClassAdapter.java Fri Oct 27 09:24:13 2017 @@ -63,6 +63,7 @@ import jdk.internal.org.objectweb.asm.ClassVisitor; import jdk.internal.org.objectweb.asm.FieldVisitor; import jdk.internal.org.objectweb.asm.MethodVisitor; +import jdk.internal.org.objectweb.asm.ModuleVisitor; import jdk.internal.org.objectweb.asm.Opcodes; import jdk.internal.org.objectweb.asm.TypePath; @@ -80,7 +81,7 @@ protected String className; public RemappingClassAdapter(final ClassVisitor cv, final Remapper remapper) { - this(Opcodes.ASM5, cv, remapper); + this(Opcodes.ASM6, cv, remapper); } protected RemappingClassAdapter(final int api, final ClassVisitor cv, @@ -98,6 +99,11 @@ interfaces == null ? null : remapper.mapTypes(interfaces)); } + @Override + public ModuleVisitor visitModule(String name, int flags, String version) { + throw new RuntimeException("RemappingClassAdapter is deprecated, use ClassRemapper instead"); + } + @Override public AnnotationVisitor visitAnnotation(String desc, boolean visible) { AnnotationVisitor av = super.visitAnnotation(remapper.mapDesc(desc), --- old/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingFieldAdapter.java Fri Oct 27 09:24:15 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingFieldAdapter.java Fri Oct 27 09:24:15 2017 @@ -76,7 +76,7 @@ private final Remapper remapper; public RemappingFieldAdapter(final FieldVisitor fv, final Remapper remapper) { - this(Opcodes.ASM5, fv, remapper); + this(Opcodes.ASM6, fv, remapper); } protected RemappingFieldAdapter(final int api, final FieldVisitor fv, --- old/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingMethodAdapter.java Fri Oct 27 09:24:17 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingMethodAdapter.java Fri Oct 27 09:24:17 2017 @@ -79,7 +79,7 @@ public RemappingMethodAdapter(final int access, final String desc, final MethodVisitor mv, final Remapper remapper) { - this(Opcodes.ASM5, access, desc, mv, remapper); + this(Opcodes.ASM6, access, desc, mv, remapper); } protected RemappingMethodAdapter(final int api, final int access, @@ -125,18 +125,20 @@ } private Object[] remapEntries(int n, Object[] entries) { - for (int i = 0; i < n; i++) { - if (entries[i] instanceof String) { - Object[] newEntries = new Object[n]; - if (i > 0) { - System.arraycopy(entries, 0, newEntries, 0, i); + if (entries != null) { + for (int i = 0; i < n; i++) { + if (entries[i] instanceof String) { + Object[] newEntries = new Object[n]; + if (i > 0) { + System.arraycopy(entries, 0, newEntries, 0, i); + } + do { + Object t = entries[i]; + newEntries[i++] = t instanceof String ? remapper + .mapType((String) t) : t; + } while (i < n); + return newEntries; } - do { - Object t = entries[i]; - newEntries[i++] = t instanceof String ? remapper - .mapType((String) t) : t; - } while (i < n); - return newEntries; } } return entries; --- old/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingSignatureAdapter.java Fri Oct 27 09:24:19 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingSignatureAdapter.java Fri Oct 27 09:24:18 2017 @@ -79,7 +79,7 @@ public RemappingSignatureAdapter(final SignatureVisitor v, final Remapper remapper) { - this(Opcodes.ASM5, v, remapper); + this(Opcodes.ASM6, v, remapper); } protected RemappingSignatureAdapter(final int api, --- old/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/SerialVersionUIDAdder.java Fri Oct 27 09:24:20 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/SerialVersionUIDAdder.java Fri Oct 27 09:24:20 2017 @@ -80,7 +80,7 @@ * ClassWriter cw = new ClassWriter(...); * ClassVisitor sv = new SerialVersionUIDAdder(cw); * ClassVisitor ca = new MyClassAdapter(sv); - * new ClassReader(originalClass).accept(ca, false); + * new ClassReader(orginalClass).accept(ca, false); * * * The SVUID algorithm can be found classNames = new Stack(); public SignatureRemapper(final SignatureVisitor v, final Remapper remapper) { - this(Opcodes.ASM5, v, remapper); + this(Opcodes.ASM6, v, remapper); } protected SignatureRemapper(final int api, final SignatureVisitor v, --- old/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/StaticInitMerger.java Fri Oct 27 09:24:23 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/StaticInitMerger.java Fri Oct 27 09:24:23 2017 @@ -78,7 +78,7 @@ private int counter; public StaticInitMerger(final String prefix, final ClassVisitor cv) { - this(Opcodes.ASM5, prefix, cv); + this(Opcodes.ASM6, prefix, cv); } protected StaticInitMerger(final int api, final String prefix, --- old/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/TryCatchBlockSorter.java Fri Oct 27 09:24:25 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/TryCatchBlockSorter.java Fri Oct 27 09:24:25 2017 @@ -86,7 +86,7 @@ public TryCatchBlockSorter(final MethodVisitor mv, final int access, final String name, final String desc, final String signature, final String[] exceptions) { - this(Opcodes.ASM5, mv, access, name, desc, signature, exceptions); + this(Opcodes.ASM6, mv, access, name, desc, signature, exceptions); } protected TryCatchBlockSorter(final int api, final MethodVisitor mv, --- old/src/java.base/share/classes/jdk/internal/org/objectweb/asm/signature/SignatureVisitor.java Fri Oct 27 09:24:26 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/signature/SignatureVisitor.java Fri Oct 27 09:24:26 2017 @@ -102,7 +102,7 @@ /** * 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; @@ -111,10 +111,10 @@ * * @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 SignatureVisitor(final int api) { - if (api != Opcodes.ASM4 && api != Opcodes.ASM5) { + if (api < Opcodes.ASM4 || api > Opcodes.ASM6) { throw new IllegalArgumentException(); } this.api = api; --- old/src/java.base/share/classes/jdk/internal/org/objectweb/asm/signature/SignatureWriter.java Fri Oct 27 09:24:28 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/signature/SignatureWriter.java Fri Oct 27 09:24:28 2017 @@ -95,7 +95,7 @@ * Constructs a new {@link SignatureWriter} object. */ public SignatureWriter() { - super(Opcodes.ASM5); + super(Opcodes.ASM6); } // ------------------------------------------------------------------------ --- old/src/java.base/share/classes/jdk/internal/org/objectweb/asm/tree/AnnotationNode.java Fri Oct 27 09:24:30 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/tree/AnnotationNode.java Fri Oct 27 09:24:29 2017 @@ -65,7 +65,7 @@ import jdk.internal.org.objectweb.asm.Opcodes; /** - * A node that represents an annotationn. + * A node that represents an annotation. * * @author Eric Bruneton */ @@ -81,8 +81,8 @@ * as two consecutive elements in the list. The name is a {@link String}, * and the value may be a {@link Byte}, {@link Boolean}, {@link Character}, * {@link Short}, {@link Integer}, {@link Long}, {@link Float}, - * {@link Double}, {@link String} or {@link jdk.internal.org.objectweb.asm.Type}, or an - * two elements String array (for enumeration values), a + * {@link Double}, {@link String} or {@link jdk.internal.org.objectweb.asm.Type}, or a + * two elements String array (for enumeration values), an * {@link AnnotationNode}, or a {@link List} of values of one of the * preceding types. The list may be null if there is no name value * pair. @@ -100,7 +100,7 @@ * If a subclass calls this constructor. */ public AnnotationNode(final String desc) { - this(Opcodes.ASM5, desc); + this(Opcodes.ASM6, desc); if (getClass() != AnnotationNode.class) { throw new IllegalStateException(); } @@ -111,7 +111,7 @@ * * @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 desc * the class descriptor of the annotation class. */ @@ -127,7 +127,7 @@ * where the visited values must be stored. */ AnnotationNode(final List values) { - super(Opcodes.ASM5); + super(Opcodes.ASM6); this.values = values; } @@ -143,7 +143,65 @@ if (this.desc != null) { values.add(name); } - values.add(value); + if (value instanceof byte[]) { + byte[] v = (byte[]) value; + ArrayList l = new ArrayList(v.length); + for (byte b : v) { + l.add(b); + } + values.add(l); + } else if (value instanceof boolean[]) { + boolean[] v = (boolean[]) value; + ArrayList l = new ArrayList(v.length); + for (boolean b : v) { + l.add(b); + } + values.add(l); + } else if (value instanceof short[]) { + short[] v = (short[]) value; + ArrayList l = new ArrayList(v.length); + for (short s : v) { + l.add(s); + } + values.add(l); + } else if (value instanceof char[]) { + char[] v = (char[]) value; + ArrayList l = new ArrayList(v.length); + for (char c : v) { + l.add(c); + } + values.add(l); + } else if (value instanceof int[]) { + int[] v = (int[]) value; + ArrayList l = new ArrayList(v.length); + for (int i : v) { + l.add(i); + } + values.add(l); + } else if (value instanceof long[]) { + long[] v = (long[]) value; + ArrayList l = new ArrayList(v.length); + for (long lng : v) { + l.add(lng); + } + values.add(l); + } else if (value instanceof float[]) { + float[] v = (float[]) value; + ArrayList l = new ArrayList(v.length); + for (float f : v) { + l.add(f); + } + values.add(l); + } else if (value instanceof double[]) { + double[] v = (double[]) value; + ArrayList l = new ArrayList(v.length); + for (double d : v) { + l.add(d); + } + values.add(l); + } else { + values.add(value); + } } @Override @@ -200,8 +258,8 @@ * versions of the ASM API than the given version. * * @param api - * an ASM API version. Must be one of {@link Opcodes#ASM4} or - * {@link Opcodes#ASM5}. + * an ASM API version. Must be one of {@link Opcodes#ASM4}, + * {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. */ public void check(final int api) { // nothing to do --- old/src/java.base/share/classes/jdk/internal/org/objectweb/asm/tree/ClassNode.java Fri Oct 27 09:24:31 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/tree/ClassNode.java Fri Oct 27 09:24:31 2017 @@ -67,6 +67,7 @@ import jdk.internal.org.objectweb.asm.ClassVisitor; import jdk.internal.org.objectweb.asm.FieldVisitor; import jdk.internal.org.objectweb.asm.MethodVisitor; +import jdk.internal.org.objectweb.asm.ModuleVisitor; import jdk.internal.org.objectweb.asm.Opcodes; import jdk.internal.org.objectweb.asm.TypePath; @@ -127,6 +128,11 @@ public String sourceDebug; /** + * Module information. May be null. + */ + public ModuleNode module; + + /** * The internal name of the enclosing class of the class. May be * null. */ @@ -221,7 +227,7 @@ * If a subclass calls this constructor. */ public ClassNode() { - this(Opcodes.ASM5); + this(Opcodes.ASM6); if (getClass() != ClassNode.class) { throw new IllegalStateException(); } @@ -232,7 +238,7 @@ * * @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 ClassNode(final int api) { super(api); @@ -267,6 +273,12 @@ } @Override + public ModuleVisitor visitModule(final String name, final int access, + final String version) { + return module = new ModuleNode(name, access, version); + } + + @Override public void visitOuterClass(final String owner, final String name, final String desc) { outerClass = owner; @@ -358,11 +370,16 @@ * API than the given version. * * @param api - * an ASM API version. Must be one of {@link Opcodes#ASM4} or - * {@link Opcodes#ASM5}. + * an ASM API version. Must be one of {@link Opcodes#ASM4}, + * {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. */ public void check(final int api) { - if (api == Opcodes.ASM4) { + if (api < Opcodes.ASM6) { + if (module != null) { + throw new RuntimeException(); + } + } + if (api < Opcodes.ASM5) { if (visibleTypeAnnotations != null && visibleTypeAnnotations.size() > 0) { throw new RuntimeException(); @@ -371,13 +388,32 @@ && invisibleTypeAnnotations.size() > 0) { throw new RuntimeException(); } - for (FieldNode f : fields) { - f.check(api); - } - for (MethodNode m : methods) { - m.check(api); - } } + // checks attributes + int i, n; + n = visibleAnnotations == null ? 0 : visibleAnnotations.size(); + for (i = 0; i < n; ++i) { + visibleAnnotations.get(i).check(api); + } + n = invisibleAnnotations == null ? 0 : invisibleAnnotations.size(); + for (i = 0; i < n; ++i) { + invisibleAnnotations.get(i).check(api); + } + n = visibleTypeAnnotations == null ? 0 : visibleTypeAnnotations.size(); + for (i = 0; i < n; ++i) { + visibleTypeAnnotations.get(i).check(api); + } + n = invisibleTypeAnnotations == null ? 0 : invisibleTypeAnnotations + .size(); + for (i = 0; i < n; ++i) { + invisibleTypeAnnotations.get(i).check(api); + } + for (FieldNode f : fields) { + f.check(api); + } + for (MethodNode m : methods) { + m.check(api); + } } /** @@ -395,6 +431,10 @@ if (sourceFile != null || sourceDebug != null) { cv.visitSource(sourceFile, sourceDebug); } + // visits module + if (module != null) { + module.accept(cv); + } // visits outer class if (outerClass != null) { cv.visitOuterClass(outerClass, outerMethod, outerMethodDesc); --- old/src/java.base/share/classes/jdk/internal/org/objectweb/asm/tree/FieldNode.java Fri Oct 27 09:24:33 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/tree/FieldNode.java Fri Oct 27 09:24:32 2017 @@ -173,7 +173,7 @@ */ public FieldNode(final int access, final String name, final String desc, final String signature, final Object value) { - this(Opcodes.ASM5, access, name, desc, signature, value); + this(Opcodes.ASM6, access, name, desc, signature, value); if (getClass() != FieldNode.class) { throw new IllegalStateException(); } @@ -276,8 +276,8 @@ * API than the given version. * * @param api - * an ASM API version. Must be one of {@link Opcodes#ASM4} or - * {@link Opcodes#ASM5}. + * an ASM API version. Must be one of {@link Opcodes#ASM4}, + * {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. */ public void check(final int api) { if (api == Opcodes.ASM4) { --- old/src/java.base/share/classes/jdk/internal/org/objectweb/asm/tree/InsnList.java Fri Oct 27 09:24:35 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/tree/InsnList.java Fri Oct 27 09:24:34 2017 @@ -634,14 +634,28 @@ } public void add(Object o) { - InsnList.this.insertBefore(next, (AbstractInsnNode) o); + if (next != null) { + InsnList.this.insertBefore(next, (AbstractInsnNode) o); + } else if (prev != null) { + InsnList.this.insert(prev, (AbstractInsnNode) o); + } else { + InsnList.this.add((AbstractInsnNode) o); + } prev = (AbstractInsnNode) o; remove = null; } public void set(Object o) { - InsnList.this.set(next.prev, (AbstractInsnNode) o); - prev = (AbstractInsnNode) o; + if (remove != null) { + InsnList.this.set(remove, (AbstractInsnNode) o); + if (remove == prev) { + prev = (AbstractInsnNode) o; + } else { + next = (AbstractInsnNode) o; + } + } else { + throw new IllegalStateException(); + } } } } --- old/src/java.base/share/classes/jdk/internal/org/objectweb/asm/tree/LocalVariableAnnotationNode.java Fri Oct 27 09:24:36 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/tree/LocalVariableAnnotationNode.java Fri Oct 27 09:24:36 2017 @@ -122,7 +122,7 @@ */ public LocalVariableAnnotationNode(int typeRef, TypePath typePath, LabelNode[] start, LabelNode[] end, int[] index, String desc) { - this(Opcodes.ASM5, typeRef, typePath, start, end, index, desc); + this(Opcodes.ASM6, typeRef, typePath, start, end, index, desc); } /** @@ -130,7 +130,7 @@ * * @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 typeRef * a reference to the annotated type. See {@link TypeReference}. * @param start @@ -181,6 +181,6 @@ index[i] = this.index.get(i); } accept(mv.visitLocalVariableAnnotation(typeRef, typePath, start, end, - index, desc, true)); + index, desc, visible)); } } --- old/src/java.base/share/classes/jdk/internal/org/objectweb/asm/tree/MethodNode.java Fri Oct 27 09:24:38 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/tree/MethodNode.java Fri Oct 27 09:24:37 2017 @@ -249,7 +249,7 @@ * If a subclass calls this constructor. */ public MethodNode() { - this(Opcodes.ASM5); + this(Opcodes.ASM6); if (getClass() != MethodNode.class) { throw new IllegalStateException(); } @@ -260,7 +260,7 @@ * * @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 MethodNode(final int api) { super(api); @@ -291,7 +291,7 @@ */ public MethodNode(final int access, final String name, final String desc, final String signature, final String[] exceptions) { - this(Opcodes.ASM5, access, name, desc, signature, exceptions); + this(Opcodes.ASM6, access, name, desc, signature, exceptions); if (getClass() != MethodNode.class) { throw new IllegalStateException(); } @@ -302,7 +302,7 @@ * * @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 access * the method's access flags (see {@link Opcodes}). This * parameter also indicates if the method is synthetic and/or @@ -688,8 +688,8 @@ * versions of the ASM API than the given version. * * @param api - * an ASM API version. Must be one of {@link Opcodes#ASM4} or - * {@link Opcodes#ASM5}. + * an ASM API version. Must be one of {@link Opcodes#ASM4}, + * {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. */ public void check(final int api) { if (api == Opcodes.ASM4) { --- old/src/java.base/share/classes/jdk/internal/org/objectweb/asm/tree/TypeAnnotationNode.java Fri Oct 27 09:24:39 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/tree/TypeAnnotationNode.java Fri Oct 27 09:24:39 2017 @@ -99,7 +99,7 @@ */ public TypeAnnotationNode(final int typeRef, final TypePath typePath, final String desc) { - this(Opcodes.ASM5, typeRef, typePath, desc); + this(Opcodes.ASM6, typeRef, typePath, desc); if (getClass() != TypeAnnotationNode.class) { throw new IllegalStateException(); } @@ -110,7 +110,7 @@ * * @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 typeRef * a reference to the annotated type. See {@link TypeReference}. * @param typePath --- old/src/java.base/share/classes/jdk/internal/org/objectweb/asm/tree/analysis/BasicInterpreter.java Fri Oct 27 09:24:41 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/tree/analysis/BasicInterpreter.java Fri Oct 27 09:24:41 2017 @@ -82,7 +82,7 @@ Opcodes { public BasicInterpreter() { - super(ASM5); + super(ASM6); } protected BasicInterpreter(final int api) { --- old/src/java.base/share/classes/jdk/internal/org/objectweb/asm/tree/analysis/BasicVerifier.java Fri Oct 27 09:24:43 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/tree/analysis/BasicVerifier.java Fri Oct 27 09:24:42 2017 @@ -76,7 +76,7 @@ public class BasicVerifier extends BasicInterpreter { public BasicVerifier() { - super(ASM5); + super(ASM6); } protected BasicVerifier(final int api) { --- old/src/java.base/share/classes/jdk/internal/org/objectweb/asm/tree/analysis/SimpleVerifier.java Fri Oct 27 09:24:44 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/tree/analysis/SimpleVerifier.java Fri Oct 27 09:24:44 2017 @@ -136,7 +136,7 @@ public SimpleVerifier(final Type currentClass, final Type currentSuperClass, final List currentClassInterfaces, final boolean isInterface) { - this(ASM5, currentClass, currentSuperClass, currentClassInterfaces, + this(ASM6, currentClass, currentSuperClass, currentClassInterfaces, isInterface); } --- old/src/java.base/share/classes/jdk/internal/org/objectweb/asm/tree/analysis/SourceInterpreter.java Fri Oct 27 09:24:46 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/tree/analysis/SourceInterpreter.java Fri Oct 27 09:24:45 2017 @@ -79,7 +79,7 @@ Opcodes { public SourceInterpreter() { - super(ASM5); + super(ASM6); } protected SourceInterpreter(final int api) { --- old/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/ASMifier.java Fri Oct 27 09:24:47 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/ASMifier.java Fri Oct 27 09:24:47 2017 @@ -110,6 +110,11 @@ private static final int ACCESS_INNER = 1048576; /** + * Pseudo access flag used to distinguish module requires/exports flags. + */ + private static final int ACCESS_MODULE = 2097152; + + /** * Constructs a new {@link ASMifier}. Subclasses must not use this * constructor. Instead, they must use the * {@link #ASMifier(int, String, int)} version. @@ -118,7 +123,7 @@ * If a subclass calls this constructor. */ public ASMifier() { - this(Opcodes.ASM5, "cw", 0); + this(Opcodes.ASM6, "cw", 0); if (getClass() != ASMifier.class) { throw new IllegalStateException(); } @@ -129,7 +134,7 @@ * * @param api * the ASM API version implemented by this class. Must be one of - * {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. + * {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. * @param name * the name of the visitor variable in the produced code. * @param id @@ -196,13 +201,17 @@ final String signature, final String superName, final String[] interfaces) { String simpleName; - int n = name.lastIndexOf('/'); - if (n == -1) { - simpleName = name; + if (name == null) { + simpleName = "module-info"; } else { - text.add("package asm." + name.substring(0, n).replace('/', '.') - + ";\n"); - simpleName = name.substring(n + 1); + int n = name.lastIndexOf('/'); + if (n == -1) { + simpleName = name; + } else { + text.add("package asm." + name.substring(0, n).replace('/', '.') + + ";\n"); + simpleName = name.substring(n + 1).replace('-', '_'); + } } text.add("import java.util.*;\n"); text.add("import jdk.internal.org.objectweb.asm.*;\n"); @@ -237,6 +246,12 @@ case Opcodes.V1_7: buf.append("V1_7"); break; + case Opcodes.V1_8: + buf.append("V1_8"); + break; + case Opcodes.V9: + buf.append("V9"); + break; default: buf.append(version); break; @@ -276,6 +291,24 @@ } @Override + public Printer visitModule(final String name, final int flags, + final String version) { + buf.setLength(0); + buf.append("ModuleVisitor mdv = cw.visitModule("); + appendConstant(name); + buf.append(", "); + appendAccess(flags | ACCESS_MODULE); + buf.append(", "); + appendConstant(version); + buf.append(");\n\n"); + text.add(buf.toString()); + ASMifier a = createASMifier("mdv", 0); + text.add(a.getText()); + text.add("}\n"); + return a; + } + + @Override public void visitOuterClass(final String owner, final String name, final String desc) { buf.setLength(0); @@ -386,6 +419,108 @@ } // ------------------------------------------------------------------------ + // Module + // ------------------------------------------------------------------------ + + @Override + public void visitMainClass(String mainClass) { + buf.setLength(0); + buf.append("mdv.visitMainClass("); + appendConstant(buf, mainClass); + buf.append(");\n"); + text.add(buf.toString()); + } + + @Override + public void visitPackage(String packaze) { + buf.setLength(0); + buf.append("mdv.visitPackage("); + appendConstant(buf, packaze); + buf.append(");\n"); + text.add(buf.toString()); + } + + @Override + public void visitRequire(String module, int access, String version) { + buf.setLength(0); + buf.append("mdv.visitRequire("); + appendConstant(buf, module); + buf.append(", "); + appendAccess(access | ACCESS_MODULE); + buf.append(", "); + appendConstant(buf, version); + buf.append(");\n"); + text.add(buf.toString()); + } + + @Override + public void visitExport(String packaze, int access, String... modules) { + buf.setLength(0); + buf.append("mdv.visitExport("); + appendConstant(buf, packaze); + buf.append(", "); + appendAccess(access | ACCESS_MODULE); + if (modules != null && modules.length > 0) { + buf.append(", new String[] {"); + for (int i = 0; i < modules.length; ++i) { + buf.append(i == 0 ? " " : ", "); + appendConstant(modules[i]); + } + buf.append(" }"); + } + buf.append(");\n"); + text.add(buf.toString()); + } + + @Override + public void visitOpen(String packaze, int access, String... modules) { + buf.setLength(0); + buf.append("mdv.visitOpen("); + appendConstant(buf, packaze); + buf.append(", "); + appendAccess(access | ACCESS_MODULE); + if (modules != null && modules.length > 0) { + buf.append(", new String[] {"); + for (int i = 0; i < modules.length; ++i) { + buf.append(i == 0 ? " " : ", "); + appendConstant(modules[i]); + } + buf.append(" }"); + } + buf.append(");\n"); + text.add(buf.toString()); + } + + @Override + public void visitUse(String service) { + buf.setLength(0); + buf.append("mdv.visitUse("); + appendConstant(buf, service); + buf.append(");\n"); + text.add(buf.toString()); + } + + @Override + public void visitProvide(String service, String... providers) { + buf.setLength(0); + buf.append("mdv.visitProvide("); + appendConstant(buf, service); + buf.append(", new String[] {"); + for (int i = 0; i < providers.length; ++i) { + buf.append(i == 0 ? " " : ", "); + appendConstant(providers[i]); + } + buf.append(" });\n"); + text.add(buf.toString()); + } + + @Override + public void visitModuleEnd() { + text.add("mdv.visitEnd();\n"); + } + + + // ------------------------------------------------------------------------ // Annotations // ------------------------------------------------------------------------ @@ -972,7 +1107,7 @@ // ------------------------------------------------------------------------ protected ASMifier createASMifier(final String name, final int id) { - return new ASMifier(Opcodes.ASM5, name, id); + return new ASMifier(Opcodes.ASM6, name, id); } /** @@ -1000,7 +1135,11 @@ if (!first) { buf.append(" + "); } - buf.append("ACC_FINAL"); + if ((access & ACCESS_MODULE) == 0) { + buf.append("ACC_FINAL"); + } else { + buf.append("ACC_TRANSITIVE"); + } first = false; } if ((access & Opcodes.ACC_STATIC) != 0) { @@ -1010,31 +1149,35 @@ buf.append("ACC_STATIC"); first = false; } - if ((access & Opcodes.ACC_SYNCHRONIZED) != 0) { + if ((access & (Opcodes.ACC_SYNCHRONIZED | Opcodes.ACC_SUPER | Opcodes.ACC_TRANSITIVE)) != 0) { if (!first) { buf.append(" + "); } if ((access & ACCESS_CLASS) == 0) { - buf.append("ACC_SYNCHRONIZED"); + if ((access & ACCESS_MODULE) == 0) { + buf.append("ACC_SYNCHRONIZED"); + } else { + buf.append("ACC_TRANSITIVE"); + } } else { buf.append("ACC_SUPER"); } first = false; } - if ((access & Opcodes.ACC_VOLATILE) != 0 - && (access & ACCESS_FIELD) != 0) { + if ((access & (Opcodes.ACC_VOLATILE | Opcodes.ACC_BRIDGE | Opcodes.ACC_STATIC_PHASE)) != 0) { if (!first) { buf.append(" + "); } - buf.append("ACC_VOLATILE"); - first = false; - } - if ((access & Opcodes.ACC_BRIDGE) != 0 && (access & ACCESS_CLASS) == 0 - && (access & ACCESS_FIELD) == 0) { - if (!first) { - buf.append(" + "); + if ((access & ACCESS_FIELD) == 0) { + if ((access & ACCESS_MODULE) == 0) { + buf.append("ACC_BRIDGE"); + } else { + buf.append("ACC_STATIC_PHASE"); + } + } else { + buf.append("ACC_VOLATILE"); } - buf.append("ACC_BRIDGE"); + first = false; } if ((access & Opcodes.ACC_VARARGS) != 0 && (access & ACCESS_CLASS) == 0 @@ -1113,11 +1256,15 @@ buf.append("ACC_DEPRECATED"); first = false; } - if ((access & Opcodes.ACC_MANDATED) != 0) { + if ((access & (Opcodes.ACC_MANDATED | Opcodes.ACC_MODULE)) != 0) { if (!first) { buf.append(" + "); } - buf.append("ACC_MANDATED"); + if ((access & ACCESS_CLASS) == 0) { + buf.append("ACC_MANDATED"); + } else { + buf.append("ACC_MODULE"); + } first = false; } if (first) { @@ -1163,7 +1310,8 @@ .append(", \""); buf.append(h.getOwner()).append("\", \""); buf.append(h.getName()).append("\", \""); - buf.append(h.getDesc()).append("\")"); + buf.append(h.getDesc()).append("\", "); + buf.append(h.isInterface()).append(")"); } else if (cst instanceof Byte) { buf.append("new Byte((byte)").append(cst).append(')'); } else if (cst instanceof Boolean) { --- old/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/CheckAnnotationAdapter.java Fri Oct 27 09:24:49 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/CheckAnnotationAdapter.java Fri Oct 27 09:24:49 2017 @@ -78,7 +78,7 @@ } CheckAnnotationAdapter(final AnnotationVisitor av, final boolean named) { - super(Opcodes.ASM5, av); + super(Opcodes.ASM6, av); this.named = named; } --- old/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/CheckClassAdapter.java Fri Oct 27 09:24:51 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/CheckClassAdapter.java Fri Oct 27 09:24:50 2017 @@ -73,6 +73,7 @@ import jdk.internal.org.objectweb.asm.FieldVisitor; import jdk.internal.org.objectweb.asm.Label; import jdk.internal.org.objectweb.asm.MethodVisitor; +import jdk.internal.org.objectweb.asm.ModuleVisitor; import jdk.internal.org.objectweb.asm.Opcodes; import jdk.internal.org.objectweb.asm.Type; import jdk.internal.org.objectweb.asm.TypePath; @@ -181,6 +182,11 @@ private boolean end; /** + * true if the visitModule method has been called. + */ + private boolean module; + + /** * The already visited labels. This map associate Integer values to Label * keys. */ @@ -363,7 +369,7 @@ * If a subclass calls this constructor. */ public CheckClassAdapter(final ClassVisitor cv, final boolean checkDataFlow) { - this(Opcodes.ASM5, cv, checkDataFlow); + this(Opcodes.ASM6, cv, checkDataFlow); if (getClass() != CheckClassAdapter.class) { throw new IllegalStateException(); } @@ -374,7 +380,7 @@ * * @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 adapter must delegate calls. * @param checkDataFlow @@ -407,8 +413,12 @@ + Opcodes.ACC_SUPER + Opcodes.ACC_INTERFACE + Opcodes.ACC_ABSTRACT + Opcodes.ACC_SYNTHETIC + Opcodes.ACC_ANNOTATION + Opcodes.ACC_ENUM - + Opcodes.ACC_DEPRECATED + 0x40000); // ClassWriter.ACC_SYNTHETIC_ATTRIBUTE - if (name == null || !name.endsWith("package-info")) { + + Opcodes.ACC_DEPRECATED + Opcodes.ACC_MODULE + + 0x40000); // ClassWriter.ACC_SYNTHETIC_ATTRIBUTE + if (name == null) { + throw new IllegalArgumentException("Illegal class name (null)"); + } + if (!name.endsWith("package-info")) { CheckMethodAdapter.checkInternalName(name, "class name"); } if ("java/lang/Object".equals(name)) { @@ -449,6 +459,22 @@ super.visitSource(file, debug); } + @Override + public ModuleVisitor visitModule(String name, int access, String version) { + checkState(); + if (module) { + throw new IllegalStateException( + "visitModule can be called only once."); + } + module = true; + if (name == null) { + throw new IllegalArgumentException("Illegal module name (null)"); + } + checkAccess(access, Opcodes.ACC_OPEN | Opcodes.ACC_SYNTHETIC); + return new CheckModuleAdapter(super.visitModule(name, access, version), + (access & Opcodes.ACC_OPEN) != 0); + } + @Override public void visitOuterClass(final String owner, final String name, final String desc) { --- old/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/CheckFieldAdapter.java Fri Oct 27 09:24:52 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/CheckFieldAdapter.java Fri Oct 27 09:24:52 2017 @@ -83,7 +83,7 @@ * If a subclass calls this constructor. */ public CheckFieldAdapter(final FieldVisitor fv) { - this(Opcodes.ASM5, fv); + this(Opcodes.ASM6, fv); if (getClass() != CheckFieldAdapter.class) { throw new IllegalStateException(); } @@ -94,7 +94,7 @@ * * @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 adapter must delegate calls. */ --- old/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/CheckMethodAdapter.java Fri Oct 27 09:24:54 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/CheckMethodAdapter.java Fri Oct 27 09:24:53 2017 @@ -426,7 +426,7 @@ */ public CheckMethodAdapter(final MethodVisitor mv, final Map labels) { - this(Opcodes.ASM5, mv, labels); + this(Opcodes.ASM6, mv, labels); if (getClass() != CheckMethodAdapter.class) { throw new IllegalStateException(); } @@ -439,7 +439,8 @@ * * @param api * the ASM API version implemented by this CheckMethodAdapter. - * 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}. * @param mv * the method visitor to which this adapter must delegate calls. * @param labels @@ -756,6 +757,12 @@ throw new IllegalArgumentException( "INVOKEINTERFACE can't be used with classes"); } + if (opcode == Opcodes.INVOKESPECIAL && itf + && (version & 0xFFFF) < Opcodes.V1_8) { + throw new IllegalArgumentException( + "INVOKESPECIAL can't be used with interfaces prior to Java 8"); + } + // Calling super.visitMethodInsn requires to call the correct version // depending on this.api (otherwise infinite loops can occur). To // simplify and to make it easier to automatically remove the backward --- old/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/CheckSignatureAdapter.java Fri Oct 27 09:24:55 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/CheckSignatureAdapter.java Fri Oct 27 09:24:55 2017 @@ -142,7 +142,7 @@ * null. */ public CheckSignatureAdapter(final int type, final SignatureVisitor sv) { - this(Opcodes.ASM5, type, sv); + this(Opcodes.ASM6, type, sv); } /** @@ -150,7 +150,7 @@ * * @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 type * the type of signature to be checked. See * {@link #CLASS_SIGNATURE}, {@link #METHOD_SIGNATURE} and @@ -175,7 +175,7 @@ || (state != EMPTY && state != FORMAL && state != BOUND)) { throw new IllegalStateException(); } - CheckMethodAdapter.checkIdentifier(name, "formal type parameter"); + checkIdentifier(name, "formal type parameter"); state = FORMAL; if (sv != null) { sv.visitFormalTypeParameter(name); @@ -284,7 +284,7 @@ if (type != TYPE_SIGNATURE || state != EMPTY) { throw new IllegalStateException(); } - CheckMethodAdapter.checkIdentifier(name, "type variable"); + checkIdentifier(name, "type variable"); state = SIMPLE_TYPE; if (sv != null) { sv.visitTypeVariable(name); @@ -306,7 +306,7 @@ if (type != TYPE_SIGNATURE || state != EMPTY) { throw new IllegalStateException(); } - CheckMethodAdapter.checkInternalName(name, "class name"); + checkClassName(name, "class name"); state = CLASS_TYPE; if (sv != null) { sv.visitClassType(name); @@ -318,7 +318,7 @@ if (state != CLASS_TYPE) { throw new IllegalStateException(); } - CheckMethodAdapter.checkIdentifier(name, "inner class name"); + checkIdentifier(name, "inner class name"); if (sv != null) { sv.visitInnerClassType(name); } @@ -356,4 +356,30 @@ sv.visitEnd(); } } + + private void checkClassName(final String name, final String msg) { + if (name == null || name.length() == 0) { + throw new IllegalArgumentException("Invalid " + msg + + " (must not be null or empty)"); + } + for (int i = 0; i < name.length(); ++i) { + if (".;[<>:".indexOf(name.charAt(i)) != -1) { + throw new IllegalArgumentException("Invalid " + msg + + " (must not contain . ; [ < > or :): " + name); + } + } + } + + private void checkIdentifier(final String name, final String msg) { + if (name == null || name.length() == 0) { + throw new IllegalArgumentException("Invalid " + msg + + " (must not be null or empty)"); + } + for (int i = 0; i < name.length(); ++i) { + if (".;[/<>:".indexOf(name.charAt(i)) != -1) { + throw new IllegalArgumentException("Invalid " + msg + + " (must not contain . ; [ / < > or :): " + name); + } + } + } } --- old/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/Printer.java Fri Oct 27 09:24:57 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/Printer.java Fri Oct 27 09:24:57 2017 @@ -146,7 +146,7 @@ /** * The ASM API version implemented by this class. 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; @@ -174,7 +174,7 @@ * * @param api * the ASM API version implemented by this printer. Must be one - * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. + * of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. */ protected Printer(final int api) { this.api = api; @@ -226,7 +226,25 @@ */ public abstract void visitSource(final String source, final String debug); + /** + * Module. + * See {@link jdk.internal.org.objectweb.asm.ClassVisitor#visitModule(String, int)}. + * + * @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 + */ + public Printer visitModule(String name, int access, String version) { + throw new RuntimeException("Must be overriden"); + } + + /** * Class outer class. * See {@link jdk.internal.org.objectweb.asm.ClassVisitor#visitOuterClass}. * @@ -376,6 +394,45 @@ public abstract void visitClassEnd(); // ------------------------------------------------------------------------ + // Module + // ------------------------------------------------------------------------ + + public void visitMainClass(String mainClass) { + throw new RuntimeException("Must be overriden"); + } + + public void visitPackage(String packaze) { + throw new RuntimeException("Must be overriden"); + } + + public void visitRequire(String module, int access, String version) { + throw new RuntimeException("Must be overriden"); + } + + public void visitExport(String packaze, int access, String... modules) { + throw new RuntimeException("Must be overriden"); + } + + public void visitOpen(String packaze, int access, String... modules) { + throw new RuntimeException("Must be overriden"); + } + + public void visitUse(String service) { + throw new RuntimeException("Must be overriden"); + } + + public void visitProvide(String service, String... providers) { + throw new RuntimeException("Must be overriden"); + } + + /** + * Module end. See {@link jdk.internal.org.objectweb.asm.ModuleVisitor#visitEnd}. + */ + public void visitModuleEnd() { + throw new RuntimeException("Must be overriden"); + } + + // ------------------------------------------------------------------------ // Annotations // ------------------------------------------------------------------------ --- old/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/Textifier.java Fri Oct 27 09:24:59 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/Textifier.java Fri Oct 27 09:24:58 2017 @@ -182,7 +182,7 @@ * If a subclass calls this constructor. */ public Textifier() { - this(Opcodes.ASM5); + this(Opcodes.ASM6); if (getClass() != Textifier.class) { throw new IllegalStateException(); } @@ -193,7 +193,7 @@ * * @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}. */ protected Textifier(final int api) { super(api); @@ -250,6 +250,10 @@ public void visit(final int version, final int access, final String name, final String signature, final String superName, final String[] interfaces) { + if ((access & Opcodes.ACC_MODULE) != 0) { + // visitModule will print the module + return; + } this.access = access; int major = version & 0xFFFF; int minor = version >>> 16; @@ -271,7 +275,7 @@ .append(sv.getDeclaration()).append('\n'); } - appendAccess(access & ~Opcodes.ACC_SUPER); + appendAccess(access & ~(Opcodes.ACC_SUPER | Opcodes.ACC_MODULE)); if ((access & Opcodes.ACC_ANNOTATION) != 0) { buf.append("@interface "); } else if ((access & Opcodes.ACC_INTERFACE) != 0) { @@ -315,6 +319,24 @@ } @Override + public Printer visitModule(final String name, final int access, + final String version) { + buf.setLength(0); + if ((access & Opcodes.ACC_OPEN) != 0) { + buf.append("open "); + } + buf.append("module ") + .append(name) + .append(" { ") + .append(version == null ? "" : "// " + version) + .append("\n\n"); + text.add(buf.toString()); + Textifier t = createTextifier(); + text.add(t.getText()); + return t; + } + + @Override public void visitOuterClass(final String owner, final String name, final String desc) { buf.setLength(0); @@ -443,7 +465,7 @@ } buf.append(tab); - appendAccess(access & ~Opcodes.ACC_VOLATILE); + appendAccess(access & ~(Opcodes.ACC_VOLATILE | Opcodes.ACC_TRANSIENT)); if ((access & Opcodes.ACC_NATIVE) != 0) { buf.append("native "); } @@ -483,6 +505,118 @@ } // ------------------------------------------------------------------------ + // Module + // ------------------------------------------------------------------------ + + @Override + public void visitMainClass(String mainClass) { + buf.setLength(0); + buf.append(" // main class ").append(mainClass).append('\n'); + text.add(buf.toString()); + } + + @Override + public void visitPackage(String packaze) { + buf.setLength(0); + buf.append(" // package ").append(packaze).append('\n'); + text.add(buf.toString()); + } + + @Override + public void visitRequire(String require, int access, String version) { + buf.setLength(0); + buf.append(tab).append("requires "); + if ((access & Opcodes.ACC_TRANSITIVE) != 0) { + buf.append("transitive "); + } + if ((access & Opcodes.ACC_STATIC_PHASE) != 0) { + buf.append("static "); + } + buf.append(require) + .append("; // access flags 0x") + .append(Integer.toHexString(access).toUpperCase()) + .append('\n'); + if (version != null) { + buf.append(" // version ") + .append(version) + .append('\n'); + } + text.add(buf.toString()); + } + + @Override + public void visitExport(String export, int access, String... modules) { + buf.setLength(0); + buf.append(tab).append("exports "); + buf.append(export); + if (modules != null && modules.length > 0) { + buf.append(" to"); + } else { + buf.append(';'); + } + buf.append(" // access flags 0x") + .append(Integer.toHexString(access).toUpperCase()) + .append('\n'); + if (modules != null && modules.length > 0) { + for (int i = 0; i < modules.length; ++i) { + buf.append(tab2).append(modules[i]); + buf.append(i != modules.length - 1 ? ",\n": ";\n"); + } + } + text.add(buf.toString()); + } + + @Override + public void visitOpen(String export, int access, String... modules) { + buf.setLength(0); + buf.append(tab).append("opens "); + buf.append(export); + if (modules != null && modules.length > 0) { + buf.append(" to"); + } else { + buf.append(';'); + } + buf.append(" // access flags 0x") + .append(Integer.toHexString(access).toUpperCase()) + .append('\n'); + if (modules != null && modules.length > 0) { + for (int i = 0; i < modules.length; ++i) { + buf.append(tab2).append(modules[i]); + buf.append(i != modules.length - 1 ? ",\n": ";\n"); + } + } + text.add(buf.toString()); + } + + @Override + public void visitUse(String use) { + buf.setLength(0); + buf.append(tab).append("uses "); + appendDescriptor(INTERNAL_NAME, use); + buf.append(";\n"); + text.add(buf.toString()); + } + + @Override + public void visitProvide(String provide, String... providers) { + buf.setLength(0); + buf.append(tab).append("provides "); + appendDescriptor(INTERNAL_NAME, provide); + buf.append(" with\n"); + for (int i = 0; i < providers.length; ++i) { + buf.append(tab2); + appendDescriptor(INTERNAL_NAME, providers[i]); + buf.append(i != providers.length - 1 ? ",\n": ";\n"); + } + text.add(buf.toString()); + } + + @Override + public void visitModuleEnd() { + // empty + } + + // ------------------------------------------------------------------------ // Annotations // ------------------------------------------------------------------------ @@ -1296,13 +1430,16 @@ appendDescriptor(INTERNAL_NAME, h.getOwner()); buf.append('.'); buf.append(h.getName()); - if(!isMethodHandle){ + if (!isMethodHandle) { buf.append('('); } appendDescriptor(HANDLE_DESCRIPTOR, h.getDesc()); - if(!isMethodHandle){ + if (!isMethodHandle) { buf.append(')'); } + if (h.isInterface()) { + buf.append(" itf"); + } } /** --- old/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/TraceAnnotationVisitor.java Fri Oct 27 09:25:00 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/TraceAnnotationVisitor.java Fri Oct 27 09:25:00 2017 @@ -76,7 +76,7 @@ } public TraceAnnotationVisitor(final AnnotationVisitor av, final Printer p) { - super(Opcodes.ASM5, av); + super(Opcodes.ASM6, av); this.p = p; } --- old/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/TraceClassVisitor.java Fri Oct 27 09:25:02 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/TraceClassVisitor.java Fri Oct 27 09:25:01 2017 @@ -65,6 +65,7 @@ import jdk.internal.org.objectweb.asm.ClassVisitor; import jdk.internal.org.objectweb.asm.FieldVisitor; import jdk.internal.org.objectweb.asm.MethodVisitor; +import jdk.internal.org.objectweb.asm.ModuleVisitor; import jdk.internal.org.objectweb.asm.Opcodes; import jdk.internal.org.objectweb.asm.TypePath; @@ -160,7 +161,7 @@ */ public TraceClassVisitor(final ClassVisitor cv, final Printer p, final PrintWriter pw) { - super(Opcodes.ASM5, cv); + super(Opcodes.ASM6, cv); this.pw = pw; this.p = p; } @@ -179,6 +180,14 @@ super.visitSource(file, debug); } + @Override + public ModuleVisitor visitModule(String name, int flags, + String version) { + Printer p = this.p.visitModule(name, flags, version); + ModuleVisitor mv = super.visitModule(name, flags, version); + return new TraceModuleVisitor(mv, p); + } + @Override public void visitOuterClass(final String owner, final String name, final String desc) { --- old/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/TraceFieldVisitor.java Fri Oct 27 09:25:04 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/TraceFieldVisitor.java Fri Oct 27 09:25:03 2017 @@ -79,7 +79,7 @@ } public TraceFieldVisitor(final FieldVisitor fv, final Printer p) { - super(Opcodes.ASM5, fv); + super(Opcodes.ASM6, fv); this.p = p; } --- old/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/TraceMethodVisitor.java Fri Oct 27 09:25:05 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/TraceMethodVisitor.java Fri Oct 27 09:25:05 2017 @@ -81,7 +81,7 @@ } public TraceMethodVisitor(final MethodVisitor mv, final Printer p) { - super(Opcodes.ASM5, mv); + super(Opcodes.ASM6, mv); this.p = p; } --- old/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/TraceSignatureVisitor.java Fri Oct 27 09:25:07 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/TraceSignatureVisitor.java Fri Oct 27 09:25:06 2017 @@ -104,13 +104,13 @@ private String separator = ""; public TraceSignatureVisitor(final int access) { - super(Opcodes.ASM5); + super(Opcodes.ASM6); isInterface = (access & Opcodes.ACC_INTERFACE) != 0; this.declaration = new StringBuilder(); } private TraceSignatureVisitor(final StringBuilder buf) { - super(Opcodes.ASM5); + super(Opcodes.ASM6); this.declaration = buf; } --- old/src/java.base/share/classes/jdk/internal/org/objectweb/asm/version.txt Fri Oct 27 09:25:08 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/version.txt Fri Oct 27 09:25:08 2017 @@ -1,12 +1,4 @@ -Path: . -Working Copy Root Path: /hudson/jobs/objectweb-init/workspace/asm-svn-2016-01-25 -URL: file:///svnroot/asm/trunk/asm -Repository Root: file:///svnroot/asm -Repository UUID: 271bd773-ee82-43a6-9b2b-1890ed8ce7f9 -Revision: 1795 -Node Kind: directory -Schedule: normal -Last Changed Author: ebruneton -Last Changed Rev: 1795 -Last Changed Date: 2016-01-24 14:17:10 +0100 (Sun, 24 Jan 2016) +ASM_6_0-11-gac81f5f +origin https://gitlab.ow2.org/asm/asm.git (fetch) +ac81f5f Merge branch 'add-class-dump-tool-for-unit-tests' into 'master' --- old/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModulesPlugin.java Fri Oct 27 09:25:10 2017 +++ new/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModulesPlugin.java Fri Oct 27 09:25:09 2017 @@ -58,8 +58,6 @@ import java.util.stream.Collectors; import jdk.internal.module.Checks; -import jdk.internal.module.ClassFileAttributes; -import jdk.internal.module.ClassFileConstants; import jdk.internal.module.DefaultRoots; import jdk.internal.module.IllegalAccessMaps; import jdk.internal.module.ModuleHashes; @@ -68,13 +66,13 @@ import jdk.internal.module.ModuleReferenceImpl; import jdk.internal.module.ModuleResolution; import jdk.internal.module.ModuleTarget; -import jdk.internal.org.objectweb.asm.Attribute; + import jdk.internal.org.objectweb.asm.ClassReader; import jdk.internal.org.objectweb.asm.ClassVisitor; import jdk.internal.org.objectweb.asm.ClassWriter; import jdk.internal.org.objectweb.asm.MethodVisitor; +import jdk.internal.org.objectweb.asm.ModuleVisitor; import jdk.internal.org.objectweb.asm.Opcodes; - import static jdk.internal.org.objectweb.asm.Opcodes.*; import jdk.tools.jlink.internal.ModuleSorter; @@ -435,24 +433,25 @@ } boolean hasModulePackages() throws IOException { - Set attrTypes = new HashSet<>(); - ClassVisitor cv = new ClassVisitor(Opcodes.ASM5) { + Set packages = new HashSet<>(); + ClassVisitor cv = new ClassVisitor(Opcodes.ASM6) { @Override - public void visitAttribute(Attribute attr) { - attrTypes.add(attr.type); + public ModuleVisitor visitModule(String name, + int flags, + String version) { + return new ModuleVisitor(Opcodes.ASM6) { + public void visitPackage(String pn) { + packages.add(pn); + } + }; } }; - // prototype of attributes that should be parsed - Attribute[] attrs = new Attribute[] { - new ClassFileAttributes.ModulePackagesAttribute() - }; - try (InputStream in = getInputStream()) { // parse module-info.class ClassReader cr = new ClassReader(in); - cr.accept(cv, attrs, 0); - return attrTypes.contains(ClassFileConstants.MODULE_PACKAGES); + cr.accept(cv, 0); + return packages.size() > 0; } } --- old/test/hotspot/jtreg/runtime/constantPool/ConstModule.java Fri Oct 27 09:25:11 2017 +++ new/test/hotspot/jtreg/runtime/constantPool/ConstModule.java Fri Oct 27 09:25:11 2017 @@ -47,13 +47,13 @@ // Test that the JVM throws CFE for constant pool CONSTANT_Module type, for // class file version 53, when ACC_MODULE is not set in the access_flags. - ConstModule.write_and_load(Opcodes.V1_9, + ConstModule.write_and_load(Opcodes.V9, Opcodes.ACC_INTERFACE + Opcodes.ACC_ABSTRACT + Opcodes.ACC_SYNTHETIC, "jdk.fooMod", "FooMod", MODULE_TEST, CFE_EXCEPTION); // Test that the JVM throws NCDFE for constant pool CONSTANT_Module type, // for class file version 53, when ACC_MODULE is set in the access_flags. - ConstModule.write_and_load(Opcodes.V1_9, + ConstModule.write_and_load(Opcodes.V9, Opcodes.ACC_INTERFACE + Opcodes.ACC_ABSTRACT + Opcodes.ACC_SYNTHETIC + ACC_MODULE, "jdk.fooModACC", "FooModACC", MODULE_TEST, NCDFE_EXCEPTION); @@ -65,13 +65,13 @@ // Test that the JVM throws CFE for constant pool CONSTANT_Package type, for // class file version 53, when ACC_MODULE is not set in the access_flags. - ConstModule.write_and_load(Opcodes.V1_9, + ConstModule.write_and_load(Opcodes.V9, Opcodes.ACC_INTERFACE + Opcodes.ACC_ABSTRACT + Opcodes.ACC_SYNTHETIC, "jdk.fooPkg", "FooPkg", PACKAGE_TEST, CFE_EXCEPTION); // Test that the JVM throws NCDFE for constant pool CONSTANT_Package type, // for class file version 53, when ACC_MODULE is set in the access_flags. - ConstModule.write_and_load(Opcodes.V1_9, + ConstModule.write_and_load(Opcodes.V9, Opcodes.ACC_INTERFACE + Opcodes.ACC_ABSTRACT + Opcodes.ACC_SYNTHETIC + ACC_MODULE, "jdk.fooModACC", "FooModACC", PACKAGE_TEST, NCDFE_EXCEPTION); --- old/test/jdk/java/lang/ModuleTests/AnnotationsTest.java Fri Oct 27 09:25:13 2017 +++ new/test/jdk/java/lang/ModuleTests/AnnotationsTest.java Fri Oct 27 09:25:13 2017 @@ -34,7 +34,6 @@ import java.util.List; import java.util.Set; -import jdk.internal.module.ClassFileAttributes; import jdk.internal.org.objectweb.asm.AnnotationVisitor; import jdk.internal.org.objectweb.asm.Attribute; import jdk.internal.org.objectweb.asm.ClassReader; @@ -41,6 +40,7 @@ import jdk.internal.org.objectweb.asm.ClassVisitor; import jdk.internal.org.objectweb.asm.ClassWriter; import jdk.internal.org.objectweb.asm.Opcodes; +import jdk.internal.org.objectweb.asm.commons.ModuleTargetAttribute; import org.testng.annotations.Test; import static org.testng.Assert.*; @@ -48,6 +48,7 @@ /** * @test * @modules java.base/jdk.internal.org.objectweb.asm + * java.base/jdk.internal.org.objectweb.asm.commons * java.base/jdk.internal.module * java.xml * @run testng AnnotationsTest @@ -113,14 +114,11 @@ ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES); - ClassVisitor cv = new ClassVisitor(Opcodes.ASM5, cw) { }; + ClassVisitor cv = new ClassVisitor(Opcodes.ASM6, cw) { }; ClassReader cr = new ClassReader(in); - List attrs = new ArrayList<>(); - attrs.add(new ClassFileAttributes.ModuleAttribute()); - attrs.add(new ClassFileAttributes.ModulePackagesAttribute()); - attrs.add(new ClassFileAttributes.ModuleTargetAttribute()); + attrs.add(new ModuleTargetAttribute()); cr.accept(cv, attrs.toArray(new Attribute[0]), 0); AnnotationVisitor annotationVisitor --- old/test/jdk/java/lang/invoke/DefineClassTest.java Fri Oct 27 09:25:15 2017 +++ new/test/jdk/java/lang/invoke/DefineClassTest.java Fri Oct 27 09:25:14 2017 @@ -243,7 +243,7 @@ byte[] generateClass(String className) { ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES); - cw.visit(V1_9, + cw.visit(V9, ACC_PUBLIC + ACC_SUPER, className.replace(".", "/"), null, @@ -272,7 +272,7 @@ ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES); - cw.visit(V1_9, + cw.visit(V9, ACC_PUBLIC + ACC_SUPER, className.replace(".", "/"), null, @@ -309,7 +309,7 @@ ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES); - cw.visit(V1_9, + cw.visit(V9, ACC_PUBLIC + ACC_SUPER, className.replace(".", "/"), null, --- old/test/jdk/java/util/ServiceLoader/BadProvidersTest.java Fri Oct 27 09:25:16 2017 +++ new/test/jdk/java/util/ServiceLoader/BadProvidersTest.java Fri Oct 27 09:25:16 2017 @@ -209,7 +209,7 @@ ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES); - cw.visit(V1_9, + cw.visit(V9, ACC_PUBLIC + ACC_SUPER, "p/ProviderFactory", null, --- old/test/jdk/lib/testlibrary/ModuleTargetHelper.java Fri Oct 27 09:25:18 2017 +++ new/test/jdk/lib/testlibrary/ModuleTargetHelper.java Fri Oct 27 09:25:17 2017 @@ -29,14 +29,10 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import jdk.internal.module.ClassFileConstants; -import jdk.internal.module.ClassFileAttributes; -import jdk.internal.module.ClassFileAttributes.ModuleTargetAttribute; -import jdk.internal.org.objectweb.asm.Attribute; -import jdk.internal.org.objectweb.asm.ClassReader; -import jdk.internal.org.objectweb.asm.ClassVisitor; -import jdk.internal.org.objectweb.asm.Opcodes; +import jdk.internal.module.ModuleInfo; +import jdk.internal.module.ModuleInfo.Attributes; + public class ModuleTargetHelper { private ModuleTargetHelper() {} @@ -60,29 +56,12 @@ } public static ModuleTarget read(InputStream in) throws IOException { - ModuleTargetAttribute[] modTargets = new ModuleTargetAttribute[1]; - ClassVisitor cv = new ClassVisitor(Opcodes.ASM5) { - @Override - public void visitAttribute(Attribute attr) { - if (attr instanceof ModuleTargetAttribute) { - modTargets[0] = (ModuleTargetAttribute)attr; - } - } - }; - - // prototype of attributes that should be parsed - Attribute[] attrs = new Attribute[] { - new ModuleTargetAttribute() - }; - - // parse module-info.class - ClassReader cr = new ClassReader(in); - cr.accept(cv, attrs, 0); - if (modTargets[0] != null) { - return new ModuleTarget(modTargets[0].targetPlatform()); + ModuleInfo.Attributes attrs = ModuleInfo.read(in, null); + if (attrs.target() != null) { + return new ModuleTarget(attrs.target().targetPlatform()); + } else { + return null; } - - return null; } public static ModuleTarget read(ModuleReference modRef) throws IOException { --- old/test/jdk/tools/jlink/plugins/SystemModuleDescriptors/src/m1/p1/Main.java Fri Oct 27 09:25:19 2017 +++ new/test/jdk/tools/jlink/plugins/SystemModuleDescriptors/src/m1/p1/Main.java Fri Oct 27 09:25:19 2017 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,35 +34,13 @@ import java.util.Collections; import java.util.Set; -import jdk.internal.module.ClassFileAttributes; -import jdk.internal.module.ClassFileAttributes.ModuleTargetAttribute; -import jdk.internal.module.ClassFileConstants; -import jdk.internal.org.objectweb.asm.Attribute; -import jdk.internal.org.objectweb.asm.ClassReader; -import jdk.internal.org.objectweb.asm.ClassVisitor; -import jdk.internal.org.objectweb.asm.Opcodes; +import jdk.internal.module.ModuleInfo; +import jdk.internal.module.ModuleInfo.Attributes; public class Main { private static boolean hasModuleTarget(InputStream in) throws IOException { - ModuleTargetAttribute[] modTargets = new ModuleTargetAttribute[1]; - ClassVisitor cv = new ClassVisitor(Opcodes.ASM5) { - @Override - public void visitAttribute(Attribute attr) { - if (attr instanceof ModuleTargetAttribute) { - modTargets[0] = (ModuleTargetAttribute)attr; - } - } - }; - - // prototype of attributes that should be parsed - Attribute[] attrs = new Attribute[] { - new ModuleTargetAttribute() - }; - - // parse module-info.class - ClassReader cr = new ClassReader(in); - cr.accept(cv, attrs, 0); - return modTargets[0] != null && modTargets[0].targetPlatform() != null; + ModuleInfo.Attributes attrs = ModuleInfo.read(in, null); + return attrs.target() != null; } public static void main(String... args) throws Exception { --- old/test/jdk/tools/jlink/plugins/SystemModuleDescriptors/src/m4/p4/Main.java Fri Oct 27 09:25:21 2017 +++ new/test/jdk/tools/jlink/plugins/SystemModuleDescriptors/src/m4/p4/Main.java Fri Oct 27 09:25:21 2017 @@ -35,35 +35,13 @@ import java.util.Map; import java.util.Set; -import jdk.internal.module.ClassFileAttributes; -import jdk.internal.module.ClassFileAttributes.ModuleTargetAttribute; -import jdk.internal.module.ClassFileConstants; -import jdk.internal.org.objectweb.asm.Attribute; -import jdk.internal.org.objectweb.asm.ClassReader; -import jdk.internal.org.objectweb.asm.ClassVisitor; -import jdk.internal.org.objectweb.asm.Opcodes; +import jdk.internal.module.ModuleInfo; +import jdk.internal.module.ModuleInfo.Attributes; public class Main { private static boolean hasModuleTarget(InputStream in) throws IOException { - ModuleTargetAttribute[] modTargets = new ModuleTargetAttribute[1]; - ClassVisitor cv = new ClassVisitor(Opcodes.ASM5) { - @Override - public void visitAttribute(Attribute attr) { - if (attr instanceof ModuleTargetAttribute) { - modTargets[0] = (ModuleTargetAttribute)attr; - } - } - }; - - // prototype of attributes that should be parsed - Attribute[] attrs = new Attribute[] { - new ModuleTargetAttribute() - }; - - // parse module-info.class - ClassReader cr = new ClassReader(in); - cr.accept(cv, attrs, 0); - return modTargets[0] != null && modTargets[0].targetPlatform() != null; + ModuleInfo.Attributes attrs = ModuleInfo.read(in, null); + return attrs.target() != null; } private static boolean hasModuleTarget(String modName) throws IOException { --- /dev/null Fri Oct 27 09:25:23 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/CurrentFrame.java Fri Oct 27 09:25:22 2017 @@ -0,0 +1,85 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * 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 jdk.internal.org.objectweb.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; + } +} --- /dev/null Fri Oct 27 09:25:25 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ModuleVisitor.java Fri Oct 27 09:25:24 2017 @@ -0,0 +1,219 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * 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 jdk.internal.org.objectweb.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(); + } + } +} --- /dev/null Fri Oct 27 09:25:26 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ModuleWriter.java Fri Oct 27 09:25:25 2017 @@ -0,0 +1,322 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * 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 jdk.internal.org.objectweb.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); + } + } +} --- /dev/null Fri Oct 27 09:25:28 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/ModuleHashesAttribute.java Fri Oct 27 09:25:27 2017 @@ -0,0 +1,155 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * 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 jdk.internal.org.objectweb.asm.commons; + +import java.util.ArrayList; +import java.util.List; + +import jdk.internal.org.objectweb.asm.Attribute; +import jdk.internal.org.objectweb.asm.ByteVector; +import jdk.internal.org.objectweb.asm.ClassReader; +import jdk.internal.org.objectweb.asm.ClassWriter; +import jdk.internal.org.objectweb.asm.Label; + +/** + * ModuleHashes attribute. + * This attribute is specific to the OpenJDK and may change in the future. + * + * @author Remi Forax + */ +public final class ModuleHashesAttribute extends Attribute { + public String algorithm; + public List modules; + public List hashes; + + /** + * Creates an attribute with a hashing algorithm, a list of module names, + * and a list of the same length of hashes. + * @param algorithm the hashing algorithm name. + * @param modules a list of module name + * @param hashes a list of hash, one for each module name. + */ + public ModuleHashesAttribute(final String algorithm, + final List modules, final List hashes) { + super("ModuleHashes"); + this.algorithm = algorithm; + this.modules = modules; + this.hashes = hashes; + } + + /** + * Creates an empty attribute that can be used as prototype + * to be passed as argument of the method + * {@link ClassReader#accept(org.objectweb.asm.ClassVisitor, Attribute[], int)}. + */ + public ModuleHashesAttribute() { + this(null, null, null); + } + + @Override + protected Attribute read(ClassReader cr, int off, int len, char[] buf, + int codeOff, Label[] labels) { + String hashAlgorithm = cr.readUTF8(off, buf); + + int count = cr.readUnsignedShort(off + 2); + ArrayList modules = new ArrayList(count); + ArrayList hashes = new ArrayList(count); + off += 4; + + for (int i = 0; i < count; i++) { + String module = cr.readModule(off, buf); + int hashLength = cr.readUnsignedShort(off + 2); + off += 4; + + byte[] hash = new byte[hashLength]; + for (int j = 0; j < hashLength; j++) { + hash[j] = (byte) (cr.readByte(off + j) & 0xff); + } + off += hashLength; + + modules.add(module); + hashes.add(hash); + } + return new ModuleHashesAttribute(hashAlgorithm, modules, hashes); + } + + @Override + protected ByteVector write(ClassWriter cw, byte[] code, int len, + int maxStack, int maxLocals) { + ByteVector v = new ByteVector(); + int index = cw.newUTF8(algorithm); + v.putShort(index); + + int count = (modules == null)? 0: modules.size(); + v.putShort(count); + + for(int i = 0; i < count; i++) { + String module = modules.get(i); + v.putShort(cw.newModule(module)); + + byte[] hash = hashes.get(i); + v.putShort(hash.length); + for(byte b: hash) { + v.putByte(b); + } + } + return v; + } +} --- /dev/null Fri Oct 27 09:25:29 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/ModuleRemapper.java Fri Oct 27 09:25:28 2017 @@ -0,0 +1,135 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * 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 jdk.internal.org.objectweb.asm.commons; + +import jdk.internal.org.objectweb.asm.ModuleVisitor; +import jdk.internal.org.objectweb.asm.Opcodes; + +/** + * A {@link ModuleVisitor} adapter for type remapping. + * + * @author Remi Forax + */ +public class ModuleRemapper extends ModuleVisitor { + private final Remapper remapper; + + public ModuleRemapper(final ModuleVisitor mv, final Remapper remapper) { + this(Opcodes.ASM6, mv, remapper); + } + + protected ModuleRemapper(final int api, final ModuleVisitor mv, + final Remapper remapper) { + super(api, mv); + this.remapper = remapper; + } + + @Override + public void visitMainClass(String mainClass) { + super.visitMainClass(remapper.mapType(mainClass)); + } + + @Override + public void visitPackage(String packaze) { + super.visitPackage(remapper.mapPackageName(packaze)); + } + + @Override + public void visitRequire(String module, int access, String version) { + super.visitRequire(remapper.mapModuleName(module), access, version); + } + + @Override + public void visitExport(String packaze, int access, String... modules) { + String[] newModules = null; + if (modules != null) { + newModules = new String[modules.length]; + for (int i = 0 ; i < modules.length; i++) { + newModules[i] = remapper.mapModuleName(modules[i]); + } + } + super.visitExport(remapper.mapPackageName(packaze), access, newModules); + } + + @Override + public void visitOpen(String packaze, int access, String... modules) { + String[] newModules = null; + if (modules != null) { + newModules = new String[modules.length]; + for (int i = 0 ; i < modules.length; i++) { + newModules[i] = remapper.mapModuleName(modules[i]); + } + } + super.visitOpen(remapper.mapPackageName(packaze), access, newModules); + } + + @Override + public void visitUse(String service) { + super.visitUse(remapper.mapType(service)); + } + + @Override + public void visitProvide(String service, String... providers) { + String[] newProviders = new String[providers.length]; + for (int i = 0 ; i < providers.length; i++) { + newProviders[i] = remapper.mapType(providers[i]); + } + super.visitProvide(remapper.mapType(service), newProviders); + } +} --- /dev/null Fri Oct 27 09:25:31 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/ModuleResolutionAttribute.java Fri Oct 27 09:25:30 2017 @@ -0,0 +1,135 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * 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 jdk.internal.org.objectweb.asm.commons; + +import jdk.internal.org.objectweb.asm.Attribute; +import jdk.internal.org.objectweb.asm.ByteVector; +import jdk.internal.org.objectweb.asm.ClassReader; +import jdk.internal.org.objectweb.asm.ClassWriter; +import jdk.internal.org.objectweb.asm.Label; + +/** + * ModuleResolution_attribute. + * This attribute is specific to the OpenJDK and may change in the future. + * + * @author Remi Forax + */ +public final class ModuleResolutionAttribute extends Attribute { + /** + * Resolution state of a module meaning that the module is not available + * from the class-path by default. + */ + public static final int RESOLUTION_DO_NOT_RESOLVE_BY_DEFAULT = 1; + + /** + * Resolution state of a module meaning the module is marked as deprecated. + */ + public static final int RESOLUTION_WARN_DEPRECATED = 2; + + /** + * Resolution state of a module meaning the module is marked as deprecated + * and will be removed in a future release. + */ + public static final int RESOLUTION_WARN_DEPRECATED_FOR_REMOVAL = 4; + + /** + * Resolution state of a module meaning the module is not yet standardized, + * so in incubating mode. + */ + public static final int RESOLUTION_WARN_INCUBATING = 8; + + public int resolution; + + /** + * Creates an attribute with a resolution state value. + * @param resolution the resolution state among + * {@link #RESOLUTION_WARN_DEPRECATED}, + * {@link #RESOLUTION_WARN_DEPRECATED_FOR_REMOVAL}, and + * {@link #RESOLUTION_WARN_INCUBATING}. + */ + public ModuleResolutionAttribute(final int resolution) { + super("ModuleResolution"); + this.resolution = resolution; + } + + /** + * Creates an empty attribute that can be used as prototype + * to be passed as argument of the method + * {@link ClassReader#accept(org.objectweb.asm.ClassVisitor, Attribute[], int)}. + */ + public ModuleResolutionAttribute() { + this(0); + } + + @Override + protected Attribute read(ClassReader cr, int off, int len, char[] buf, + int codeOff, Label[] labels) { + int resolution = cr.readUnsignedShort(off); + return new ModuleResolutionAttribute(resolution); + } + + @Override + protected ByteVector write(ClassWriter cw, byte[] code, int len, + int maxStack, int maxLocals) { + ByteVector v = new ByteVector(); + v.putShort(resolution); + return v; + } +} --- /dev/null Fri Oct 27 09:25:32 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/ModuleTargetAttribute.java Fri Oct 27 09:25:32 2017 @@ -0,0 +1,110 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * 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 jdk.internal.org.objectweb.asm.commons; + +import jdk.internal.org.objectweb.asm.Attribute; +import jdk.internal.org.objectweb.asm.ByteVector; +import jdk.internal.org.objectweb.asm.ClassReader; +import jdk.internal.org.objectweb.asm.ClassWriter; +import jdk.internal.org.objectweb.asm.Label; + +/** + * ModuleTarget attribute. + * This attribute is specific to the OpenJDK and may change in the future. + * + * @author Remi Forax + */ +public final class ModuleTargetAttribute extends Attribute { + public String platform; + + /** + * Creates an attribute with a platform name. + * @param platform the platform name on which the module can run. + */ + public ModuleTargetAttribute(final String platform) { + super("ModuleTarget"); + this.platform = platform; + } + + /** + * Creates an empty attribute that can be used as prototype + * to be passed as argument of the method + * {@link ClassReader#accept(org.objectweb.asm.ClassVisitor, Attribute[], int)}. + */ + public ModuleTargetAttribute() { + this(null); + } + + @Override + protected Attribute read(ClassReader cr, int off, int len, char[] buf, + int codeOff, Label[] labels) { + String platform = cr.readUTF8(off, buf); + return new ModuleTargetAttribute(platform); + } + + @Override + protected ByteVector write(ClassWriter cw, byte[] code, int len, + int maxStack, int maxLocals) { + ByteVector v = new ByteVector(); + int index = (platform == null)? 0: cw.newUTF8(platform); + v.putShort(index); + return v; + } +} --- /dev/null Fri Oct 27 09:25:34 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/tree/ModuleExportNode.java Fri Oct 27 09:25:33 2017 @@ -0,0 +1,111 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * 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 jdk.internal.org.objectweb.asm.tree; + +import java.util.List; + +import jdk.internal.org.objectweb.asm.ModuleVisitor; + +/** + * A node that represents an exported package with its name and the module that can access to it. + * + * @author Remi Forax + */ +public class ModuleExportNode { + /** + * The package name. + */ + public String packaze; + + /** + * The access flags (see {@link jdk.internal.org.objectweb.asm.Opcodes}). + * Valid values are {@code ACC_SYNTHETIC} and {@code ACC_MANDATED}. + */ + public int access; + + /** + * A list of modules that can access to this exported package. + * May be null. + */ + public List modules; + + /** + * Constructs a new {@link ModuleExportNode}. + * + * @param packaze + * the parameter's name. + * @param modules + * a list of modules that can access to this exported package. + */ + public ModuleExportNode(final String packaze, final int access, final List modules) { + this.packaze = packaze; + this.access = access; + this.modules = modules; + } + + /** + * Makes the given module visitor visit this export declaration. + * + * @param mv + * a module visitor. + */ + public void accept(final ModuleVisitor mv) { + mv.visitExport(packaze, access, (modules == null) ? null : modules.toArray(new String[0])); + } +} --- /dev/null Fri Oct 27 09:25:36 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/tree/ModuleNode.java Fri Oct 27 09:25:35 2017 @@ -0,0 +1,280 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * 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 jdk.internal.org.objectweb.asm.tree; + +import java.util.ArrayList; +import java.util.List; + +import jdk.internal.org.objectweb.asm.ClassVisitor; +import jdk.internal.org.objectweb.asm.ModuleVisitor; +import jdk.internal.org.objectweb.asm.Opcodes; + +/** + * A node that represents a module declaration. + * + * @author Remi Forax + */ +public class ModuleNode extends ModuleVisitor { + /** + * Module name + */ + public String name; + + /** + * Module access flags, among {@code ACC_OPEN}, {@code ACC_SYNTHETIC} + * and {@code ACC_MANDATED}. + */ + public int access; + + /** + * Version of the module. + * May be null. + */ + public String version; + + /** + * Name of the main class in internal form + * May be null. + */ + public String mainClass; + + /** + * A list of packages that are declared by the current module. + * May be null. + */ + public List packages; + + /** + * A list of modules can are required by the current module. + * May be null. + */ + public List requires; + + /** + * A list of packages that are exported by the current module. + * May be null. + */ + public List exports; + + /** + * A list of packages that are opened by the current module. + * May be null. + */ + public List opens; + + /** + * A list of classes in their internal forms that are used + * as a service by the current module. May be null. + */ + public List uses; + + /** + * A list of services along with their implementations provided + * by the current module. May be null. + */ + public List provides; + + public ModuleNode(final String name, final int access, + final String version) { + super(Opcodes.ASM6); + this.name = name; + this.access = access; + this.version = version; + } + + public ModuleNode(final int api, + final String name, + final int access, + final String version, + final List requires, + final List exports, + final List opens, + final List uses, + final List provides) { + super(api); + this.name = name; + this.access = access; + this.version = version; + this.requires = requires; + this.exports = exports; + this.opens = opens; + this.uses = uses; + this.provides = provides; + if (getClass() != ModuleNode.class) { + throw new IllegalStateException(); + } + } + + @Override + public void visitMainClass(String mainClass) { + this.mainClass = mainClass; + } + + @Override + public void visitPackage(String packaze) { + if (packages == null) { + packages = new ArrayList(5); + } + packages.add(packaze); + } + + @Override + public void visitRequire(String module, int access, String version) { + if (requires == null) { + requires = new ArrayList(5); + } + requires.add(new ModuleRequireNode(module, access, version)); + } + + @Override + public void visitExport(String packaze, int access, String... modules) { + if (exports == null) { + exports = new ArrayList(5); + } + List moduleList = null; + if (modules != null) { + moduleList = new ArrayList(modules.length); + for (int i = 0; i < modules.length; i++) { + moduleList.add(modules[i]); + } + } + exports.add(new ModuleExportNode(packaze, access, moduleList)); + } + + @Override + public void visitOpen(String packaze, int access, String... modules) { + if (opens == null) { + opens = new ArrayList(5); + } + List moduleList = null; + if (modules != null) { + moduleList = new ArrayList(modules.length); + for (int i = 0; i < modules.length; i++) { + moduleList.add(modules[i]); + } + } + opens.add(new ModuleOpenNode(packaze, access, moduleList)); + } + + @Override + public void visitUse(String service) { + if (uses == null) { + uses = new ArrayList(5); + } + uses.add(service); + } + + @Override + public void visitProvide(String service, String... providers) { + if (provides == null) { + provides = new ArrayList(5); + } + ArrayList providerList = + new ArrayList(providers.length); + for (int i = 0; i < providers.length; i++) { + providerList.add(providers[i]); + } + provides.add(new ModuleProvideNode(service, providerList)); + } + + @Override + public void visitEnd() { + } + + public void accept(final ClassVisitor cv) { + ModuleVisitor mv = cv.visitModule(name, access, version); + if (mv == null) { + return; + } + if (mainClass != null) { + mv.visitMainClass(mainClass); + } + if (packages != null) { + for (int i = 0; i < packages.size(); i++) { + mv.visitPackage(packages.get(i)); + } + } + + if (requires != null) { + for (int i = 0; i < requires.size(); i++) { + requires.get(i).accept(mv); + } + } + if (exports != null) { + for (int i = 0; i < exports.size(); i++) { + exports.get(i).accept(mv); + } + } + if (opens != null) { + for (int i = 0; i < opens.size(); i++) { + opens.get(i).accept(mv); + } + } + if (uses != null) { + for (int i = 0; i < uses.size(); i++) { + mv.visitUse(uses.get(i)); + } + } + if (provides != null) { + for (int i = 0; i < provides.size(); i++) { + provides.get(i).accept(mv); + } + } + } +} --- /dev/null Fri Oct 27 09:25:37 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/tree/ModuleOpenNode.java Fri Oct 27 09:25:37 2017 @@ -0,0 +1,111 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * 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 jdk.internal.org.objectweb.asm.tree; + +import java.util.List; + +import jdk.internal.org.objectweb.asm.ModuleVisitor; + +/** + * A node that represents an opened package with its name and the module that can access to it. + * + * @author Remi Forax + */ +public class ModuleOpenNode { + /** + * The package name. + */ + public String packaze; + + /** + * The access flags (see {@link jdk.internal.org.objectweb.asm.Opcodes}). + * Valid values are {@code ACC_SYNTHETIC} and {@code ACC_MANDATED}. + */ + public int access; + + /** + * A list of modules that can access to this exported package. + * May be null. + */ + public List modules; + + /** + * Constructs a new {@link ModuleOpenNode}. + * + * @param packaze + * the parameter's name. + * @param modules + * a list of modules that can access to this open package. + */ + public ModuleOpenNode(final String packaze, final int access, final List modules) { + this.packaze = packaze; + this.access = access; + this.modules = modules; + } + + /** + * Makes the given module visitor visit this open declaration. + * + * @param mv + * a module visitor. + */ + public void accept(final ModuleVisitor mv) { + mv.visitExport(packaze, access, (modules == null) ? null : modules.toArray(new String[0])); + } +} --- /dev/null Fri Oct 27 09:25:39 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/tree/ModuleProvideNode.java Fri Oct 27 09:25:38 2017 @@ -0,0 +1,103 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * 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 jdk.internal.org.objectweb.asm.tree; + +import java.util.List; + +import jdk.internal.org.objectweb.asm.ModuleVisitor; + +/** + * A node that represents a service and its implementation provided by the current module. + * + * @author Remi Forax + */ +public class ModuleProvideNode { + /** + * The service name (in its internal form). + */ + public String service; + + /** + * The service provider names (in their internal form). + */ + public List providers; + + /** + * Constructs a new {@link ModuleProvideNode}. + * + * @param service + * the service name (in its internal form). + * @param providers + * the service provider names (in their internal form). + */ + public ModuleProvideNode(final String service, final List providers) { + this.service = service; + this.providers = providers; + } + + /** + * Makes the given module visitor visit this require declaration. + * + * @param mv + * a module visitor. + */ + public void accept(final ModuleVisitor mv) { + mv.visitProvide(service, providers.toArray(new String[0])); + } +} --- /dev/null Fri Oct 27 09:25:41 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/tree/ModuleRequireNode.java Fri Oct 27 09:25:40 2017 @@ -0,0 +1,116 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * 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 jdk.internal.org.objectweb.asm.tree; + +import jdk.internal.org.objectweb.asm.ModuleVisitor; + +/** + * A node that represents a required module with its name and access of a module descriptor. + * + * @author Remi Forax + */ +public class ModuleRequireNode { + /** + * The name of the required module. + */ + public String module; + + /** + * The access flags (see {@link jdk.internal.org.objectweb.asm.Opcodes}). + * Valid values are ACC_TRANSITIVE, ACC_STATIC_PHASE, + * ACC_SYNTHETIC and ACC_MANDATED. + */ + public int access; + + /** + * Version at compile time of the required module or null. + */ + public String version; + + /** + * Constructs a new {@link ModuleRequireNode}. + * + * @param module + * the name of the required module. + * @param access + * The access flags. Valid values are + * ACC_TRANSITIVE, ACC_STATIC_PHASE, + * ACC_SYNTHETIC and ACC_MANDATED + * (see {@link jdk.internal.org.objectweb.asm.Opcodes}). + * @param version + * Version of the required module at compile time, + * null if not defined. + */ + public ModuleRequireNode(final String module, final int access, + final String version) { + this.module = module; + this.access = access; + this.version = version; + } + + /** + * Makes the given module visitor visit this require directive. + * + * @param mv + * a module visitor. + */ + public void accept(final ModuleVisitor mv) { + mv.visitRequire(module, access, version); + } +} --- /dev/null Fri Oct 27 09:25:42 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/CheckModuleAdapter.java Fri Oct 27 09:25:42 2017 @@ -0,0 +1,180 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * 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 jdk.internal.org.objectweb.asm.util; + +import java.util.HashSet; + +import jdk.internal.org.objectweb.asm.ModuleVisitor; +import jdk.internal.org.objectweb.asm.Opcodes; + +/** + * @author Remi Forax + */ +public final class CheckModuleAdapter extends ModuleVisitor { + private boolean end; + private final boolean isOpen; + + private final HashSet requireNames = new HashSet(); + private final HashSet exportNames = new HashSet(); + private final HashSet openNames = new HashSet(); + private final HashSet useNames = new HashSet(); + private final HashSet provideNames = new HashSet(); + + public CheckModuleAdapter(final ModuleVisitor mv, final boolean isOpen) { + super(Opcodes.ASM6, mv); + this.isOpen = isOpen; + } + + @Override + public void visitRequire(String module, int access, String version) { + checkEnd(); + if (module == null) { + throw new IllegalArgumentException("require cannot be null"); + } + checkDeclared("requires", requireNames, module); + CheckClassAdapter.checkAccess(access, Opcodes.ACC_STATIC_PHASE + + Opcodes.ACC_TRANSITIVE + Opcodes.ACC_SYNTHETIC + Opcodes.ACC_MANDATED); + super.visitRequire(module, access, version); + } + + @Override + public void visitExport(String packaze, int access, String... modules) { + checkEnd(); + if (packaze == null) { + throw new IllegalArgumentException("packaze cannot be null"); + } + CheckMethodAdapter.checkInternalName(packaze, "package name"); + checkDeclared("exports", exportNames, packaze); + CheckClassAdapter.checkAccess(access, Opcodes.ACC_SYNTHETIC + + Opcodes.ACC_MANDATED); + if (modules != null) { + for (int i = 0; i < modules.length; i++) { + if (modules[i] == null) { + throw new IllegalArgumentException("module at index " + i + " cannot be null"); + } + } + } + super.visitExport(packaze, access, modules); + } + + @Override + public void visitOpen(String packaze, int access, String... modules) { + checkEnd(); + if (isOpen) { + throw new IllegalArgumentException("an open module can not use open directive"); + } + if (packaze == null) { + throw new IllegalArgumentException("packaze cannot be null"); + } + CheckMethodAdapter.checkInternalName(packaze, "package name"); + checkDeclared("opens", openNames, packaze); + CheckClassAdapter.checkAccess(access, Opcodes.ACC_SYNTHETIC + + Opcodes.ACC_MANDATED); + if (modules != null) { + for (int i = 0; i < modules.length; i++) { + if (modules[i] == null) { + throw new IllegalArgumentException("module at index " + i + " cannot be null"); + } + } + } + super.visitOpen(packaze, access, modules); + } + + @Override + public void visitUse(String service) { + checkEnd(); + CheckMethodAdapter.checkInternalName(service, "service"); + checkDeclared("uses", useNames, service); + super.visitUse(service); + } + + @Override + public void visitProvide(String service, String... providers) { + checkEnd(); + CheckMethodAdapter.checkInternalName(service, "service"); + checkDeclared("provides", provideNames, service); + if (providers == null || providers.length == 0) { + throw new IllegalArgumentException("providers cannot be null or empty"); + } + for (int i = 0; i < providers.length; i++) { + CheckMethodAdapter.checkInternalName(providers[i], "provider"); + } + super.visitProvide(service, providers); + } + + @Override + public void visitEnd() { + checkEnd(); + end = true; + super.visitEnd(); + } + + private void checkEnd() { + if (end) { + throw new IllegalStateException( + "Cannot call a visit method after visitEnd has been called"); + } + } + + private static void checkDeclared(String directive, HashSet names, String name) { + if (!names.add(name)) { + throw new IllegalArgumentException(directive + " " + name + " already declared"); + } + } +} --- /dev/null Fri Oct 27 09:25:44 2017 +++ new/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/TraceModuleVisitor.java Fri Oct 27 09:25:43 2017 @@ -0,0 +1,130 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * 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 jdk.internal.org.objectweb.asm.util; + +import jdk.internal.org.objectweb.asm.ModuleVisitor; +import jdk.internal.org.objectweb.asm.Opcodes; + +/** + * A {@link ModuleVisitor} that prints the fields it visits with a + * {@link Printer}. + * + * @author Remi Forax + */ +public final class TraceModuleVisitor extends ModuleVisitor { + + public final Printer p; + + public TraceModuleVisitor(final Printer p) { + this(null, p); + } + + public TraceModuleVisitor(final ModuleVisitor mv, final Printer p) { + super(Opcodes.ASM6, mv); + this.p = p; + } + + @Override + public void visitMainClass(String mainClass) { + p.visitMainClass(mainClass); + super.visitMainClass(mainClass); + } + + @Override + public void visitPackage(String packaze) { + p.visitPackage(packaze); + super.visitPackage(packaze); + } + + @Override + public void visitRequire(String module, int access, String version) { + p.visitRequire(module, access, version); + super.visitRequire(module, access, version); + } + + @Override + public void visitExport(String packaze, int access, String... modules) { + p.visitExport(packaze, access, modules); + super.visitExport(packaze, access, modules); + } + + @Override + public void visitOpen(String packaze, int access, String... modules) { + p.visitOpen(packaze, access, modules); + super.visitOpen(packaze, access, modules); + } + + @Override + public void visitUse(String use) { + p.visitUse(use); + super.visitUse(use); + } + + @Override + public void visitProvide(String service, String... providers) { + p.visitProvide(service, providers); + super.visitProvide(service, providers); + } + + @Override + public void visitEnd() { + p.visitModuleEnd(); + super.visitEnd(); + } +} --- old/src/java.base/share/classes/jdk/internal/module/ClassFileAttributes.java Fri Oct 27 09:25:45 2017 +++ /dev/null Fri Oct 27 09:25:45 2017 @@ -1,765 +0,0 @@ -/* - * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.internal.module; - -import java.lang.module.ModuleDescriptor; -import java.lang.module.ModuleDescriptor.Builder; -import java.lang.module.ModuleDescriptor.Requires; -import java.lang.module.ModuleDescriptor.Exports; -import java.lang.module.ModuleDescriptor.Opens; -import java.lang.module.ModuleDescriptor.Provides; -import java.lang.module.ModuleDescriptor.Version; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import jdk.internal.misc.JavaLangModuleAccess; -import jdk.internal.misc.SharedSecrets; -import jdk.internal.org.objectweb.asm.Attribute; -import jdk.internal.org.objectweb.asm.ByteVector; -import jdk.internal.org.objectweb.asm.ClassReader; -import jdk.internal.org.objectweb.asm.ClassWriter; -import jdk.internal.org.objectweb.asm.Label; -import static jdk.internal.module.ClassFileConstants.*; - - -/** - * Provides ASM implementations of {@code Attribute} to read and write the - * class file attributes in a module-info class file. - */ - -public final class ClassFileAttributes { - - private ClassFileAttributes() { } - - /** - * Module_attribute { - * // See lang-vm.html for details. - * } - */ - public static class ModuleAttribute extends Attribute { - private static final JavaLangModuleAccess JLMA - = SharedSecrets.getJavaLangModuleAccess(); - - private ModuleDescriptor descriptor; - private Version replacementVersion; - - public ModuleAttribute(ModuleDescriptor descriptor) { - super(MODULE); - this.descriptor = descriptor; - } - - public ModuleAttribute(Version v) { - super(MODULE); - this.replacementVersion = v; - } - - public ModuleAttribute() { - super(MODULE); - } - - @Override - protected Attribute read(ClassReader cr, - int off, - int len, - char[] buf, - int codeOff, - Label[] labels) - { - // module_name (CONSTANT_Module_info) - String mn = cr.readModule(off, buf); - off += 2; - - // module_flags - int module_flags = cr.readUnsignedShort(off); - off += 2; - - Set modifiers = new HashSet<>(); - if ((module_flags & ACC_OPEN) != 0) - modifiers.add(ModuleDescriptor.Modifier.OPEN); - if ((module_flags & ACC_SYNTHETIC) != 0) - modifiers.add(ModuleDescriptor.Modifier.SYNTHETIC); - if ((module_flags & ACC_MANDATED) != 0) - modifiers.add(ModuleDescriptor.Modifier.MANDATED); - - Builder builder = JLMA.newModuleBuilder(mn, false, modifiers); - - // module_version - String module_version = cr.readUTF8(off, buf); - off += 2; - if (replacementVersion != null) { - builder.version(replacementVersion); - } else if (module_version != null) { - builder.version(module_version); - } - - // requires_count and requires[requires_count] - int requires_count = cr.readUnsignedShort(off); - off += 2; - for (int i=0; i mods; - if (requires_flags == 0) { - mods = Collections.emptySet(); - } else { - mods = new HashSet<>(); - if ((requires_flags & ACC_TRANSITIVE) != 0) - mods.add(Requires.Modifier.TRANSITIVE); - if ((requires_flags & ACC_STATIC_PHASE) != 0) - mods.add(Requires.Modifier.STATIC); - if ((requires_flags & ACC_SYNTHETIC) != 0) - mods.add(Requires.Modifier.SYNTHETIC); - if ((requires_flags & ACC_MANDATED) != 0) - mods.add(Requires.Modifier.MANDATED); - } - - // requires_version - String requires_version = cr.readUTF8(off, buf); - off += 2; - if (requires_version == null) { - builder.requires(mods, dn); - } else { - JLMA.requires(builder, mods, dn, requires_version); - } - } - - // exports_count and exports[exports_count] - int exports_count = cr.readUnsignedShort(off); - off += 2; - if (exports_count > 0) { - for (int i=0; i mods; - if (exports_flags == 0) { - mods = Collections.emptySet(); - } else { - mods = new HashSet<>(); - if ((exports_flags & ACC_SYNTHETIC) != 0) - mods.add(Exports.Modifier.SYNTHETIC); - if ((exports_flags & ACC_MANDATED) != 0) - mods.add(Exports.Modifier.MANDATED); - } - - int exports_to_count = cr.readUnsignedShort(off); - off += 2; - if (exports_to_count > 0) { - Set targets = new HashSet<>(); - for (int j=0; j 0) { - for (int i=0; i mods; - if (opens_flags == 0) { - mods = Collections.emptySet(); - } else { - mods = new HashSet<>(); - if ((opens_flags & ACC_SYNTHETIC) != 0) - mods.add(Opens.Modifier.SYNTHETIC); - if ((opens_flags & ACC_MANDATED) != 0) - mods.add(Opens.Modifier.MANDATED); - } - - int opens_to_count = cr.readUnsignedShort(off); - off += 2; - if (opens_to_count > 0) { - Set targets = new HashSet<>(); - for (int j=0; j 0) { - for (int i=0; i 0) { - for (int i=0; i providers = new ArrayList<>(); - for (int j=0; j modifiers = descriptor.modifiers(); - int module_flags = 0; - if (modifiers.contains(ModuleDescriptor.Modifier.OPEN)) - module_flags |= ACC_OPEN; - if (modifiers.contains(ModuleDescriptor.Modifier.SYNTHETIC)) - module_flags |= ACC_SYNTHETIC; - if (modifiers.contains(ModuleDescriptor.Modifier.MANDATED)) - module_flags |= ACC_MANDATED; - attr.putShort(module_flags); - - // module_version - String vs = descriptor.rawVersion().orElse(null); - if (vs == null) { - attr.putShort(0); - } else { - int module_version_index = cw.newUTF8(vs); - attr.putShort(module_version_index); - } - - // requires_count - attr.putShort(descriptor.requires().size()); - - // requires[requires_count] - for (Requires r : descriptor.requires()) { - int requires_index = cw.newModule(r.name()); - attr.putShort(requires_index); - - int requires_flags = 0; - if (r.modifiers().contains(Requires.Modifier.TRANSITIVE)) - requires_flags |= ACC_TRANSITIVE; - if (r.modifiers().contains(Requires.Modifier.STATIC)) - requires_flags |= ACC_STATIC_PHASE; - if (r.modifiers().contains(Requires.Modifier.SYNTHETIC)) - requires_flags |= ACC_SYNTHETIC; - if (r.modifiers().contains(Requires.Modifier.MANDATED)) - requires_flags |= ACC_MANDATED; - attr.putShort(requires_flags); - - int requires_version_index; - vs = r.rawCompiledVersion().orElse(null); - if (vs == null) { - requires_version_index = 0; - } else { - requires_version_index = cw.newUTF8(vs); - } - attr.putShort(requires_version_index); - } - - // exports_count and exports[exports_count]; - attr.putShort(descriptor.exports().size()); - for (Exports e : descriptor.exports()) { - String pkg = e.source().replace('.', '/'); - attr.putShort(cw.newPackage(pkg)); - - int exports_flags = 0; - if (e.modifiers().contains(Exports.Modifier.SYNTHETIC)) - exports_flags |= ACC_SYNTHETIC; - if (e.modifiers().contains(Exports.Modifier.MANDATED)) - exports_flags |= ACC_MANDATED; - attr.putShort(exports_flags); - - if (e.isQualified()) { - Set ts = e.targets(); - attr.putShort(ts.size()); - ts.forEach(target -> attr.putShort(cw.newModule(target))); - } else { - attr.putShort(0); - } - } - - // opens_counts and opens[opens_counts] - attr.putShort(descriptor.opens().size()); - for (Opens obj : descriptor.opens()) { - String pkg = obj.source().replace('.', '/'); - attr.putShort(cw.newPackage(pkg)); - - int opens_flags = 0; - if (obj.modifiers().contains(Opens.Modifier.SYNTHETIC)) - opens_flags |= ACC_SYNTHETIC; - if (obj.modifiers().contains(Opens.Modifier.MANDATED)) - opens_flags |= ACC_MANDATED; - attr.putShort(opens_flags); - - if (obj.isQualified()) { - Set ts = obj.targets(); - attr.putShort(ts.size()); - ts.forEach(target -> attr.putShort(cw.newModule(target))); - } else { - attr.putShort(0); - } - } - - // uses_count and uses_index[uses_count] - if (descriptor.uses().isEmpty()) { - attr.putShort(0); - } else { - attr.putShort(descriptor.uses().size()); - for (String s : descriptor.uses()) { - String service = s.replace('.', '/'); - int index = cw.newClass(service); - attr.putShort(index); - } - } - - // provides_count and provides[provides_count] - if (descriptor.provides().isEmpty()) { - attr.putShort(0); - } else { - attr.putShort(descriptor.provides().size()); - for (Provides p : descriptor.provides()) { - String service = p.service().replace('.', '/'); - attr.putShort(cw.newClass(service)); - int with_count = p.providers().size(); - attr.putShort(with_count); - for (String provider : p.providers()) { - attr.putShort(cw.newClass(provider.replace('.', '/'))); - } - } - } - - return attr; - } - } - - /** - * ModulePackages attribute. - * - *
 {@code
-     *
-     * ModulePackages_attribute {
-     *   // index to CONSTANT_utf8_info structure in constant pool representing
-     *   // the string "ModulePackages"
-     *   u2 attribute_name_index;
-     *   u4 attribute_length;
-     *
-     *   // the number of entries in the packages table
-     *   u2 packages_count;
-     *   { // index to CONSTANT_Package_info structure with the package name
-     *     u2 package_index
-     *   } packages[package_count];
-     *
-     * }
- */ - public static class ModulePackagesAttribute extends Attribute { - private final Set packages; - - public ModulePackagesAttribute(Set packages) { - super(MODULE_PACKAGES); - this.packages = packages; - } - - public ModulePackagesAttribute() { - this(null); - } - - @Override - protected Attribute read(ClassReader cr, - int off, - int len, - char[] buf, - int codeOff, - Label[] labels) - { - // package count - int package_count = cr.readUnsignedShort(off); - off += 2; - - // packages - Set packages = new HashSet<>(); - for (int i=0; i p.replace('.', '/')) - .forEach(p -> attr.putShort(cw.newPackage(p))); - - return attr; - } - - } - - /** - * ModuleMainClass attribute. - * - *
 {@code
-     *
-     * MainClass_attribute {
-     *   // index to CONSTANT_utf8_info structure in constant pool representing
-     *   // the string "ModuleMainClass"
-     *   u2 attribute_name_index;
-     *   u4 attribute_length;
-     *
-     *   // index to CONSTANT_Class_info structure with the main class name
-     *   u2 main_class_index;
-     * }
-     *
-     * } 
- */ - public static class ModuleMainClassAttribute extends Attribute { - private final String mainClass; - - public ModuleMainClassAttribute(String mainClass) { - super(MODULE_MAIN_CLASS); - this.mainClass = mainClass; - } - - public ModuleMainClassAttribute() { - this(null); - } - - @Override - protected Attribute read(ClassReader cr, - int off, - int len, - char[] buf, - int codeOff, - Label[] labels) - { - String value = cr.readClass(off, buf).replace('/', '.'); - return new ModuleMainClassAttribute(value); - } - - @Override - protected ByteVector write(ClassWriter cw, - byte[] code, - int len, - int maxStack, - int maxLocals) - { - ByteVector attr = new ByteVector(); - int index = cw.newClass(mainClass.replace('.', '/')); - attr.putShort(index); - return attr; - } - } - - /** - * ModuleTarget attribute. - * - *
 {@code
-     *
-     * TargetPlatform_attribute {
-     *   // index to CONSTANT_utf8_info structure in constant pool representing
-     *   // the string "ModuleTarget"
-     *   u2 attribute_name_index;
-     *   u4 attribute_length;
-     *
-     *   // index to CONSTANT_utf8_info structure with the target platform
-     *   u2 target_platform_index;
-     * }
-     *
-     * } 
- */ - public static class ModuleTargetAttribute extends Attribute { - private final String targetPlatform; - - public ModuleTargetAttribute(String targetPlatform) { - super(MODULE_TARGET); - this.targetPlatform = targetPlatform; - } - - public ModuleTargetAttribute() { - this(null); - } - - public String targetPlatform() { - return targetPlatform; - } - - @Override - protected Attribute read(ClassReader cr, - int off, - int len, - char[] buf, - int codeOff, - Label[] labels) - { - - String targetPlatform = null; - - int target_platform_index = cr.readUnsignedShort(off); - if (target_platform_index != 0) - targetPlatform = cr.readUTF8(off, buf); - off += 2; - - return new ModuleTargetAttribute(targetPlatform); - } - - @Override - protected ByteVector write(ClassWriter cw, - byte[] code, - int len, - int maxStack, - int maxLocals) - { - ByteVector attr = new ByteVector(); - - int target_platform_index = 0; - if (targetPlatform != null && targetPlatform.length() > 0) - target_platform_index = cw.newUTF8(targetPlatform); - attr.putShort(target_platform_index); - - return attr; - } - } - - /** - * ModuleHashes attribute. - * - *
 {@code
-     *
-     * ModuleHashes_attribute {
-     *   // index to CONSTANT_utf8_info structure in constant pool representing
-     *   // the string "ModuleHashes"
-     *   u2 attribute_name_index;
-     *   u4 attribute_length;
-     *
-     *   // index to CONSTANT_utf8_info structure with algorithm name
-     *   u2 algorithm_index;
-     *
-     *   // the number of entries in the hashes table
-     *   u2 hashes_count;
-     *   {   u2 module_name_index (index to CONSTANT_Module_info structure)
-     *       u2 hash_length;
-     *       u1 hash[hash_length];
-     *   } hashes[hashes_count];
-     *
-     * } 
- */ - static class ModuleHashesAttribute extends Attribute { - private final ModuleHashes hashes; - - ModuleHashesAttribute(ModuleHashes hashes) { - super(MODULE_HASHES); - this.hashes = hashes; - } - - ModuleHashesAttribute() { - this(null); - } - - @Override - protected Attribute read(ClassReader cr, - int off, - int len, - char[] buf, - int codeOff, - Label[] labels) - { - String algorithm = cr.readUTF8(off, buf); - off += 2; - - int hashes_count = cr.readUnsignedShort(off); - off += 2; - - Map map = new HashMap<>(); - for (int i=0; i names = hashes.names(); - attr.putShort(names.size()); - - for (String mn : names) { - byte[] hash = hashes.hashFor(mn); - assert hash != null; - attr.putShort(cw.newModule(mn)); - - attr.putShort(hash.length); - for (byte b: hash) { - attr.putByte(b); - } - } - - return attr; - } - } - - /** - * ModuleResolution_attribute { - * u2 attribute_name_index; // "ModuleResolution" - * u4 attribute_length; // 2 - * u2 resolution_flags; - * - * The value of the resolution_flags item is a mask of flags used to denote - * properties of module resolution. The flags are as follows: - * - * // Optional - * 0x0001 (DO_NOT_RESOLVE_BY_DEFAULT) - * - * // At most one of: - * 0x0002 (WARN_DEPRECATED) - * 0x0004 (WARN_DEPRECATED_FOR_REMOVAL) - * 0x0008 (WARN_INCUBATING) - */ - static class ModuleResolutionAttribute extends Attribute { - private final int value; - - ModuleResolutionAttribute() { - super(MODULE_RESOLUTION); - value = 0; - } - - ModuleResolutionAttribute(int value) { - super(MODULE_RESOLUTION); - this.value = value; - } - - @Override - protected Attribute read(ClassReader cr, - int off, - int len, - char[] buf, - int codeOff, - Label[] labels) - { - int flags = cr.readUnsignedShort(off); - return new ModuleResolutionAttribute(flags); - } - - @Override - protected ByteVector write(ClassWriter cw, - byte[] code, - int len, - int maxStack, - int maxLocals) - { - ByteVector attr = new ByteVector(); - attr.putShort(value); - return attr; - } - } -}