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
26package jdk.internal.module;
27
28import java.lang.module.ModuleDescriptor;
29import java.lang.module.ModuleDescriptor.Builder;
30import java.lang.module.ModuleDescriptor.Requires;
31import java.lang.module.ModuleDescriptor.Exports;
32import java.lang.module.ModuleDescriptor.Opens;
33import java.lang.module.ModuleDescriptor.Provides;
34import java.lang.module.ModuleDescriptor.Version;
35import java.util.ArrayList;
36import java.util.Collections;
37import java.util.HashMap;
38import java.util.HashSet;
39import java.util.List;
40import java.util.Map;
41import java.util.Set;
42
43import jdk.internal.misc.JavaLangModuleAccess;
44import jdk.internal.misc.SharedSecrets;
45import jdk.internal.org.objectweb.asm.Attribute;
46import jdk.internal.org.objectweb.asm.ByteVector;
47import jdk.internal.org.objectweb.asm.ClassReader;
48import jdk.internal.org.objectweb.asm.ClassWriter;
49import jdk.internal.org.objectweb.asm.Label;
50import 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
58public 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}
766