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