src/java.base/share/classes/jdk/internal/module/ClassFileAttributes.java
changeset 47489 6d0e943bcd24
parent 47488 2af7932c2f6f
child 47491 7e83ed8fa882
equal deleted inserted replaced
47488:2af7932c2f6f 47489:6d0e943bcd24
     1 /*
       
     2  * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  * or visit www.oracle.com if you need additional information or have any
       
    23  * questions.
       
    24  */
       
    25 
       
    26 package jdk.internal.module;
       
    27 
       
    28 import java.lang.module.ModuleDescriptor;
       
    29 import java.lang.module.ModuleDescriptor.Builder;
       
    30 import java.lang.module.ModuleDescriptor.Requires;
       
    31 import java.lang.module.ModuleDescriptor.Exports;
       
    32 import java.lang.module.ModuleDescriptor.Opens;
       
    33 import java.lang.module.ModuleDescriptor.Provides;
       
    34 import java.lang.module.ModuleDescriptor.Version;
       
    35 import java.util.ArrayList;
       
    36 import java.util.Collections;
       
    37 import java.util.HashMap;
       
    38 import java.util.HashSet;
       
    39 import java.util.List;
       
    40 import java.util.Map;
       
    41 import java.util.Set;
       
    42 
       
    43 import jdk.internal.misc.JavaLangModuleAccess;
       
    44 import jdk.internal.misc.SharedSecrets;
       
    45 import jdk.internal.org.objectweb.asm.Attribute;
       
    46 import jdk.internal.org.objectweb.asm.ByteVector;
       
    47 import jdk.internal.org.objectweb.asm.ClassReader;
       
    48 import jdk.internal.org.objectweb.asm.ClassWriter;
       
    49 import jdk.internal.org.objectweb.asm.Label;
       
    50 import static jdk.internal.module.ClassFileConstants.*;
       
    51 
       
    52 
       
    53 /**
       
    54  * Provides ASM implementations of {@code Attribute} to read and write the
       
    55  * class file attributes in a module-info class file.
       
    56  */
       
    57 
       
    58 public final class ClassFileAttributes {
       
    59 
       
    60     private ClassFileAttributes() { }
       
    61 
       
    62     /**
       
    63      * Module_attribute {
       
    64      *   // See lang-vm.html for details.
       
    65      * }
       
    66      */
       
    67     public static class ModuleAttribute extends Attribute {
       
    68         private static final JavaLangModuleAccess JLMA
       
    69             = SharedSecrets.getJavaLangModuleAccess();
       
    70 
       
    71         private ModuleDescriptor descriptor;
       
    72         private Version replacementVersion;
       
    73 
       
    74         public ModuleAttribute(ModuleDescriptor descriptor) {
       
    75             super(MODULE);
       
    76             this.descriptor = descriptor;
       
    77         }
       
    78 
       
    79         public ModuleAttribute(Version v) {
       
    80             super(MODULE);
       
    81             this.replacementVersion = v;
       
    82         }
       
    83 
       
    84         public ModuleAttribute() {
       
    85             super(MODULE);
       
    86         }
       
    87 
       
    88         @Override
       
    89         protected Attribute read(ClassReader cr,
       
    90                                  int off,
       
    91                                  int len,
       
    92                                  char[] buf,
       
    93                                  int codeOff,
       
    94                                  Label[] labels)
       
    95         {
       
    96             // module_name (CONSTANT_Module_info)
       
    97             String mn = cr.readModule(off, buf);
       
    98             off += 2;
       
    99 
       
   100             // module_flags
       
   101             int module_flags = cr.readUnsignedShort(off);
       
   102             off += 2;
       
   103 
       
   104             Set<ModuleDescriptor.Modifier> modifiers = new HashSet<>();
       
   105             if ((module_flags & ACC_OPEN) != 0)
       
   106                 modifiers.add(ModuleDescriptor.Modifier.OPEN);
       
   107             if ((module_flags & ACC_SYNTHETIC) != 0)
       
   108                 modifiers.add(ModuleDescriptor.Modifier.SYNTHETIC);
       
   109             if ((module_flags & ACC_MANDATED) != 0)
       
   110                 modifiers.add(ModuleDescriptor.Modifier.MANDATED);
       
   111 
       
   112             Builder builder = JLMA.newModuleBuilder(mn, false, modifiers);
       
   113 
       
   114             // module_version
       
   115             String module_version = cr.readUTF8(off, buf);
       
   116             off += 2;
       
   117             if (replacementVersion != null) {
       
   118                 builder.version(replacementVersion);
       
   119             } else if (module_version != null) {
       
   120                 builder.version(module_version);
       
   121             }
       
   122 
       
   123             // requires_count and requires[requires_count]
       
   124             int requires_count = cr.readUnsignedShort(off);
       
   125             off += 2;
       
   126             for (int i=0; i<requires_count; i++) {
       
   127                 // CONSTANT_Module_info
       
   128                 String dn = cr.readModule(off, buf);
       
   129                 off += 2;
       
   130 
       
   131                 // requires_flags
       
   132                 int requires_flags = cr.readUnsignedShort(off);
       
   133                 off += 2;
       
   134                 Set<Requires.Modifier> mods;
       
   135                 if (requires_flags == 0) {
       
   136                     mods = Collections.emptySet();
       
   137                 } else {
       
   138                     mods = new HashSet<>();
       
   139                     if ((requires_flags & ACC_TRANSITIVE) != 0)
       
   140                         mods.add(Requires.Modifier.TRANSITIVE);
       
   141                     if ((requires_flags & ACC_STATIC_PHASE) != 0)
       
   142                         mods.add(Requires.Modifier.STATIC);
       
   143                     if ((requires_flags & ACC_SYNTHETIC) != 0)
       
   144                         mods.add(Requires.Modifier.SYNTHETIC);
       
   145                     if ((requires_flags & ACC_MANDATED) != 0)
       
   146                         mods.add(Requires.Modifier.MANDATED);
       
   147                 }
       
   148 
       
   149                 // requires_version
       
   150                 String requires_version = cr.readUTF8(off, buf);
       
   151                 off += 2;
       
   152                 if (requires_version == null) {
       
   153                     builder.requires(mods, dn);
       
   154                 } else {
       
   155                     JLMA.requires(builder, mods, dn, requires_version);
       
   156                 }
       
   157             }
       
   158 
       
   159             // exports_count and exports[exports_count]
       
   160             int exports_count = cr.readUnsignedShort(off);
       
   161             off += 2;
       
   162             if (exports_count > 0) {
       
   163                 for (int i=0; i<exports_count; i++) {
       
   164                     // CONSTANT_Package_info
       
   165                     String pkg = cr.readPackage(off, buf).replace('/', '.');
       
   166                     off += 2;
       
   167 
       
   168                     int exports_flags = cr.readUnsignedShort(off);
       
   169                     off += 2;
       
   170                     Set<Exports.Modifier> mods;
       
   171                     if (exports_flags == 0) {
       
   172                         mods = Collections.emptySet();
       
   173                     } else {
       
   174                         mods = new HashSet<>();
       
   175                         if ((exports_flags & ACC_SYNTHETIC) != 0)
       
   176                             mods.add(Exports.Modifier.SYNTHETIC);
       
   177                         if ((exports_flags & ACC_MANDATED) != 0)
       
   178                             mods.add(Exports.Modifier.MANDATED);
       
   179                     }
       
   180 
       
   181                     int exports_to_count = cr.readUnsignedShort(off);
       
   182                     off += 2;
       
   183                     if (exports_to_count > 0) {
       
   184                         Set<String> targets = new HashSet<>();
       
   185                         for (int j=0; j<exports_to_count; j++) {
       
   186                             String t = cr.readModule(off, buf);
       
   187                             off += 2;
       
   188                             targets.add(t);
       
   189                         }
       
   190                         builder.exports(mods, pkg, targets);
       
   191                     } else {
       
   192                         builder.exports(mods, pkg);
       
   193                     }
       
   194                 }
       
   195             }
       
   196 
       
   197             // opens_count and opens[opens_count]
       
   198             int open_count = cr.readUnsignedShort(off);
       
   199             off += 2;
       
   200             if (open_count > 0) {
       
   201                 for (int i=0; i<open_count; i++) {
       
   202                     // CONSTANT_Package_info
       
   203                     String pkg = cr.readPackage(off, buf).replace('/', '.');
       
   204                     off += 2;
       
   205 
       
   206                     int opens_flags = cr.readUnsignedShort(off);
       
   207                     off += 2;
       
   208                     Set<Opens.Modifier> mods;
       
   209                     if (opens_flags == 0) {
       
   210                         mods = Collections.emptySet();
       
   211                     } else {
       
   212                         mods = new HashSet<>();
       
   213                         if ((opens_flags & ACC_SYNTHETIC) != 0)
       
   214                             mods.add(Opens.Modifier.SYNTHETIC);
       
   215                         if ((opens_flags & ACC_MANDATED) != 0)
       
   216                             mods.add(Opens.Modifier.MANDATED);
       
   217                     }
       
   218 
       
   219                     int opens_to_count = cr.readUnsignedShort(off);
       
   220                     off += 2;
       
   221                     if (opens_to_count > 0) {
       
   222                         Set<String> targets = new HashSet<>();
       
   223                         for (int j=0; j<opens_to_count; j++) {
       
   224                             String t = cr.readModule(off, buf);
       
   225                             off += 2;
       
   226                             targets.add(t);
       
   227                         }
       
   228                         builder.opens(mods, pkg, targets);
       
   229                     } else {
       
   230                         builder.opens(mods, pkg);
       
   231                     }
       
   232                 }
       
   233             }
       
   234 
       
   235             // uses_count and uses_index[uses_count]
       
   236             int uses_count = cr.readUnsignedShort(off);
       
   237             off += 2;
       
   238             if (uses_count > 0) {
       
   239                 for (int i=0; i<uses_count; i++) {
       
   240                     String sn = cr.readClass(off, buf).replace('/', '.');
       
   241                     builder.uses(sn);
       
   242                     off += 2;
       
   243                 }
       
   244             }
       
   245 
       
   246             // provides_count and provides[provides_count]
       
   247             int provides_count = cr.readUnsignedShort(off);
       
   248             off += 2;
       
   249             if (provides_count > 0) {
       
   250                 for (int i=0; i<provides_count; i++) {
       
   251                     String service = cr.readClass(off, buf).replace('/', '.');
       
   252                     off += 2;
       
   253                     int with_count = cr.readUnsignedShort(off);
       
   254                     off += 2;
       
   255                     List<String> providers = new ArrayList<>();
       
   256                     for (int j=0; j<with_count; j++) {
       
   257                         String cn = cr.readClass(off, buf).replace('/', '.');
       
   258                         off += 2;
       
   259                         providers.add(cn);
       
   260                     }
       
   261                     builder.provides(service, providers);
       
   262                 }
       
   263             }
       
   264 
       
   265             return new ModuleAttribute(builder.build());
       
   266         }
       
   267 
       
   268         @Override
       
   269         protected ByteVector write(ClassWriter cw,
       
   270                                    byte[] code,
       
   271                                    int len,
       
   272                                    int maxStack,
       
   273                                    int maxLocals)
       
   274         {
       
   275             assert descriptor != null;
       
   276             ByteVector attr = new ByteVector();
       
   277 
       
   278             // module_name
       
   279             String mn = descriptor.name();
       
   280             int module_name_index = cw.newModule(mn);
       
   281             attr.putShort(module_name_index);
       
   282 
       
   283             // module_flags
       
   284             Set<ModuleDescriptor.Modifier> modifiers = descriptor.modifiers();
       
   285             int module_flags = 0;
       
   286             if (modifiers.contains(ModuleDescriptor.Modifier.OPEN))
       
   287                 module_flags |= ACC_OPEN;
       
   288             if (modifiers.contains(ModuleDescriptor.Modifier.SYNTHETIC))
       
   289                 module_flags |= ACC_SYNTHETIC;
       
   290             if (modifiers.contains(ModuleDescriptor.Modifier.MANDATED))
       
   291                 module_flags |= ACC_MANDATED;
       
   292             attr.putShort(module_flags);
       
   293 
       
   294             // module_version
       
   295             String vs = descriptor.rawVersion().orElse(null);
       
   296             if (vs == null) {
       
   297                 attr.putShort(0);
       
   298             } else {
       
   299                 int module_version_index = cw.newUTF8(vs);
       
   300                 attr.putShort(module_version_index);
       
   301             }
       
   302 
       
   303             // requires_count
       
   304             attr.putShort(descriptor.requires().size());
       
   305 
       
   306             // requires[requires_count]
       
   307             for (Requires r : descriptor.requires()) {
       
   308                 int requires_index = cw.newModule(r.name());
       
   309                 attr.putShort(requires_index);
       
   310 
       
   311                 int requires_flags = 0;
       
   312                 if (r.modifiers().contains(Requires.Modifier.TRANSITIVE))
       
   313                     requires_flags |= ACC_TRANSITIVE;
       
   314                 if (r.modifiers().contains(Requires.Modifier.STATIC))
       
   315                     requires_flags |= ACC_STATIC_PHASE;
       
   316                 if (r.modifiers().contains(Requires.Modifier.SYNTHETIC))
       
   317                     requires_flags |= ACC_SYNTHETIC;
       
   318                 if (r.modifiers().contains(Requires.Modifier.MANDATED))
       
   319                     requires_flags |= ACC_MANDATED;
       
   320                 attr.putShort(requires_flags);
       
   321 
       
   322                 int requires_version_index;
       
   323                 vs = r.rawCompiledVersion().orElse(null);
       
   324                 if (vs == null) {
       
   325                     requires_version_index = 0;
       
   326                 } else {
       
   327                     requires_version_index = cw.newUTF8(vs);
       
   328                 }
       
   329                 attr.putShort(requires_version_index);
       
   330             }
       
   331 
       
   332             // exports_count and exports[exports_count];
       
   333             attr.putShort(descriptor.exports().size());
       
   334             for (Exports e : descriptor.exports()) {
       
   335                 String pkg = e.source().replace('.', '/');
       
   336                 attr.putShort(cw.newPackage(pkg));
       
   337 
       
   338                 int exports_flags = 0;
       
   339                 if (e.modifiers().contains(Exports.Modifier.SYNTHETIC))
       
   340                     exports_flags |= ACC_SYNTHETIC;
       
   341                 if (e.modifiers().contains(Exports.Modifier.MANDATED))
       
   342                     exports_flags |= ACC_MANDATED;
       
   343                 attr.putShort(exports_flags);
       
   344 
       
   345                 if (e.isQualified()) {
       
   346                     Set<String> ts = e.targets();
       
   347                     attr.putShort(ts.size());
       
   348                     ts.forEach(target -> attr.putShort(cw.newModule(target)));
       
   349                 } else {
       
   350                     attr.putShort(0);
       
   351                 }
       
   352             }
       
   353 
       
   354             // opens_counts and opens[opens_counts]
       
   355             attr.putShort(descriptor.opens().size());
       
   356             for (Opens obj : descriptor.opens()) {
       
   357                 String pkg = obj.source().replace('.', '/');
       
   358                 attr.putShort(cw.newPackage(pkg));
       
   359 
       
   360                 int opens_flags = 0;
       
   361                 if (obj.modifiers().contains(Opens.Modifier.SYNTHETIC))
       
   362                     opens_flags |= ACC_SYNTHETIC;
       
   363                 if (obj.modifiers().contains(Opens.Modifier.MANDATED))
       
   364                     opens_flags |= ACC_MANDATED;
       
   365                 attr.putShort(opens_flags);
       
   366 
       
   367                 if (obj.isQualified()) {
       
   368                     Set<String> ts = obj.targets();
       
   369                     attr.putShort(ts.size());
       
   370                     ts.forEach(target -> attr.putShort(cw.newModule(target)));
       
   371                 } else {
       
   372                     attr.putShort(0);
       
   373                 }
       
   374             }
       
   375 
       
   376             // uses_count and uses_index[uses_count]
       
   377             if (descriptor.uses().isEmpty()) {
       
   378                 attr.putShort(0);
       
   379             } else {
       
   380                 attr.putShort(descriptor.uses().size());
       
   381                 for (String s : descriptor.uses()) {
       
   382                     String service = s.replace('.', '/');
       
   383                     int index = cw.newClass(service);
       
   384                     attr.putShort(index);
       
   385                 }
       
   386             }
       
   387 
       
   388             // provides_count and provides[provides_count]
       
   389             if (descriptor.provides().isEmpty()) {
       
   390                 attr.putShort(0);
       
   391             } else {
       
   392                 attr.putShort(descriptor.provides().size());
       
   393                 for (Provides p : descriptor.provides()) {
       
   394                     String service = p.service().replace('.', '/');
       
   395                     attr.putShort(cw.newClass(service));
       
   396                     int with_count = p.providers().size();
       
   397                     attr.putShort(with_count);
       
   398                     for (String provider : p.providers()) {
       
   399                         attr.putShort(cw.newClass(provider.replace('.', '/')));
       
   400                     }
       
   401                 }
       
   402             }
       
   403 
       
   404             return attr;
       
   405         }
       
   406     }
       
   407 
       
   408     /**
       
   409      * ModulePackages attribute.
       
   410      *
       
   411      * <pre> {@code
       
   412      *
       
   413      * ModulePackages_attribute {
       
   414      *   // index to CONSTANT_utf8_info structure in constant pool representing
       
   415      *   // the string "ModulePackages"
       
   416      *   u2 attribute_name_index;
       
   417      *   u4 attribute_length;
       
   418      *
       
   419      *   // the number of entries in the packages table
       
   420      *   u2 packages_count;
       
   421      *   { // index to CONSTANT_Package_info structure with the package name
       
   422      *     u2 package_index
       
   423      *   } packages[package_count];
       
   424      *
       
   425      * }</pre>
       
   426      */
       
   427     public static class ModulePackagesAttribute extends Attribute {
       
   428         private final Set<String> packages;
       
   429 
       
   430         public ModulePackagesAttribute(Set<String> packages) {
       
   431             super(MODULE_PACKAGES);
       
   432             this.packages = packages;
       
   433         }
       
   434 
       
   435         public ModulePackagesAttribute() {
       
   436             this(null);
       
   437         }
       
   438 
       
   439         @Override
       
   440         protected Attribute read(ClassReader cr,
       
   441                                  int off,
       
   442                                  int len,
       
   443                                  char[] buf,
       
   444                                  int codeOff,
       
   445                                  Label[] labels)
       
   446         {
       
   447             // package count
       
   448             int package_count = cr.readUnsignedShort(off);
       
   449             off += 2;
       
   450 
       
   451             // packages
       
   452             Set<String> packages = new HashSet<>();
       
   453             for (int i=0; i<package_count; i++) {
       
   454                 String pkg = cr.readPackage(off, buf).replace('/', '.');
       
   455                 packages.add(pkg);
       
   456                 off += 2;
       
   457             }
       
   458 
       
   459             return new ModulePackagesAttribute(packages);
       
   460         }
       
   461 
       
   462         @Override
       
   463         protected ByteVector write(ClassWriter cw,
       
   464                                    byte[] code,
       
   465                                    int len,
       
   466                                    int maxStack,
       
   467                                    int maxLocals)
       
   468         {
       
   469             assert packages != null;
       
   470 
       
   471             ByteVector attr = new ByteVector();
       
   472 
       
   473             // package_count
       
   474             attr.putShort(packages.size());
       
   475 
       
   476             // packages
       
   477             packages.stream()
       
   478                 .map(p -> p.replace('.', '/'))
       
   479                 .forEach(p -> attr.putShort(cw.newPackage(p)));
       
   480 
       
   481             return attr;
       
   482         }
       
   483 
       
   484     }
       
   485 
       
   486     /**
       
   487      * ModuleMainClass attribute.
       
   488      *
       
   489      * <pre> {@code
       
   490      *
       
   491      * MainClass_attribute {
       
   492      *   // index to CONSTANT_utf8_info structure in constant pool representing
       
   493      *   // the string "ModuleMainClass"
       
   494      *   u2 attribute_name_index;
       
   495      *   u4 attribute_length;
       
   496      *
       
   497      *   // index to CONSTANT_Class_info structure with the main class name
       
   498      *   u2 main_class_index;
       
   499      * }
       
   500      *
       
   501      * } </pre>
       
   502      */
       
   503     public static class ModuleMainClassAttribute extends Attribute {
       
   504         private final String mainClass;
       
   505 
       
   506         public ModuleMainClassAttribute(String mainClass) {
       
   507             super(MODULE_MAIN_CLASS);
       
   508             this.mainClass = mainClass;
       
   509         }
       
   510 
       
   511         public ModuleMainClassAttribute() {
       
   512             this(null);
       
   513         }
       
   514 
       
   515         @Override
       
   516         protected Attribute read(ClassReader cr,
       
   517                                  int off,
       
   518                                  int len,
       
   519                                  char[] buf,
       
   520                                  int codeOff,
       
   521                                  Label[] labels)
       
   522         {
       
   523             String value = cr.readClass(off, buf).replace('/', '.');
       
   524             return new ModuleMainClassAttribute(value);
       
   525         }
       
   526 
       
   527         @Override
       
   528         protected ByteVector write(ClassWriter cw,
       
   529                                    byte[] code,
       
   530                                    int len,
       
   531                                    int maxStack,
       
   532                                    int maxLocals)
       
   533         {
       
   534             ByteVector attr = new ByteVector();
       
   535             int index = cw.newClass(mainClass.replace('.', '/'));
       
   536             attr.putShort(index);
       
   537             return attr;
       
   538         }
       
   539     }
       
   540 
       
   541     /**
       
   542      * ModuleTarget attribute.
       
   543      *
       
   544      * <pre> {@code
       
   545      *
       
   546      * TargetPlatform_attribute {
       
   547      *   // index to CONSTANT_utf8_info structure in constant pool representing
       
   548      *   // the string "ModuleTarget"
       
   549      *   u2 attribute_name_index;
       
   550      *   u4 attribute_length;
       
   551      *
       
   552      *   // index to CONSTANT_utf8_info structure with the target platform
       
   553      *   u2 target_platform_index;
       
   554      * }
       
   555      *
       
   556      * } </pre>
       
   557      */
       
   558     public static class ModuleTargetAttribute extends Attribute {
       
   559         private final String targetPlatform;
       
   560 
       
   561         public ModuleTargetAttribute(String targetPlatform) {
       
   562             super(MODULE_TARGET);
       
   563             this.targetPlatform = targetPlatform;
       
   564         }
       
   565 
       
   566         public ModuleTargetAttribute() {
       
   567             this(null);
       
   568         }
       
   569 
       
   570         public String targetPlatform() {
       
   571             return targetPlatform;
       
   572         }
       
   573 
       
   574         @Override
       
   575         protected Attribute read(ClassReader cr,
       
   576                                  int off,
       
   577                                  int len,
       
   578                                  char[] buf,
       
   579                                  int codeOff,
       
   580                                  Label[] labels)
       
   581         {
       
   582 
       
   583             String targetPlatform = null;
       
   584 
       
   585             int target_platform_index = cr.readUnsignedShort(off);
       
   586             if (target_platform_index != 0)
       
   587                 targetPlatform = cr.readUTF8(off, buf);
       
   588             off += 2;
       
   589 
       
   590             return new ModuleTargetAttribute(targetPlatform);
       
   591         }
       
   592 
       
   593         @Override
       
   594         protected ByteVector write(ClassWriter cw,
       
   595                                    byte[] code,
       
   596                                    int len,
       
   597                                    int maxStack,
       
   598                                    int maxLocals)
       
   599         {
       
   600             ByteVector attr = new ByteVector();
       
   601 
       
   602             int target_platform_index = 0;
       
   603             if (targetPlatform != null && targetPlatform.length() > 0)
       
   604                 target_platform_index = cw.newUTF8(targetPlatform);
       
   605             attr.putShort(target_platform_index);
       
   606 
       
   607             return attr;
       
   608         }
       
   609     }
       
   610 
       
   611     /**
       
   612      * ModuleHashes attribute.
       
   613      *
       
   614      * <pre> {@code
       
   615      *
       
   616      * ModuleHashes_attribute {
       
   617      *   // index to CONSTANT_utf8_info structure in constant pool representing
       
   618      *   // the string "ModuleHashes"
       
   619      *   u2 attribute_name_index;
       
   620      *   u4 attribute_length;
       
   621      *
       
   622      *   // index to CONSTANT_utf8_info structure with algorithm name
       
   623      *   u2 algorithm_index;
       
   624      *
       
   625      *   // the number of entries in the hashes table
       
   626      *   u2 hashes_count;
       
   627      *   {   u2 module_name_index (index to CONSTANT_Module_info structure)
       
   628      *       u2 hash_length;
       
   629      *       u1 hash[hash_length];
       
   630      *   } hashes[hashes_count];
       
   631      *
       
   632      * } </pre>
       
   633      */
       
   634     static class ModuleHashesAttribute extends Attribute {
       
   635         private final ModuleHashes hashes;
       
   636 
       
   637         ModuleHashesAttribute(ModuleHashes hashes) {
       
   638             super(MODULE_HASHES);
       
   639             this.hashes = hashes;
       
   640         }
       
   641 
       
   642         ModuleHashesAttribute() {
       
   643             this(null);
       
   644         }
       
   645 
       
   646         @Override
       
   647         protected Attribute read(ClassReader cr,
       
   648                                  int off,
       
   649                                  int len,
       
   650                                  char[] buf,
       
   651                                  int codeOff,
       
   652                                  Label[] labels)
       
   653         {
       
   654             String algorithm = cr.readUTF8(off, buf);
       
   655             off += 2;
       
   656 
       
   657             int hashes_count = cr.readUnsignedShort(off);
       
   658             off += 2;
       
   659 
       
   660             Map<String, byte[]> map = new HashMap<>();
       
   661             for (int i=0; i<hashes_count; i++) {
       
   662                 String mn = cr.readModule(off, buf);
       
   663                 off += 2;
       
   664 
       
   665                 int hash_length = cr.readUnsignedShort(off);
       
   666                 off += 2;
       
   667                 byte[] hash = new byte[hash_length];
       
   668                 for (int j=0; j<hash_length; j++) {
       
   669                     hash[j] = (byte) (0xff & cr.readByte(off+j));
       
   670                 }
       
   671                 off += hash_length;
       
   672 
       
   673                 map.put(mn, hash);
       
   674             }
       
   675 
       
   676             ModuleHashes hashes = new ModuleHashes(algorithm, map);
       
   677 
       
   678             return new ModuleHashesAttribute(hashes);
       
   679         }
       
   680 
       
   681         @Override
       
   682         protected ByteVector write(ClassWriter cw,
       
   683                                    byte[] code,
       
   684                                    int len,
       
   685                                    int maxStack,
       
   686                                    int maxLocals)
       
   687         {
       
   688             ByteVector attr = new ByteVector();
       
   689 
       
   690             int index = cw.newUTF8(hashes.algorithm());
       
   691             attr.putShort(index);
       
   692 
       
   693             Set<String> names = hashes.names();
       
   694             attr.putShort(names.size());
       
   695 
       
   696             for (String mn : names) {
       
   697                 byte[] hash = hashes.hashFor(mn);
       
   698                 assert hash != null;
       
   699                 attr.putShort(cw.newModule(mn));
       
   700 
       
   701                 attr.putShort(hash.length);
       
   702                 for (byte b: hash) {
       
   703                     attr.putByte(b);
       
   704                 }
       
   705             }
       
   706 
       
   707             return attr;
       
   708         }
       
   709     }
       
   710 
       
   711     /**
       
   712      *  ModuleResolution_attribute {
       
   713      *    u2 attribute_name_index;    // "ModuleResolution"
       
   714      *    u4 attribute_length;        // 2
       
   715      *    u2 resolution_flags;
       
   716      *
       
   717      *  The value of the resolution_flags item is a mask of flags used to denote
       
   718      *  properties of module resolution. The flags are as follows:
       
   719      *
       
   720      *   // Optional
       
   721      *   0x0001 (DO_NOT_RESOLVE_BY_DEFAULT)
       
   722      *
       
   723      *   // At most one of:
       
   724      *   0x0002 (WARN_DEPRECATED)
       
   725      *   0x0004 (WARN_DEPRECATED_FOR_REMOVAL)
       
   726      *   0x0008 (WARN_INCUBATING)
       
   727      */
       
   728     static class ModuleResolutionAttribute extends Attribute {
       
   729         private final int value;
       
   730 
       
   731         ModuleResolutionAttribute() {
       
   732             super(MODULE_RESOLUTION);
       
   733             value = 0;
       
   734         }
       
   735 
       
   736         ModuleResolutionAttribute(int value) {
       
   737             super(MODULE_RESOLUTION);
       
   738             this.value = value;
       
   739         }
       
   740 
       
   741         @Override
       
   742         protected Attribute read(ClassReader cr,
       
   743                                  int off,
       
   744                                  int len,
       
   745                                  char[] buf,
       
   746                                  int codeOff,
       
   747                                  Label[] labels)
       
   748         {
       
   749             int flags = cr.readUnsignedShort(off);
       
   750             return new ModuleResolutionAttribute(flags);
       
   751         }
       
   752 
       
   753         @Override
       
   754         protected ByteVector write(ClassWriter cw,
       
   755                                    byte[] code,
       
   756                                    int len,
       
   757                                    int maxStack,
       
   758                                    int maxLocals)
       
   759         {
       
   760             ByteVector attr = new ByteVector();
       
   761             attr.putShort(value);
       
   762             return attr;
       
   763         }
       
   764     }
       
   765 }