changeset 47489:6d0e943bcd24

8186236: ModuleInfoExtender should be ASM6 aware Reviewed-by: ksrini, mchung, sundar
author alanb
date Thu, 02 Nov 2017 13:20:21 -0700
parents 2af7932c2f6f
children 7e83ed8fa882
files src/java.base/share/classes/java/lang/Module.java src/java.base/share/classes/jdk/internal/module/ClassFileAttributes.java src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java src/java.base/share/classes/jdk/internal/module/ModuleInfoWriter.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModulesPlugin.java
diffstat 5 files changed, 190 insertions(+), 860 deletions(-) [+]
line wrap: on
line diff
--- a/src/java.base/share/classes/java/lang/Module.java	Thu Nov 02 13:18:23 2017 -0700
+++ b/src/java.base/share/classes/java/lang/Module.java	Thu Nov 02 13:20:21 2017 -0700
@@ -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);
--- a/src/java.base/share/classes/jdk/internal/module/ClassFileAttributes.java	Thu Nov 02 13:18:23 2017 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -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<ModuleDescriptor.Modifier> 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<requires_count; i++) {
-                // CONSTANT_Module_info
-                String dn = cr.readModule(off, buf);
-                off += 2;
-
-                // requires_flags
-                int requires_flags = cr.readUnsignedShort(off);
-                off += 2;
-                Set<Requires.Modifier> 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<exports_count; i++) {
-                    // CONSTANT_Package_info
-                    String pkg = cr.readPackage(off, buf).replace('/', '.');
-                    off += 2;
-
-                    int exports_flags = cr.readUnsignedShort(off);
-                    off += 2;
-                    Set<Exports.Modifier> 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<String> targets = new HashSet<>();
-                        for (int j=0; j<exports_to_count; j++) {
-                            String t = cr.readModule(off, buf);
-                            off += 2;
-                            targets.add(t);
-                        }
-                        builder.exports(mods, pkg, targets);
-                    } else {
-                        builder.exports(mods, pkg);
-                    }
-                }
-            }
-
-            // opens_count and opens[opens_count]
-            int open_count = cr.readUnsignedShort(off);
-            off += 2;
-            if (open_count > 0) {
-                for (int i=0; i<open_count; i++) {
-                    // CONSTANT_Package_info
-                    String pkg = cr.readPackage(off, buf).replace('/', '.');
-                    off += 2;
-
-                    int opens_flags = cr.readUnsignedShort(off);
-                    off += 2;
-                    Set<Opens.Modifier> 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<String> targets = new HashSet<>();
-                        for (int j=0; j<opens_to_count; j++) {
-                            String t = cr.readModule(off, buf);
-                            off += 2;
-                            targets.add(t);
-                        }
-                        builder.opens(mods, pkg, targets);
-                    } else {
-                        builder.opens(mods, pkg);
-                    }
-                }
-            }
-
-            // uses_count and uses_index[uses_count]
-            int uses_count = cr.readUnsignedShort(off);
-            off += 2;
-            if (uses_count > 0) {
-                for (int i=0; i<uses_count; i++) {
-                    String sn = cr.readClass(off, buf).replace('/', '.');
-                    builder.uses(sn);
-                    off += 2;
-                }
-            }
-
-            // provides_count and provides[provides_count]
-            int provides_count = cr.readUnsignedShort(off);
-            off += 2;
-            if (provides_count > 0) {
-                for (int i=0; i<provides_count; i++) {
-                    String service = cr.readClass(off, buf).replace('/', '.');
-                    off += 2;
-                    int with_count = cr.readUnsignedShort(off);
-                    off += 2;
-                    List<String> providers = new ArrayList<>();
-                    for (int j=0; j<with_count; j++) {
-                        String cn = cr.readClass(off, buf).replace('/', '.');
-                        off += 2;
-                        providers.add(cn);
-                    }
-                    builder.provides(service, providers);
-                }
-            }
-
-            return new ModuleAttribute(builder.build());
-        }
-
-        @Override
-        protected ByteVector write(ClassWriter cw,
-                                   byte[] code,
-                                   int len,
-                                   int maxStack,
-                                   int maxLocals)
-        {
-            assert descriptor != null;
-            ByteVector attr = new ByteVector();
-
-            // module_name
-            String mn = descriptor.name();
-            int module_name_index = cw.newModule(mn);
-            attr.putShort(module_name_index);
-
-            // module_flags
-            Set<ModuleDescriptor.Modifier> 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<String> 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<String> 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.
-     *
-     * <pre> {@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];
-     *
-     * }</pre>
-     */
-    public static class ModulePackagesAttribute extends Attribute {
-        private final Set<String> packages;
-
-        public ModulePackagesAttribute(Set<String> 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<String> packages = new HashSet<>();
-            for (int i=0; i<package_count; i++) {
-                String pkg = cr.readPackage(off, buf).replace('/', '.');
-                packages.add(pkg);
-                off += 2;
-            }
-
-            return new ModulePackagesAttribute(packages);
-        }
-
-        @Override
-        protected ByteVector write(ClassWriter cw,
-                                   byte[] code,
-                                   int len,
-                                   int maxStack,
-                                   int maxLocals)
-        {
-            assert packages != null;
-
-            ByteVector attr = new ByteVector();
-
-            // package_count
-            attr.putShort(packages.size());
-
-            // packages
-            packages.stream()
-                .map(p -> p.replace('.', '/'))
-                .forEach(p -> attr.putShort(cw.newPackage(p)));
-
-            return attr;
-        }
-
-    }
-
-    /**
-     * ModuleMainClass attribute.
-     *
-     * <pre> {@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;
-     * }
-     *
-     * } </pre>
-     */
-    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.
-     *
-     * <pre> {@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;
-     * }
-     *
-     * } </pre>
-     */
-    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.
-     *
-     * <pre> {@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];
-     *
-     * } </pre>
-     */
-    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<String, byte[]> map = new HashMap<>();
-            for (int i=0; i<hashes_count; i++) {
-                String mn = cr.readModule(off, buf);
-                off += 2;
-
-                int hash_length = cr.readUnsignedShort(off);
-                off += 2;
-                byte[] hash = new byte[hash_length];
-                for (int j=0; j<hash_length; j++) {
-                    hash[j] = (byte) (0xff & cr.readByte(off+j));
-                }
-                off += hash_length;
-
-                map.put(mn, hash);
-            }
-
-            ModuleHashes hashes = new ModuleHashes(algorithm, map);
-
-            return new ModuleHashesAttribute(hashes);
-        }
-
-        @Override
-        protected ByteVector write(ClassWriter cw,
-                                   byte[] code,
-                                   int len,
-                                   int maxStack,
-                                   int maxLocals)
-        {
-            ByteVector attr = new ByteVector();
-
-            int index = cw.newUTF8(hashes.algorithm());
-            attr.putShort(index);
-
-            Set<String> 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;
-        }
-    }
-}
--- a/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java	Thu Nov 02 13:18:23 2017 -0700
+++ b/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java	Thu Nov 02 13:20:21 2017 -0700
@@ -31,18 +31,18 @@
 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;
 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 static jdk.internal.module.ClassFileAttributes.*;
