jdk/src/java.base/share/classes/jdk/internal/module/ClassFileAttributes.java
changeset 42338 a60f280f803c
parent 37779 7c84df693837
child 42703 20c39ea4a507
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileAttributes.java	Wed Nov 23 16:16:35 2016 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileAttributes.java	Thu Dec 01 08:57:53 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, 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
@@ -27,17 +27,20 @@
 
 import java.lang.module.ModuleDescriptor;
 import java.lang.module.ModuleDescriptor.Requires;
-import java.lang.module.ModuleDescriptor.Requires.Modifier;
 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.LinkedHashSet;
+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;
@@ -51,7 +54,7 @@
  * class file attributes in a module-info class file.
  */
 
-class ClassFileAttributes {
+public final class ClassFileAttributes {
 
     private ClassFileAttributes() { }
 
@@ -60,16 +63,18 @@
      *   // See lang-vm.html for details.
      * }
      */
-    static class ModuleAttribute extends Attribute {
+    public static class ModuleAttribute extends Attribute {
+        private static final JavaLangModuleAccess JLMA
+            = SharedSecrets.getJavaLangModuleAccess();
 
         private ModuleDescriptor descriptor;
 
-        ModuleAttribute(ModuleDescriptor descriptor) {
+        public ModuleAttribute(ModuleDescriptor descriptor) {
             super(MODULE);
             this.descriptor = descriptor;
         }
 
-        ModuleAttribute() {
+        public ModuleAttribute() {
             super(MODULE);
         }
 
@@ -81,27 +86,43 @@
                                  int codeOff,
                                  Label[] labels)
         {
-            ModuleDescriptor.Builder builder
-                = new ModuleDescriptor.Builder("xyzzy"); // Name never used
             ModuleAttribute attr = new ModuleAttribute();
 
+            // module_name
+            String mn = cr.readUTF8(off, buf).replace('/', '.');
+            off += 2;
+
+            // module_flags
+            int module_flags = cr.readUnsignedShort(off);
+            boolean open = ((module_flags & ACC_OPEN) != 0);
+            off += 2;
+
+            ModuleDescriptor.Builder builder;
+            if (open) {
+                builder = JLMA.newOpenModuleBuilder(mn, false);
+            } else {
+                builder = JLMA.newModuleBuilder(mn, false);
+            }
+
             // requires_count and requires[requires_count]
             int requires_count = cr.readUnsignedShort(off);
             off += 2;
             for (int i=0; i<requires_count; i++) {
-                String dn = cr.readUTF8(off, buf);
+                String dn = cr.readUTF8(off, buf).replace('/', '.');
                 int flags = cr.readUnsignedShort(off + 2);
-                Set<Modifier> mods;
+                Set<Requires.Modifier> mods;
                 if (flags == 0) {
                     mods = Collections.emptySet();
                 } else {
                     mods = new HashSet<>();
-                    if ((flags & ACC_PUBLIC) != 0)
-                        mods.add(Modifier.PUBLIC);
+                    if ((flags & ACC_TRANSITIVE) != 0)
+                        mods.add(Requires.Modifier.TRANSITIVE);
+                    if ((flags & ACC_STATIC_PHASE) != 0)
+                        mods.add(Requires.Modifier.STATIC);
                     if ((flags & ACC_SYNTHETIC) != 0)
-                        mods.add(Modifier.SYNTHETIC);
+                        mods.add(Requires.Modifier.SYNTHETIC);
                     if ((flags & ACC_MANDATED) != 0)
-                        mods.add(Modifier.MANDATED);
+                        mods.add(Requires.Modifier.MANDATED);
                 }
                 builder.requires(mods, dn);
                 off += 4;
@@ -113,18 +134,70 @@
             if (exports_count > 0) {
                 for (int i=0; i<exports_count; i++) {
                     String pkg = cr.readUTF8(off, buf).replace('/', '.');
-                    int exports_to_count = cr.readUnsignedShort(off+2);
-                    off += 4;
+                    off += 2;
+
+                    int flags = cr.readUnsignedShort(off);
+                    off += 2;
+                    Set<Exports.Modifier> mods;
+                    if (flags == 0) {
+                        mods = Collections.emptySet();
+                    } else {
+                        mods = new HashSet<>();
+                        if ((flags & ACC_SYNTHETIC) != 0)
+                            mods.add(Exports.Modifier.SYNTHETIC);
+                        if ((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.readUTF8(off, buf);
+                            String t = cr.readUTF8(off, buf).replace('/', '.');
                             off += 2;
                             targets.add(t);
                         }
-                        builder.exports(pkg, targets);
+                        builder.exports(mods, pkg, targets);
                     } else {
-                        builder.exports(pkg);
+                        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++) {
+                    String pkg = cr.readUTF8(off, buf).replace('/', '.');
+                    off += 2;
+
+                    int flags = cr.readUnsignedShort(off);
+                    off += 2;
+                    Set<Opens.Modifier> mods;
+                    if (flags == 0) {
+                        mods = Collections.emptySet();
+                    } else {
+                        mods = new HashSet<>();
+                        if ((flags & ACC_SYNTHETIC) != 0)
+                            mods.add(Opens.Modifier.SYNTHETIC);
+                        if ((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.readUTF8(off, buf).replace('/', '.');
+                            off += 2;
+                            targets.add(t);
+                        }
+                        builder.opens(mods, pkg, targets);
+                    } else {
+                        builder.opens(mods, pkg);
                     }
                 }
             }
@@ -144,15 +217,19 @@
             int provides_count = cr.readUnsignedShort(off);
             off += 2;
             if (provides_count > 0) {
-                Map<String, Set<String>> provides = new HashMap<>();
                 for (int i=0; i<provides_count; i++) {
-                    String sn = cr.readClass(off, buf).replace('/', '.');
-                    String cn = cr.readClass(off + 2, buf).replace('/', '.');
-                    provides.computeIfAbsent(sn, k -> new LinkedHashSet<>()).add(cn);
-                    off += 4;
+                    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);
                 }
-                provides.entrySet().forEach(e -> builder.provides(e.getKey(),
-                                                                  e.getValue()));
             }
 
             attr.descriptor = builder.build();
@@ -169,6 +246,19 @@
             assert descriptor != null;
             ByteVector attr = new ByteVector();
 
+            // module_name
+            String mn = descriptor.name();
+            int module_name_index = cw.newUTF8(mn.replace('.', '/'));
+            attr.putShort(module_name_index);
+
+            // module_flags
+            int module_flags = 0;
+            if (descriptor.isOpen())
+                module_flags |= ACC_OPEN;
+            if (descriptor.isSynthetic())
+                module_flags |= ACC_SYNTHETIC;
+            attr.putShort(module_flags);
+
             // requires_count
             attr.putShort(descriptor.requires().size());
 
@@ -176,32 +266,61 @@
             for (Requires md : descriptor.requires()) {
                 String dn = md.name();
                 int flags = 0;
-                if (md.modifiers().contains(Modifier.PUBLIC))
-                    flags |= ACC_PUBLIC;
-                if (md.modifiers().contains(Modifier.SYNTHETIC))
+                if (md.modifiers().contains(Requires.Modifier.TRANSITIVE))
+                    flags |= ACC_TRANSITIVE;
+                if (md.modifiers().contains(Requires.Modifier.STATIC))
+                    flags |= ACC_STATIC_PHASE;
+                if (md.modifiers().contains(Requires.Modifier.SYNTHETIC))
                     flags |= ACC_SYNTHETIC;
-                if (md.modifiers().contains(Modifier.MANDATED))
+                if (md.modifiers().contains(Requires.Modifier.MANDATED))
                     flags |= ACC_MANDATED;
-                int index = cw.newUTF8(dn);
+                int index = cw.newUTF8(dn.replace('.', '/'));
                 attr.putShort(index);
                 attr.putShort(flags);
             }
 
             // exports_count and exports[exports_count];
-            if (descriptor.exports().isEmpty()) {
-                attr.putShort(0);
-            } else {
-                attr.putShort(descriptor.exports().size());
-                for (Exports e : descriptor.exports()) {
-                    String pkg = e.source().replace('.', '/');
-                    attr.putShort(cw.newUTF8(pkg));
-                    if (e.isQualified()) {
-                        Set<String> ts = e.targets();
-                        attr.putShort(ts.size());
-                        ts.forEach(t -> attr.putShort(cw.newUTF8(t)));
-                    } else {
-                        attr.putShort(0);
-                    }
+            attr.putShort(descriptor.exports().size());
+            for (Exports e : descriptor.exports()) {
+                String pkg = e.source().replace('.', '/');
+                attr.putShort(cw.newUTF8(pkg));
+
+                int flags = 0;
+                if (e.modifiers().contains(Exports.Modifier.SYNTHETIC))
+                    flags |= ACC_SYNTHETIC;
+                if (e.modifiers().contains(Exports.Modifier.MANDATED))
+                    flags |= ACC_MANDATED;
+                attr.putShort(flags);
+
+                if (e.isQualified()) {
+                    Set<String> ts = e.targets();
+                    attr.putShort(ts.size());
+                    ts.forEach(t -> attr.putShort(cw.newUTF8(t.replace('.', '/'))));
+                } 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.newUTF8(pkg));
+
+                int flags = 0;
+                if (obj.modifiers().contains(Opens.Modifier.SYNTHETIC))
+                    flags |= ACC_SYNTHETIC;
+                if (obj.modifiers().contains(Opens.Modifier.MANDATED))
+                    flags |= ACC_MANDATED;
+                attr.putShort(flags);
+
+                if (obj.isQualified()) {
+                    Set<String> ts = obj.targets();
+                    attr.putShort(ts.size());
+                    ts.forEach(t -> attr.putShort(cw.newUTF8(t.replace('.', '/'))));
+                } else {
+                    attr.putShort(0);
                 }
             }
 
@@ -221,14 +340,13 @@
             if (descriptor.provides().isEmpty()) {
                 attr.putShort(0);
             } else {
-                int count = descriptor.provides().values()
-                    .stream().mapToInt(ps -> ps.providers().size()).sum();
-                attr.putShort(count);
-                for (Provides p : descriptor.provides().values()) {
+                attr.putShort(descriptor.provides().size());
+                for (Provides p : descriptor.provides()) {
                     String service = p.service().replace('.', '/');
-                    int index = cw.newClass(service);
+                    attr.putShort(cw.newClass(service));
+                    int with_count = p.providers().size();
+                    attr.putShort(with_count);
                     for (String provider : p.providers()) {
-                        attr.putShort(index);
                         attr.putShort(cw.newClass(provider.replace('.', '/')));
                     }
                 }
@@ -239,44 +357,13 @@
     }
 
     /**
-     * Synthetic attribute.
-     */
-    static class SyntheticAttribute extends Attribute {
-        SyntheticAttribute() {
-            super(SYNTHETIC);
-        }
-
-        @Override
-        protected Attribute read(ClassReader cr,
-                                 int off,
-                                 int len,
-                                 char[] buf,
-                                 int codeOff,
-                                 Label[] labels)
-        {
-            return new SyntheticAttribute();
-        }
-
-        @Override
-        protected ByteVector write(ClassWriter cw,
-                                   byte[] code,
-                                   int len,
-                                   int maxStack,
-                                   int maxLocals)
-        {
-            ByteVector attr = new ByteVector();
-            return attr;
-        }
-    }
-
-    /**
-     * ConcealedPackages attribute.
+     * ModulePackages attribute.
      *
      * <pre> {@code
      *
-     * ConcealedPackages_attribute {
+     * ModulePackages_attribute {
      *   // index to CONSTANT_utf8_info structure in constant pool representing
-     *   // the string "ConcealedPackages"
+     *   // the string "ModulePackages"
      *   u2 attribute_name_index;
      *   u4 attribute_length;
      *
@@ -288,15 +375,15 @@
      *
      * }</pre>
      */
-    static class ConcealedPackagesAttribute extends Attribute {
+    public static class ModulePackagesAttribute extends Attribute {
         private final Set<String> packages;
 
-        ConcealedPackagesAttribute(Set<String> packages) {
-            super(CONCEALED_PACKAGES);
+        public ModulePackagesAttribute(Set<String> packages) {
+            super(MODULE_PACKAGES);
             this.packages = packages;
         }
 
-        ConcealedPackagesAttribute() {
+        public ModulePackagesAttribute() {
             this(null);
         }
 
@@ -320,7 +407,7 @@
                 off += 2;
             }
 
-            return new ConcealedPackagesAttribute(packages);
+            return new ModulePackagesAttribute(packages);
         }
 
         @Override
@@ -348,13 +435,13 @@
     }
 
     /**
-     * Version attribute.
+     * ModuleVersion attribute.
      *
      * <pre> {@code
      *
-     * Version_attribute {
+     * ModuleVersion_attribute {
      *   // index to CONSTANT_utf8_info structure in constant pool representing
-     *   // the string "Version"
+     *   // the string "ModuleVersion"
      *   u2 attribute_name_index;
      *   u4 attribute_length;
      *
@@ -364,15 +451,15 @@
      *
      * } </pre>
      */
-    static class VersionAttribute extends Attribute {
+    public static class ModuleVersionAttribute extends Attribute {
         private final Version version;
 
-        VersionAttribute(Version version) {
-            super(VERSION);
+        public ModuleVersionAttribute(Version version) {
+            super(MODULE_VERSION);
             this.version = version;
         }
 
-        VersionAttribute() {
+        public ModuleVersionAttribute() {
             this(null);
         }
 
@@ -385,7 +472,7 @@
                                  Label[] labels)
         {
             String value = cr.readUTF8(off, buf);
-            return new VersionAttribute(Version.parse(value));
+            return new ModuleVersionAttribute(Version.parse(value));
         }
 
         @Override
@@ -403,13 +490,13 @@
     }
 
     /**
-     * MainClass attribute.
+     * ModuleMainClass attribute.
      *
      * <pre> {@code
      *
      * MainClass_attribute {
      *   // index to CONSTANT_utf8_info structure in constant pool representing
-     *   // the string "MainClass"
+     *   // the string "ModuleMainClass"
      *   u2 attribute_name_index;
      *   u4 attribute_length;
      *
@@ -419,15 +506,15 @@
      *
      * } </pre>
      */
-    static class MainClassAttribute extends Attribute {
+    public static class ModuleMainClassAttribute extends Attribute {
         private final String mainClass;
 
-        MainClassAttribute(String mainClass) {
-            super(MAIN_CLASS);
+        public ModuleMainClassAttribute(String mainClass) {
+            super(MODULE_MAIN_CLASS);
             this.mainClass = mainClass;
         }
 
-        MainClassAttribute() {
+        public ModuleMainClassAttribute() {
             this(null);
         }
 
@@ -440,7 +527,7 @@
                                  Label[] labels)
         {
             String value = cr.readClass(off, buf);
-            return new MainClassAttribute(value);
+            return new ModuleMainClassAttribute(value);
         }
 
         @Override
@@ -458,13 +545,13 @@
     }
 
     /**
-     * TargetPlatform attribute.
+     * ModuleTarget attribute.
      *
      * <pre> {@code
      *
      * TargetPlatform_attribute {
      *   // index to CONSTANT_utf8_info structure in constant pool representing
-     *   // the string "TargetPlatform"
+     *   // the string "ModuleTarget"
      *   u2 attribute_name_index;
      *   u4 attribute_length;
      *
@@ -478,19 +565,19 @@
      *
      * } </pre>
      */
-    static class TargetPlatformAttribute extends Attribute {
+    public static class ModuleTargetAttribute extends Attribute {
         private final String osName;
         private final String osArch;
         private final String osVersion;
 
-        TargetPlatformAttribute(String osName, String osArch, String osVersion) {
-            super(TARGET_PLATFORM);
+        public ModuleTargetAttribute(String osName, String osArch, String osVersion) {
+            super(MODULE_TARGET);
             this.osName = osName;
             this.osArch = osArch;
             this.osVersion = osVersion;
         }
 
-        TargetPlatformAttribute() {
+        public ModuleTargetAttribute() {
             this(null, null, null);
         }
 
@@ -522,7 +609,7 @@
                 osVersion = cr.readUTF8(off, buf);
             off += 2;
 
-            return new TargetPlatformAttribute(osName, osArch, osVersion);
+            return new ModuleTargetAttribute(osName, osArch, osVersion);
         }
 
         @Override
@@ -554,39 +641,37 @@
     }
 
     /**
-     * Hashes attribute.
+     * ModuleHashes attribute.
      *
      * <pre> {@code
      *
-     * Hashes_attribute {
+     * ModuleHashes_attribute {
      *   // index to CONSTANT_utf8_info structure in constant pool representing
-     *   // the string "Hashes"
+     *   // the string "ModuleHashes"
      *   u2 attribute_name_index;
      *   u4 attribute_length;
      *
-     *   // index to CONSTANT_CONSTANT_utf8_info structure with algorithm name
+     *   // index to CONSTANT_utf8_info structure with algorithm name
      *   u2 algorithm_index;
      *
      *   // the number of entries in the hashes table
-     *   u2 hash_count;
-     *   {   u2 requires_index
-     *       u2 hash_index;
-     *   } hashes[hash_count];
+     *   u2 hashes_count;
+     *   {   u2 module_name_index
+     *       u2 hash_length;
+     *       u1 hash[hash_length];
+     *   } hashes[hashes_count];
      *
      * } </pre>
-     *
-     * @apiNote For now the hash is stored in base64 as a UTF-8 string, an
-     * alternative is to store it as an array of u1.
      */
-    static class HashesAttribute extends Attribute {
+    static class ModuleHashesAttribute extends Attribute {
         private final ModuleHashes hashes;
 
-        HashesAttribute(ModuleHashes hashes) {
-            super(HASHES);
+        ModuleHashesAttribute(ModuleHashes hashes) {
+            super(MODULE_HASHES);
             this.hashes = hashes;
         }
 
-        HashesAttribute() {
+        ModuleHashesAttribute() {
             this(null);
         }
 
@@ -601,21 +686,28 @@
             String algorithm = cr.readUTF8(off, buf);
             off += 2;
 
-            int hash_count = cr.readUnsignedShort(off);
+            int hashes_count = cr.readUnsignedShort(off);
             off += 2;
 
-            Map<String, String> map = new HashMap<>();
-            for (int i=0; i<hash_count; i++) {
-                String dn = cr.readUTF8(off, buf);
+            Map<String, byte[]> map = new HashMap<>();
+            for (int i=0; i<hashes_count; i++) {
+                String mn = cr.readUTF8(off, buf).replace('/', '.');
+                off += 2;
+
+                int hash_length = cr.readUnsignedShort(off);
                 off += 2;
-                String hash = cr.readUTF8(off, buf);
-                off += 2;
-                map.put(dn, hash);
+                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 HashesAttribute(hashes);
+            return new ModuleHashesAttribute(hashes);
         }
 
         @Override
@@ -633,11 +725,15 @@
             Set<String> names = hashes.names();
             attr.putShort(names.size());
 
-            for (String dn : names) {
-                String hash = hashes.hashFor(dn);
+            for (String mn : names) {
+                byte[] hash = hashes.hashFor(mn);
                 assert hash != null;
-                attr.putShort(cw.newUTF8(dn));
-                attr.putShort(cw.newUTF8(hash));
+                attr.putShort(cw.newUTF8(mn.replace('.', '/')));
+
+                attr.putShort(hash.length);
+                for (byte b: hash) {
+                    attr.putByte(b);
+                }
             }
 
             return attr;