ClassFileAttributes.java revision 13901:b2a69d66dc65
10SN/A/*
22362SN/A * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
30SN/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
40SN/A *
50SN/A * This code is free software; you can redistribute it and/or modify it
60SN/A * under the terms of the GNU General Public License version 2 only, as
72362SN/A * published by the Free Software Foundation.  Oracle designates this
80SN/A * particular file as subject to the "Classpath" exception as provided
92362SN/A * by Oracle in the LICENSE file that accompanied this code.
100SN/A *
110SN/A * This code is distributed in the hope that it will be useful, but WITHOUT
120SN/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
130SN/A * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
140SN/A * version 2 for more details (a copy is included in the LICENSE file that
150SN/A * accompanied this code).
160SN/A *
170SN/A * You should have received a copy of the GNU General Public License version
180SN/A * 2 along with this work; if not, write to the Free Software Foundation,
190SN/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
200SN/A *
212362SN/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
222362SN/A * or visit www.oracle.com if you need additional information or have any
232362SN/A * questions.
240SN/A */
250SN/A
260SN/Apackage jdk.internal.module;
270SN/A
280SN/Aimport java.lang.module.ModuleDescriptor;
290SN/Aimport java.lang.module.ModuleDescriptor.Requires;
300SN/Aimport java.lang.module.ModuleDescriptor.Requires.Modifier;
310SN/Aimport java.lang.module.ModuleDescriptor.Exports;
320SN/Aimport java.lang.module.ModuleDescriptor.Provides;
330SN/Aimport java.lang.module.ModuleDescriptor.Version;
340SN/Aimport java.util.Collections;
350SN/Aimport java.util.HashMap;
3610071SN/Aimport java.util.HashSet;
370SN/Aimport java.util.Map;
380SN/Aimport java.util.Set;
390SN/A
400SN/Aimport jdk.internal.org.objectweb.asm.Attribute;
410SN/Aimport jdk.internal.org.objectweb.asm.ByteVector;
420SN/Aimport jdk.internal.org.objectweb.asm.ClassReader;
430SN/Aimport jdk.internal.org.objectweb.asm.ClassWriter;
440SN/Aimport jdk.internal.org.objectweb.asm.Label;
450SN/Aimport jdk.internal.module.Hasher.DependencyHashes;
460SN/Aimport static jdk.internal.module.ClassFileConstants.*;
470SN/A
480SN/A
490SN/A/**
500SN/A * Provides ASM implementations of {@code Attribute} to read and write the
510SN/A * class file attributes in a module-info class file.
520SN/A */
530SN/A
540SN/Aclass ClassFileAttributes {
550SN/A
560SN/A    private ClassFileAttributes() { }
570SN/A
580SN/A    /**
590SN/A     * Module_attribute {
600SN/A     *   // See lang-vm.html for details.
610SN/A     * }
620SN/A     */
630SN/A    static class ModuleAttribute extends Attribute {
640SN/A
650SN/A        private ModuleDescriptor descriptor;
660SN/A
670SN/A        ModuleAttribute(ModuleDescriptor descriptor) {
680SN/A            super(MODULE);
690SN/A            this.descriptor = descriptor;
700SN/A        }
710SN/A
720SN/A        ModuleAttribute() {
730SN/A            super(MODULE);
740SN/A        }
750SN/A
760SN/A        @Override
770SN/A        protected Attribute read(ClassReader cr,
780SN/A                                 int off,
790SN/A                                 int len,
800SN/A                                 char[] buf,
810SN/A                                 int codeOff,
820SN/A                                 Label[] labels)
830SN/A        {
840SN/A            ModuleDescriptor.Builder builder
850SN/A                = new ModuleDescriptor.Builder("xyzzy"); // Name never used
860SN/A            ModuleAttribute attr = new ModuleAttribute();
8710071SN/A
880SN/A            // requires_count and requires[requires_count]
890SN/A            int requires_count = cr.readUnsignedShort(off);
900SN/A            off += 2;
910SN/A            for (int i=0; i<requires_count; i++) {
920SN/A                String dn = cr.readUTF8(off, buf);
930SN/A                int flags = cr.readUnsignedShort(off + 2);
940SN/A                Set<Modifier> mods;
950SN/A                if (flags == 0) {
960SN/A                    mods = Collections.emptySet();
970SN/A                } else {
980SN/A                    mods = new HashSet<>();
990SN/A                    if ((flags & ACC_PUBLIC) != 0)
1000SN/A                        mods.add(Modifier.PUBLIC);
1010SN/A                    if ((flags & ACC_SYNTHETIC) != 0)
1020SN/A                        mods.add(Modifier.SYNTHETIC);
1030SN/A                    if ((flags & ACC_MANDATED) != 0)
1040SN/A                        mods.add(Modifier.MANDATED);
1050SN/A                }
1060SN/A                builder.requires(mods, dn);
1070SN/A                off += 4;
1080SN/A            }
1090SN/A
1100SN/A            // exports_count and exports[exports_count]
1110SN/A            int exports_count = cr.readUnsignedShort(off);
1120SN/A            off += 2;
1130SN/A            if (exports_count > 0) {
1140SN/A                for (int i=0; i<exports_count; i++) {
1150SN/A                    String pkg = cr.readUTF8(off, buf).replace('/', '.');
1160SN/A                    int exports_to_count = cr.readUnsignedShort(off+2);
11710071SN/A                    off += 4;
1180SN/A                    if (exports_to_count > 0) {
1190SN/A                        Set<String> targets = new HashSet<>();
1200SN/A                        for (int j=0; j<exports_to_count; j++) {
1210SN/A                            String t = cr.readUTF8(off, buf);
1220SN/A                            off += 2;
1230SN/A                            targets.add(t);
1240SN/A                        }
1250SN/A                        builder.exports(pkg, targets);
1260SN/A                    } else {
1270SN/A                        builder.exports(pkg);
1280SN/A                    }
1290SN/A                }
1300SN/A            }
1310SN/A
1320SN/A            // uses_count and uses_index[uses_count]
1330SN/A            int uses_count = cr.readUnsignedShort(off);
1340SN/A            off += 2;
1350SN/A            if (uses_count > 0) {
1360SN/A                for (int i=0; i<uses_count; i++) {
1370SN/A                    String sn = cr.readClass(off, buf).replace('/', '.');
13810071SN/A                    builder.uses(sn);
1390SN/A                    off += 2;
1400SN/A                }
1410SN/A            }
1420SN/A
1430SN/A            // provides_count and provides[provides_count]
1440SN/A            int provides_count = cr.readUnsignedShort(off);
1450SN/A            off += 2;
1460SN/A            if (provides_count > 0) {
1470SN/A                Map<String, Set<String>> provides = new HashMap<>();
1480SN/A                for (int i=0; i<provides_count; i++) {
1490SN/A                    String sn = cr.readClass(off, buf).replace('/', '.');
1500SN/A                    String cn = cr.readClass(off + 2, buf).replace('/', '.');
1510SN/A                    provides.computeIfAbsent(sn, k -> new HashSet<>()).add(cn);
1520SN/A                    off += 4;
1530SN/A                }
1540SN/A                provides.entrySet().forEach(e -> builder.provides(e.getKey(),
1550SN/A                                                                  e.getValue()));
1560SN/A            }
1570SN/A
1580SN/A            attr.descriptor = builder.build();
1590SN/A            return attr;
16010071SN/A        }
1610SN/A
1620SN/A        @Override
1630SN/A        protected ByteVector write(ClassWriter cw,
1640SN/A                                   byte[] code,
1650SN/A                                   int len,
1660SN/A                                   int maxStack,
1670SN/A                                   int maxLocals)
1680SN/A        {
1690SN/A            assert descriptor != null;
1700SN/A            ByteVector attr = new ByteVector();
17110071SN/A
1720SN/A            // requires_count
1730SN/A            attr.putShort(descriptor.requires().size());
1740SN/A
1750SN/A            // requires[requires_count]
1760SN/A            for (Requires md : descriptor.requires()) {
1770SN/A                String dn = md.name();
1780SN/A                int flags = 0;
1790SN/A                if (md.modifiers().contains(Modifier.PUBLIC))
1800SN/A                    flags |= ACC_PUBLIC;
1810SN/A                if (md.modifiers().contains(Modifier.SYNTHETIC))
1820SN/A                    flags |= ACC_SYNTHETIC;
18310071SN/A                if (md.modifiers().contains(Modifier.MANDATED))
1840SN/A                    flags |= ACC_MANDATED;
1850SN/A                int index = cw.newUTF8(dn);
1860SN/A                attr.putShort(index);
1870SN/A                attr.putShort(flags);
1880SN/A            }
1890SN/A
1900SN/A            // exports_count and exports[exports_count];
19110071SN/A            if (descriptor.exports().isEmpty()) {
1920SN/A                attr.putShort(0);
1930SN/A            } else {
1940SN/A                attr.putShort(descriptor.exports().size());
1950SN/A                for (Exports e : descriptor.exports()) {
196                    String pkg = e.source().replace('.', '/');
197                    attr.putShort(cw.newUTF8(pkg));
198                    if (e.isQualified()) {
199                        Set<String> ts = e.targets();
200                        attr.putShort(ts.size());
201                        ts.forEach(t -> attr.putShort(cw.newUTF8(t)));
202                    } else {
203                        attr.putShort(0);
204                    }
205                }
206            }
207
208            // uses_count and uses_index[uses_count]
209            if (descriptor.uses().isEmpty()) {
210                attr.putShort(0);
211            } else {
212                attr.putShort(descriptor.uses().size());
213                for (String s : descriptor.uses()) {
214                    String service = s.replace('.', '/');
215                    int index = cw.newClass(service);
216                    attr.putShort(index);
217                }
218            }
219
220            // provides_count and provides[provides_count]
221            if (descriptor.provides().isEmpty()) {
222                attr.putShort(0);
223            } else {
224                int count = descriptor.provides().values()
225                    .stream().mapToInt(ps -> ps.providers().size()).sum();
226                attr.putShort(count);
227                for (Provides p : descriptor.provides().values()) {
228                    String service = p.service().replace('.', '/');
229                    int index = cw.newClass(service);
230                    for (String provider : p.providers()) {
231                        attr.putShort(index);
232                        attr.putShort(cw.newClass(provider.replace('.', '/')));
233                    }
234                }
235            }
236
237            return attr;
238        }
239    }
240
241    /**
242     * Synthetic attribute.
243     */
244    static class SyntheticAttribute extends Attribute {
245        SyntheticAttribute() {
246            super(SYNTHETIC);
247        }
248
249        @Override
250        protected Attribute read(ClassReader cr,
251                                 int off,
252                                 int len,
253                                 char[] buf,
254                                 int codeOff,
255                                 Label[] labels)
256        {
257            return new SyntheticAttribute();
258        }
259
260        @Override
261        protected ByteVector write(ClassWriter cw,
262                                   byte[] code,
263                                   int len,
264                                   int maxStack,
265                                   int maxLocals)
266        {
267            ByteVector attr = new ByteVector();
268            return attr;
269        }
270    }
271
272    /**
273     * ConcealedPackages attribute.
274     *
275     * <pre> {@code
276     *
277     * ConcealedPackages_attribute {
278     *   // index to CONSTANT_utf8_info structure in constant pool representing
279     *   // the string "ConcealedPackages"
280     *   u2 attribute_name_index;
281     *   u4 attribute_length;
282     *
283     *   // the number of entries in the packages table
284     *   u2 package_count;
285     *   { // index to CONSTANT_CONSTANT_utf8_info structure with the package name
286     *     u2 package_index
287     *   } package[package_count];
288     *
289     * }</pre>
290     */
291    static class ConcealedPackagesAttribute extends Attribute {
292        private final Set<String> packages;
293
294        ConcealedPackagesAttribute(Set<String> packages) {
295            super(CONCEALED_PACKAGES);
296            this.packages = packages;
297        }
298
299        ConcealedPackagesAttribute() {
300            this(null);
301        }
302
303        @Override
304        protected Attribute read(ClassReader cr,
305                                 int off,
306                                 int len,
307                                 char[] buf,
308                                 int codeOff,
309                                 Label[] labels)
310        {
311            // package count
312            int package_count = cr.readUnsignedShort(off);
313            off += 2;
314
315            // packages
316            Set<String> packages = new HashSet<>();
317            for (int i=0; i<package_count; i++) {
318                String pkg = cr.readUTF8(off, buf).replace('/', '.');
319                packages.add(pkg);
320                off += 2;
321            }
322
323            return new ConcealedPackagesAttribute(packages);
324        }
325
326        @Override
327        protected ByteVector write(ClassWriter cw,
328                                   byte[] code,
329                                   int len,
330                                   int maxStack,
331                                   int maxLocals)
332        {
333            assert packages != null;
334
335            ByteVector attr = new ByteVector();
336
337            // package_count
338            attr.putShort(packages.size());
339
340            // packages
341            packages.stream()
342                .map(p -> p.replace('.', '/'))
343                .forEach(p -> attr.putShort(cw.newUTF8(p)));
344
345            return attr;
346        }
347
348    }
349
350    /**
351     * Version attribute.
352     *
353     * <pre> {@code
354     *
355     * Version_attribute {
356     *   // index to CONSTANT_utf8_info structure in constant pool representing
357     *   // the string "Version"
358     *   u2 attribute_name_index;
359     *   u4 attribute_length;
360     *
361     *   // index to CONSTANT_CONSTANT_utf8_info structure with the version
362     *   u2 version_index;
363     * }
364     *
365     * } </pre>
366     */
367    static class VersionAttribute extends Attribute {
368        private final Version version;
369
370        VersionAttribute(Version version) {
371            super(VERSION);
372            this.version = version;
373        }
374
375        VersionAttribute() {
376            this(null);
377        }
378
379        @Override
380        protected Attribute read(ClassReader cr,
381                                 int off,
382                                 int len,
383                                 char[] buf,
384                                 int codeOff,
385                                 Label[] labels)
386        {
387            String value = cr.readUTF8(off, buf);
388            return new VersionAttribute(Version.parse(value));
389        }
390
391        @Override
392        protected ByteVector write(ClassWriter cw,
393                                   byte[] code,
394                                   int len,
395                                   int maxStack,
396                                   int maxLocals)
397        {
398            ByteVector attr = new ByteVector();
399            int index = cw.newUTF8(version.toString());
400            attr.putShort(index);
401            return attr;
402        }
403    }
404
405    /**
406     * MainClass attribute.
407     *
408     * <pre> {@code
409     *
410     * MainClass_attribute {
411     *   // index to CONSTANT_utf8_info structure in constant pool representing
412     *   // the string "MainClass"
413     *   u2 attribute_name_index;
414     *   u4 attribute_length;
415     *
416     *   // index to CONSTANT_Class_info structure with the main class name
417     *   u2 main_class_index;
418     * }
419     *
420     * } </pre>
421     */
422    static class MainClassAttribute extends Attribute {
423        private final String mainClass;
424
425        MainClassAttribute(String mainClass) {
426            super(MAIN_CLASS);
427            this.mainClass = mainClass;
428        }
429
430        MainClassAttribute() {
431            this(null);
432        }
433
434        @Override
435        protected Attribute read(ClassReader cr,
436                                 int off,
437                                 int len,
438                                 char[] buf,
439                                 int codeOff,
440                                 Label[] labels)
441        {
442            String value = cr.readClass(off, buf);
443            return new MainClassAttribute(value);
444        }
445
446        @Override
447        protected ByteVector write(ClassWriter cw,
448                                   byte[] code,
449                                   int len,
450                                   int maxStack,
451                                   int maxLocals)
452        {
453            ByteVector attr = new ByteVector();
454            int index = cw.newClass(mainClass);
455            attr.putShort(index);
456            return attr;
457        }
458    }
459
460    /**
461     * TargetPlatform attribute.
462     *
463     * <pre> {@code
464     *
465     * TargetPlatform_attribute {
466     *   // index to CONSTANT_utf8_info structure in constant pool representing
467     *   // the string "TargetPlatform"
468     *   u2 attribute_name_index;
469     *   u4 attribute_length;
470     *
471     *   // index to CONSTANT_CONSTANT_utf8_info structure with the OS name
472     *   u2 os_name_index;
473     *   // index to CONSTANT_CONSTANT_utf8_info structure with the OS arch
474     *   u2 os_arch_index
475     *   // index to CONSTANT_CONSTANT_utf8_info structure with the OS version
476     *   u2 os_version_index;
477     * }
478     *
479     * } </pre>
480     */
481    static class TargetPlatformAttribute extends Attribute {
482        private final String osName;
483        private final String osArch;
484        private final String osVersion;
485
486        TargetPlatformAttribute(String osName, String osArch, String osVersion) {
487            super(TARGET_PLATFORM);
488            this.osName = osName;
489            this.osArch = osArch;
490            this.osVersion = osVersion;
491        }
492
493        TargetPlatformAttribute() {
494            this(null, null, null);
495        }
496
497        @Override
498        protected Attribute read(ClassReader cr,
499                                 int off,
500                                 int len,
501                                 char[] buf,
502                                 int codeOff,
503                                 Label[] labels)
504        {
505
506            String osName = null;
507            String osArch = null;
508            String osVersion = null;
509
510            int name_index = cr.readUnsignedShort(off);
511            if (name_index != 0)
512                osName = cr.readUTF8(off, buf);
513            off += 2;
514
515            int arch_index = cr.readUnsignedShort(off);
516            if (arch_index != 0)
517                osArch = cr.readUTF8(off, buf);
518            off += 2;
519
520            int version_index = cr.readUnsignedShort(off);
521            if (version_index != 0)
522                osVersion = cr.readUTF8(off, buf);
523            off += 2;
524
525            return new TargetPlatformAttribute(osName, osArch, osVersion);
526        }
527
528        @Override
529        protected ByteVector write(ClassWriter cw,
530                                   byte[] code,
531                                   int len,
532                                   int maxStack,
533                                   int maxLocals)
534        {
535            ByteVector attr = new ByteVector();
536
537            int name_index = 0;
538            if (osName != null && osName.length() > 0)
539                name_index = cw.newUTF8(osName);
540            attr.putShort(name_index);
541
542            int arch_index = 0;
543            if (osArch != null && osArch.length() > 0)
544                arch_index = cw.newUTF8(osArch);
545            attr.putShort(arch_index);
546
547            int version_index = 0;
548            if (osVersion != null && osVersion.length() > 0)
549                version_index = cw.newUTF8(osVersion);
550            attr.putShort(version_index);
551
552            return attr;
553        }
554    }
555
556    /**
557     * Hashes attribute.
558     *
559     * <pre> {@code
560     *
561     * Hashes_attribute {
562     *   // index to CONSTANT_utf8_info structure in constant pool representing
563     *   // the string "Hashes"
564     *   u2 attribute_name_index;
565     *   u4 attribute_length;
566     *
567     *   // index to CONSTANT_CONSTANT_utf8_info structure with algorithm name
568     *   u2 algorithm_index;
569     *
570     *   // the number of entries in the hashes table
571     *   u2 hash_count;
572     *   {   u2 requires_index
573     *       u2 hash_index;
574     *   } hashes[hash_count];
575     *
576     * } </pre>
577     *
578     * @apiNote For now the hash is stored in base64 as a UTF-8 string, an
579     * alternative is to store it as an array of u1.
580     */
581    static class HashesAttribute extends Attribute {
582        private final DependencyHashes hashes;
583
584        HashesAttribute(DependencyHashes hashes) {
585            super(HASHES);
586            this.hashes = hashes;
587        }
588
589        HashesAttribute() {
590            this(null);
591        }
592
593        @Override
594        protected Attribute read(ClassReader cr,
595                                 int off,
596                                 int len,
597                                 char[] buf,
598                                 int codeOff,
599                                 Label[] labels)
600        {
601            String algorithm = cr.readUTF8(off, buf);
602            off += 2;
603
604            int hash_count = cr.readUnsignedShort(off);
605            off += 2;
606
607            Map<String, String> map = new HashMap<>();
608            for (int i=0; i<hash_count; i++) {
609                String dn = cr.readUTF8(off, buf);
610                off += 2;
611                String hash = cr.readUTF8(off, buf);
612                off += 2;
613                map.put(dn, hash);
614            }
615
616            DependencyHashes hashes = new DependencyHashes(algorithm, map);
617
618            return new HashesAttribute(hashes);
619        }
620
621        @Override
622        protected ByteVector write(ClassWriter cw,
623                                   byte[] code,
624                                   int len,
625                                   int maxStack,
626                                   int maxLocals)
627        {
628            ByteVector attr = new ByteVector();
629
630            int index = cw.newUTF8(hashes.algorithm());
631            attr.putShort(index);
632
633            Set<String> names = hashes.names();
634            attr.putShort(names.size());
635
636            for (String dn : names) {
637                String hash = hashes.hashFor(dn);
638                assert hash != null;
639                attr.putShort(cw.newUTF8(dn));
640                attr.putShort(cw.newUTF8(hash));
641            }
642
643            return attr;
644        }
645    }
646
647}
648