--- 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(); }