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