+import jdk.internal.org.objectweb.asm.commons.ModuleHashesAttribute;
+import jdk.internal.org.objectweb.asm.commons.ModuleResolutionAttribute;
+import jdk.internal.org.objectweb.asm.commons.ModuleTargetAttribute;
 
 /**
  * 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<String, Attribute> 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);
-
-        AttributeAddingClassVisitor cv
-            = new AttributeAddingClassVisitor(Opcodes.ASM5, cw);
+        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS
+                                         + ClassWriter.COMPUTE_FRAMES);
 
         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);
+
+                // ModuleMainClass attribute
+                if (mainClass != null) {
+                    mv.visitMainClass(mainClass.replace('.', '/'));
+                }
+
+                // 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<Attribute> attrs = new ArrayList<>();
-
-        // prototypes of attributes that should be parsed
-        attrs.add(new ModuleAttribute(version));
-        attrs.add(new ModulePackagesAttribute());
-        attrs.add(new ModuleMainClassAttribute());
         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<String> names = new ArrayList<>();
+            List<byte[]> 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();
     }
--- a/src/java.base/share/classes/jdk/internal/module/ModuleInfoWriter.java	Thu Nov 02 13:18:23 2017 -0700
+++ b/src/java.base/share/classes/jdk/internal/module/ModuleInfoWriter.java	Thu Nov 02 13:20:21 2017 -0700
@@ -28,13 +28,14 @@
 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 static jdk.internal.module.ClassFileAttributes.*;
-import static jdk.internal.module.ClassFileConstants.ACC_MODULE;
+import jdk.internal.org.objectweb.asm.commons.ModuleTargetAttribute;
+import static jdk.internal.org.objectweb.asm.Opcodes.*;
 
 /**
  * Utility class to write a ModuleDescriptor as a module-info.class.
@@ -42,6 +43,35 @@
 
 public final class ModuleInfoWriter {
 
+    private static final Map<ModuleDescriptor.Modifier, Integer>
+        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<ModuleDescriptor.Requires.Modifier, Integer>
+        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<ModuleDescriptor.Exports.Modifier, Integer>
+        EXPORTS_MODS_TO_FLAGS = Map.of(
+            ModuleDescriptor.Exports.Modifier.SYNTHETIC, ACC_SYNTHETIC,
+            ModuleDescriptor.Exports.Modifier.MANDATED, ACC_MANDATED
+        );
+
+    private static final Map<ModuleDescriptor.Opens.Modifier, Integer>
+        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<String> exported = md.exports().stream()
                 .map(ModuleDescriptor.Exports::source);
         Stream<String> 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()));
         }
 
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModulesPlugin.java	Thu Nov 02 13:18:23 2017 -0700
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModulesPlugin.java	Thu Nov 02 13:20:21 2017 -0700
@@ -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<String> attrTypes = new HashSet<>();
-            ClassVisitor cv = new ClassVisitor(Opcodes.ASM5) {
+            Set<String> 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;
             }
         }