ClassFileAttributes.java revision 16177:89ef4b822745
1/*
2 * Copyright (c) 2015, 2016, 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
26package jdk.internal.module;
27
28import java.lang.module.ModuleDescriptor;
29import java.lang.module.ModuleDescriptor.Requires;
30import java.lang.module.ModuleDescriptor.Exports;
31import java.lang.module.ModuleDescriptor.Opens;
32import java.lang.module.ModuleDescriptor.Provides;
33import java.lang.module.ModuleDescriptor.Version;
34import java.util.ArrayList;
35import java.util.Collections;
36import java.util.HashMap;
37import java.util.HashSet;
38import java.util.List;
39import java.util.Map;
40import java.util.Set;
41
42import jdk.internal.misc.JavaLangModuleAccess;
43import jdk.internal.misc.SharedSecrets;
44import jdk.internal.org.objectweb.asm.Attribute;
45import jdk.internal.org.objectweb.asm.ByteVector;
46import jdk.internal.org.objectweb.asm.ClassReader;
47import jdk.internal.org.objectweb.asm.ClassWriter;
48import jdk.internal.org.objectweb.asm.Label;
49import static jdk.internal.module.ClassFileConstants.*;
50
51
52/**
53 * Provides ASM implementations of {@code Attribute} to read and write the
54 * class file attributes in a module-info class file.
55 */
56
57public final class ClassFileAttributes {
58
59    private ClassFileAttributes() { }
60
61    /**
62     * Module_attribute {
63     *   // See lang-vm.html for details.
64     * }
65     */
66    public static class ModuleAttribute extends Attribute {
67        private static final JavaLangModuleAccess JLMA
68            = SharedSecrets.getJavaLangModuleAccess();
69
70        private ModuleDescriptor descriptor;
71
72        public ModuleAttribute(ModuleDescriptor descriptor) {
73            super(MODULE);
74            this.descriptor = descriptor;
75        }
76
77        public ModuleAttribute() {
78            super(MODULE);
79        }
80
81        @Override
82        protected Attribute read(ClassReader cr,
83                                 int off,
84                                 int len,
85                                 char[] buf,
86                                 int codeOff,
87                                 Label[] labels)
88        {
89            ModuleAttribute attr = new ModuleAttribute();
90
91            // module_name
92            String mn = cr.readUTF8(off, buf).replace('/', '.');
93            off += 2;
94
95            // module_flags
96            int module_flags = cr.readUnsignedShort(off);
97            boolean open = ((module_flags & ACC_OPEN) != 0);
98            off += 2;
99
100            ModuleDescriptor.Builder builder;
101            if (open) {
102                builder = JLMA.newOpenModuleBuilder(mn, false);
103            } else {
104                builder = JLMA.newModuleBuilder(mn, false);
105            }
106
107            // requires_count and requires[requires_count]
108            int requires_count = cr.readUnsignedShort(off);
109            off += 2;
110            for (int i=0; i<requires_count; i++) {
111                String dn = cr.readUTF8(off, buf).replace('/', '.');
112                int flags = cr.readUnsignedShort(off + 2);
113                Set<Requires.Modifier> mods;
114                if (flags == 0) {
115                    mods = Collections.emptySet();
116                } else {
117                    mods = new HashSet<>();
118                    if ((flags & ACC_TRANSITIVE) != 0)
119                        mods.add(Requires.Modifier.TRANSITIVE);
120                    if ((flags & ACC_STATIC_PHASE) != 0)
121                        mods.add(Requires.Modifier.STATIC);
122                    if ((flags & ACC_SYNTHETIC) != 0)
123                        mods.add(Requires.Modifier.SYNTHETIC);
124                    if ((flags & ACC_MANDATED) != 0)
125                        mods.add(Requires.Modifier.MANDATED);
126                }
127                builder.requires(mods, dn);
128                off += 4;
129            }
130
131            // exports_count and exports[exports_count]
132            int exports_count = cr.readUnsignedShort(off);
133            off += 2;
134            if (exports_count > 0) {
135                for (int i=0; i<exports_count; i++) {
136                    String pkg = cr.readUTF8(off, buf).replace('/', '.');
137                    off += 2;
138
139                    int flags = cr.readUnsignedShort(off);
140                    off += 2;
141                    Set<Exports.Modifier> mods;
142                    if (flags == 0) {
143                        mods = Collections.emptySet();
144                    } else {
145                        mods = new HashSet<>();
146                        if ((flags & ACC_SYNTHETIC) != 0)
147                            mods.add(Exports.Modifier.SYNTHETIC);
148                        if ((flags & ACC_MANDATED) != 0)
149                            mods.add(Exports.Modifier.MANDATED);
150                    }
151
152                    int exports_to_count = cr.readUnsignedShort(off);
153                    off += 2;
154                    if (exports_to_count > 0) {
155                        Set<String> targets = new HashSet<>();
156                        for (int j=0; j<exports_to_count; j++) {
157                            String t = cr.readUTF8(off, buf).replace('/', '.');
158                            off += 2;
159                            targets.add(t);
160                        }
161                        builder.exports(mods, pkg, targets);
162                    } else {
163                        builder.exports(mods, pkg);
164                    }
165                }
166            }
167
168            // opens_count and opens[opens_count]
169            int open_count = cr.readUnsignedShort(off);
170            off += 2;
171            if (open_count > 0) {
172                for (int i=0; i<open_count; i++) {
173                    String pkg = cr.readUTF8(off, buf).replace('/', '.');
174                    off += 2;
175
176                    int flags = cr.readUnsignedShort(off);
177                    off += 2;
178                    Set<Opens.Modifier> mods;
179                    if (flags == 0) {
180                        mods = Collections.emptySet();
181                    } else {
182                        mods = new HashSet<>();
183                        if ((flags & ACC_SYNTHETIC) != 0)
184                            mods.add(Opens.Modifier.SYNTHETIC);
185                        if ((flags & ACC_MANDATED) != 0)
186                            mods.add(Opens.Modifier.MANDATED);
187                    }
188
189                    int opens_to_count = cr.readUnsignedShort(off);
190                    off += 2;
191                    if (opens_to_count > 0) {
192                        Set<String> targets = new HashSet<>();
193                        for (int j=0; j<opens_to_count; j++) {
194                            String t = cr.readUTF8(off, buf).replace('/', '.');
195                            off += 2;
196                            targets.add(t);
197                        }
198                        builder.opens(mods, pkg, targets);
199                    } else {
200                        builder.opens(mods, pkg);
201                    }
202                }
203            }
204
205            // uses_count and uses_index[uses_count]
206            int uses_count = cr.readUnsignedShort(off);
207            off += 2;
208            if (uses_count > 0) {
209                for (int i=0; i<uses_count; i++) {
210                    String sn = cr.readClass(off, buf).replace('/', '.');
211                    builder.uses(sn);
212                    off += 2;
213                }
214            }
215
216            // provides_count and provides[provides_count]
217            int provides_count = cr.readUnsignedShort(off);
218            off += 2;
219            if (provides_count > 0) {
220                for (int i=0; i<provides_count; i++) {
221                    String service = cr.readClass(off, buf).replace('/', '.');
222                    off += 2;
223                    int with_count = cr.readUnsignedShort(off);
224                    off += 2;
225                    List<String> providers = new ArrayList<>();
226                    for (int j=0; j<with_count; j++) {
227                        String cn = cr.readClass(off, buf).replace('/', '.');
228                        off += 2;
229                        providers.add(cn);
230                    }
231                    builder.provides(service, providers);
232                }
233            }
234
235            attr.descriptor = builder.build();
236            return attr;
237        }
238
239        @Override
240        protected ByteVector write(ClassWriter cw,
241                                   byte[] code,
242                                   int len,
243                                   int maxStack,
244                                   int maxLocals)
245        {
246            assert descriptor != null;
247            ByteVector attr = new ByteVector();
248
249            // module_name
250            String mn = descriptor.name();
251            int module_name_index = cw.newUTF8(mn.replace('.', '/'));
252            attr.putShort(module_name_index);
253
254            // module_flags
255            int module_flags = 0;
256            if (descriptor.isOpen())
257                module_flags |= ACC_OPEN;
258            if (descriptor.isSynthetic())
259                module_flags |= ACC_SYNTHETIC;
260            attr.putShort(module_flags);
261
262            // requires_count
263            attr.putShort(descriptor.requires().size());
264
265            // requires[requires_count]
266            for (Requires md : descriptor.requires()) {
267                String dn = md.name();
268                int flags = 0;
269                if (md.modifiers().contains(Requires.Modifier.TRANSITIVE))
270                    flags |= ACC_TRANSITIVE;
271                if (md.modifiers().contains(Requires.Modifier.STATIC))
272                    flags |= ACC_STATIC_PHASE;
273                if (md.modifiers().contains(Requires.Modifier.SYNTHETIC))
274                    flags |= ACC_SYNTHETIC;
275                if (md.modifiers().contains(Requires.Modifier.MANDATED))
276                    flags |= ACC_MANDATED;
277                int index = cw.newUTF8(dn.replace('.', '/'));
278                attr.putShort(index);
279                attr.putShort(flags);
280            }
281
282            // exports_count and exports[exports_count];
283            attr.putShort(descriptor.exports().size());
284            for (Exports e : descriptor.exports()) {
285                String pkg = e.source().replace('.', '/');
286                attr.putShort(cw.newUTF8(pkg));
287
288                int flags = 0;
289                if (e.modifiers().contains(Exports.Modifier.SYNTHETIC))
290                    flags |= ACC_SYNTHETIC;
291                if (e.modifiers().contains(Exports.Modifier.MANDATED))
292                    flags |= ACC_MANDATED;
293                attr.putShort(flags);
294
295                if (e.isQualified()) {
296                    Set<String> ts = e.targets();
297                    attr.putShort(ts.size());
298                    ts.forEach(t -> attr.putShort(cw.newUTF8(t.replace('.', '/'))));
299                } else {
300                    attr.putShort(0);
301                }
302            }
303
304
305            // opens_counts and opens[opens_counts]
306            attr.putShort(descriptor.opens().size());
307            for (Opens obj : descriptor.opens()) {
308                String pkg = obj.source().replace('.', '/');
309                attr.putShort(cw.newUTF8(pkg));
310
311                int flags = 0;
312                if (obj.modifiers().contains(Opens.Modifier.SYNTHETIC))
313                    flags |= ACC_SYNTHETIC;
314                if (obj.modifiers().contains(Opens.Modifier.MANDATED))
315                    flags |= ACC_MANDATED;
316                attr.putShort(flags);
317
318                if (obj.isQualified()) {
319                    Set<String> ts = obj.targets();
320                    attr.putShort(ts.size());
321                    ts.forEach(t -> attr.putShort(cw.newUTF8(t.replace('.', '/'))));
322                } else {
323                    attr.putShort(0);
324                }
325            }
326
327            // uses_count and uses_index[uses_count]
328            if (descriptor.uses().isEmpty()) {
329                attr.putShort(0);
330            } else {
331                attr.putShort(descriptor.uses().size());
332                for (String s : descriptor.uses()) {
333                    String service = s.replace('.', '/');
334                    int index = cw.newClass(service);
335                    attr.putShort(index);
336                }
337            }
338
339            // provides_count and provides[provides_count]
340            if (descriptor.provides().isEmpty()) {
341                attr.putShort(0);
342            } else {
343                attr.putShort(descriptor.provides().size());
344                for (Provides p : descriptor.provides()) {
345                    String service = p.service().replace('.', '/');
346                    attr.putShort(cw.newClass(service));
347                    int with_count = p.providers().size();
348                    attr.putShort(with_count);
349                    for (String provider : p.providers()) {
350                        attr.putShort(cw.newClass(provider.replace('.', '/')));
351                    }
352                }
353            }
354
355            return attr;
356        }
357    }
358
359    /**
360     * ModulePackages attribute.
361     *
362     * <pre> {@code
363     *
364     * ModulePackages_attribute {
365     *   // index to CONSTANT_utf8_info structure in constant pool representing
366     *   // the string "ModulePackages"
367     *   u2 attribute_name_index;
368     *   u4 attribute_length;
369     *
370     *   // the number of entries in the packages table
371     *   u2 packages_count;
372     *   { // index to CONSTANT_CONSTANT_utf8_info structure with the package name
373     *     u2 package_index
374     *   } packages[package_count];
375     *
376     * }</pre>
377     */
378    public static class ModulePackagesAttribute extends Attribute {
379        private final Set<String> packages;
380
381        public ModulePackagesAttribute(Set<String> packages) {
382            super(MODULE_PACKAGES);
383            this.packages = packages;
384        }
385
386        public ModulePackagesAttribute() {
387            this(null);
388        }
389
390        @Override
391        protected Attribute read(ClassReader cr,
392                                 int off,
393                                 int len,
394                                 char[] buf,
395                                 int codeOff,
396                                 Label[] labels)
397        {
398            // package count
399            int package_count = cr.readUnsignedShort(off);
400            off += 2;
401
402            // packages
403            Set<String> packages = new HashSet<>();
404            for (int i=0; i<package_count; i++) {
405                String pkg = cr.readUTF8(off, buf).replace('/', '.');
406                packages.add(pkg);
407                off += 2;
408            }
409
410            return new ModulePackagesAttribute(packages);
411        }
412
413        @Override
414        protected ByteVector write(ClassWriter cw,
415                                   byte[] code,
416                                   int len,
417                                   int maxStack,
418                                   int maxLocals)
419        {
420            assert packages != null;
421
422            ByteVector attr = new ByteVector();
423
424            // package_count
425            attr.putShort(packages.size());
426
427            // packages
428            packages.stream()
429                .map(p -> p.replace('.', '/'))
430                .forEach(p -> attr.putShort(cw.newUTF8(p)));
431
432            return attr;
433        }
434
435    }
436
437    /**
438     * ModuleVersion attribute.
439     *
440     * <pre> {@code
441     *
442     * ModuleVersion_attribute {
443     *   // index to CONSTANT_utf8_info structure in constant pool representing
444     *   // the string "ModuleVersion"
445     *   u2 attribute_name_index;
446     *   u4 attribute_length;
447     *
448     *   // index to CONSTANT_CONSTANT_utf8_info structure with the version
449     *   u2 version_index;
450     * }
451     *
452     * } </pre>
453     */
454    public static class ModuleVersionAttribute extends Attribute {
455        private final Version version;
456
457        public ModuleVersionAttribute(Version version) {
458            super(MODULE_VERSION);
459            this.version = version;
460        }
461
462        public ModuleVersionAttribute() {
463            this(null);
464        }
465
466        @Override
467        protected Attribute read(ClassReader cr,
468                                 int off,
469                                 int len,
470                                 char[] buf,
471                                 int codeOff,
472                                 Label[] labels)
473        {
474            String value = cr.readUTF8(off, buf);
475            return new ModuleVersionAttribute(Version.parse(value));
476        }
477
478        @Override
479        protected ByteVector write(ClassWriter cw,
480                                   byte[] code,
481                                   int len,
482                                   int maxStack,
483                                   int maxLocals)
484        {
485            ByteVector attr = new ByteVector();
486            int index = cw.newUTF8(version.toString());
487            attr.putShort(index);
488            return attr;
489        }
490    }
491
492    /**
493     * ModuleMainClass attribute.
494     *
495     * <pre> {@code
496     *
497     * MainClass_attribute {
498     *   // index to CONSTANT_utf8_info structure in constant pool representing
499     *   // the string "ModuleMainClass"
500     *   u2 attribute_name_index;
501     *   u4 attribute_length;
502     *
503     *   // index to CONSTANT_Class_info structure with the main class name
504     *   u2 main_class_index;
505     * }
506     *
507     * } </pre>
508     */
509    public static class ModuleMainClassAttribute extends Attribute {
510        private final String mainClass;
511
512        public ModuleMainClassAttribute(String mainClass) {
513            super(MODULE_MAIN_CLASS);
514            this.mainClass = mainClass;
515        }
516
517        public ModuleMainClassAttribute() {
518            this(null);
519        }
520
521        @Override
522        protected Attribute read(ClassReader cr,
523                                 int off,
524                                 int len,
525                                 char[] buf,
526                                 int codeOff,
527                                 Label[] labels)
528        {
529            String value = cr.readClass(off, buf);
530            return new ModuleMainClassAttribute(value);
531        }
532
533        @Override
534        protected ByteVector write(ClassWriter cw,
535                                   byte[] code,
536                                   int len,
537                                   int maxStack,
538                                   int maxLocals)
539        {
540            ByteVector attr = new ByteVector();
541            int index = cw.newClass(mainClass);
542            attr.putShort(index);
543            return attr;
544        }
545    }
546
547    /**
548     * ModuleTarget attribute.
549     *
550     * <pre> {@code
551     *
552     * TargetPlatform_attribute {
553     *   // index to CONSTANT_utf8_info structure in constant pool representing
554     *   // the string "ModuleTarget"
555     *   u2 attribute_name_index;
556     *   u4 attribute_length;
557     *
558     *   // index to CONSTANT_CONSTANT_utf8_info structure with the OS name
559     *   u2 os_name_index;
560     *   // index to CONSTANT_CONSTANT_utf8_info structure with the OS arch
561     *   u2 os_arch_index
562     *   // index to CONSTANT_CONSTANT_utf8_info structure with the OS version
563     *   u2 os_version_index;
564     * }
565     *
566     * } </pre>
567     */
568    public static class ModuleTargetAttribute extends Attribute {
569        private final String osName;
570        private final String osArch;
571        private final String osVersion;
572
573        public ModuleTargetAttribute(String osName, String osArch, String osVersion) {
574            super(MODULE_TARGET);
575            this.osName = osName;
576            this.osArch = osArch;
577            this.osVersion = osVersion;
578        }
579
580        public ModuleTargetAttribute() {
581            this(null, null, null);
582        }
583
584        @Override
585        protected Attribute read(ClassReader cr,
586                                 int off,
587                                 int len,
588                                 char[] buf,
589                                 int codeOff,
590                                 Label[] labels)
591        {
592
593            String osName = null;
594            String osArch = null;
595            String osVersion = null;
596
597            int name_index = cr.readUnsignedShort(off);
598            if (name_index != 0)
599                osName = cr.readUTF8(off, buf);
600            off += 2;
601
602            int arch_index = cr.readUnsignedShort(off);
603            if (arch_index != 0)
604                osArch = cr.readUTF8(off, buf);
605            off += 2;
606
607            int version_index = cr.readUnsignedShort(off);
608            if (version_index != 0)
609                osVersion = cr.readUTF8(off, buf);
610            off += 2;
611
612            return new ModuleTargetAttribute(osName, osArch, osVersion);
613        }
614
615        @Override
616        protected ByteVector write(ClassWriter cw,
617                                   byte[] code,
618                                   int len,
619                                   int maxStack,
620                                   int maxLocals)
621        {
622            ByteVector attr = new ByteVector();
623
624            int name_index = 0;
625            if (osName != null && osName.length() > 0)
626                name_index = cw.newUTF8(osName);
627            attr.putShort(name_index);
628
629            int arch_index = 0;
630            if (osArch != null && osArch.length() > 0)
631                arch_index = cw.newUTF8(osArch);
632            attr.putShort(arch_index);
633
634            int version_index = 0;
635            if (osVersion != null && osVersion.length() > 0)
636                version_index = cw.newUTF8(osVersion);
637            attr.putShort(version_index);
638
639            return attr;
640        }
641    }
642
643    /**
644     * ModuleHashes attribute.
645     *
646     * <pre> {@code
647     *
648     * ModuleHashes_attribute {
649     *   // index to CONSTANT_utf8_info structure in constant pool representing
650     *   // the string "ModuleHashes"
651     *   u2 attribute_name_index;
652     *   u4 attribute_length;
653     *
654     *   // index to CONSTANT_utf8_info structure with algorithm name
655     *   u2 algorithm_index;
656     *
657     *   // the number of entries in the hashes table
658     *   u2 hashes_count;
659     *   {   u2 module_name_index
660     *       u2 hash_length;
661     *       u1 hash[hash_length];
662     *   } hashes[hashes_count];
663     *
664     * } </pre>
665     */
666    static class ModuleHashesAttribute extends Attribute {
667        private final ModuleHashes hashes;
668
669        ModuleHashesAttribute(ModuleHashes hashes) {
670            super(MODULE_HASHES);
671            this.hashes = hashes;
672        }
673
674        ModuleHashesAttribute() {
675            this(null);
676        }
677
678        @Override
679        protected Attribute read(ClassReader cr,
680                                 int off,
681                                 int len,
682                                 char[] buf,
683                                 int codeOff,
684                                 Label[] labels)
685        {
686            String algorithm = cr.readUTF8(off, buf);
687            off += 2;
688
689            int hashes_count = cr.readUnsignedShort(off);
690            off += 2;
691
692            Map<String, byte[]> map = new HashMap<>();
693            for (int i=0; i<hashes_count; i++) {
694                String mn = cr.readUTF8(off, buf).replace('/', '.');
695                off += 2;
696
697                int hash_length = cr.readUnsignedShort(off);
698                off += 2;
699                byte[] hash = new byte[hash_length];
700                for (int j=0; j<hash_length; j++) {
701                    hash[j] = (byte) (0xff & cr.readByte(off+j));
702                }
703                off += hash_length;
704
705                map.put(mn, hash);
706            }
707
708            ModuleHashes hashes = new ModuleHashes(algorithm, map);
709
710            return new ModuleHashesAttribute(hashes);
711        }
712
713        @Override
714        protected ByteVector write(ClassWriter cw,
715                                   byte[] code,
716                                   int len,
717                                   int maxStack,
718                                   int maxLocals)
719        {
720            ByteVector attr = new ByteVector();
721
722            int index = cw.newUTF8(hashes.algorithm());
723            attr.putShort(index);
724
725            Set<String> names = hashes.names();
726            attr.putShort(names.size());
727
728            for (String mn : names) {
729                byte[] hash = hashes.hashFor(mn);
730                assert hash != null;
731                attr.putShort(cw.newUTF8(mn.replace('.', '/')));
732
733                attr.putShort(hash.length);
734                for (byte b: hash) {
735                    attr.putByte(b);
736                }
737            }
738
739            return attr;
740        }
741    }
742
743}
744