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); 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 } 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 } | 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 private Version replacementVersion; 72 73 public ModuleAttribute(ModuleDescriptor descriptor) { 74 super(MODULE); 75 this.descriptor = descriptor; 76 } 77 78 public ModuleAttribute(Version v) { 79 super(MODULE); 80 this.replacementVersion = v; 81 } 82 83 public ModuleAttribute() { 84 super(MODULE); 85 } 86 87 @Override 88 protected Attribute read(ClassReader cr, 89 int off, 90 int len, 91 char[] buf, 92 int codeOff, 93 Label[] labels) 94 { 95 // module_name (CONSTANT_Module_info) 96 String mn = cr.readModule(off, buf); 97 off += 2; 98 99 // module_flags 100 int module_flags = cr.readUnsignedShort(off); 101 boolean open = ((module_flags & ACC_OPEN) != 0); 102 boolean synthetic = ((module_flags & ACC_SYNTHETIC) != 0); 103 off += 2; 104 105 ModuleDescriptor.Builder builder = JLMA.newModuleBuilder(mn, 106 false, 107 open, 108 synthetic); 109 110 // module_version 111 String module_version = cr.readUTF8(off, buf); 112 off += 2; 113 if (replacementVersion != null) { 114 builder.version(replacementVersion); 115 } else if (module_version != null) { 116 builder.version(module_version); 117 } 118 119 // requires_count and requires[requires_count] 120 int requires_count = cr.readUnsignedShort(off); 121 off += 2; 122 for (int i=0; i<requires_count; i++) { 123 // CONSTANT_Module_info 124 String dn = cr.readModule(off, buf); 125 off += 2; 126 127 // requires_flags 128 int requires_flags = cr.readUnsignedShort(off); 129 off += 2; 130 Set<Requires.Modifier> mods; 131 if (requires_flags == 0) { 132 mods = Collections.emptySet(); 133 } else { 134 mods = new HashSet<>(); 135 if ((requires_flags & ACC_TRANSITIVE) != 0) 136 mods.add(Requires.Modifier.TRANSITIVE); 137 if ((requires_flags & ACC_STATIC_PHASE) != 0) 138 mods.add(Requires.Modifier.STATIC); 139 if ((requires_flags & ACC_SYNTHETIC) != 0) 140 mods.add(Requires.Modifier.SYNTHETIC); 141 if ((requires_flags & ACC_MANDATED) != 0) 142 mods.add(Requires.Modifier.MANDATED); 143 } 144 145 146 // requires_version 147 Version compiledVersion = null; 148 String requires_version = cr.readUTF8(off, buf); 149 off += 2; 150 if (requires_version != null) { 151 compiledVersion = Version.parse(requires_version); 152 } 153 154 if (compiledVersion == null) { 155 builder.requires(mods, dn); 156 } else { 157 builder.requires(mods, dn, compiledVersion); 158 } 159 } 160 161 // exports_count and exports[exports_count] 162 int exports_count = cr.readUnsignedShort(off); 163 off += 2; 164 if (exports_count > 0) { 165 for (int i=0; i<exports_count; i++) { 166 // CONSTANT_Package_info 167 String pkg = cr.readPackage(off, buf).replace('/', '.'); 168 off += 2; 169 170 int exports_flags = cr.readUnsignedShort(off); 171 off += 2; 172 Set<Exports.Modifier> mods; 173 if (exports_flags == 0) { 174 mods = Collections.emptySet(); 175 } else { 176 mods = new HashSet<>(); 177 if ((exports_flags & ACC_SYNTHETIC) != 0) 178 mods.add(Exports.Modifier.SYNTHETIC); 179 if ((exports_flags & ACC_MANDATED) != 0) 180 mods.add(Exports.Modifier.MANDATED); 181 } 182 183 int exports_to_count = cr.readUnsignedShort(off); 184 off += 2; 185 if (exports_to_count > 0) { 186 Set<String> targets = new HashSet<>(); 187 for (int j=0; j<exports_to_count; j++) { 188 String t = cr.readModule(off, buf); 189 off += 2; 190 targets.add(t); 191 } 192 builder.exports(mods, pkg, targets); 193 } else { 194 builder.exports(mods, pkg); 195 } 196 } 197 } 198 199 // opens_count and opens[opens_count] 200 int open_count = cr.readUnsignedShort(off); 201 off += 2; 202 if (open_count > 0) { 203 for (int i=0; i<open_count; i++) { 204 // CONSTANT_Package_info 205 String pkg = cr.readPackage(off, buf).replace('/', '.'); 206 off += 2; 207 208 int opens_flags = cr.readUnsignedShort(off); 209 off += 2; 210 Set<Opens.Modifier> mods; 211 if (opens_flags == 0) { 212 mods = Collections.emptySet(); 213 } else { 214 mods = new HashSet<>(); 215 if ((opens_flags & ACC_SYNTHETIC) != 0) 216 mods.add(Opens.Modifier.SYNTHETIC); 217 if ((opens_flags & ACC_MANDATED) != 0) 218 mods.add(Opens.Modifier.MANDATED); 219 } 220 221 int opens_to_count = cr.readUnsignedShort(off); 222 off += 2; 223 if (opens_to_count > 0) { 224 Set<String> targets = new HashSet<>(); 225 for (int j=0; j<opens_to_count; j++) { 226 String t = cr.readModule(off, buf); 227 off += 2; 228 targets.add(t); 229 } 230 builder.opens(mods, pkg, targets); 231 } else { 232 builder.opens(mods, pkg); 233 } 234 } 235 } 236 237 // uses_count and uses_index[uses_count] 238 int uses_count = cr.readUnsignedShort(off); 239 off += 2; 240 if (uses_count > 0) { 241 for (int i=0; i<uses_count; i++) { 242 String sn = cr.readClass(off, buf).replace('/', '.'); 243 builder.uses(sn); 244 off += 2; 245 } 246 } 247 248 // provides_count and provides[provides_count] 249 int provides_count = cr.readUnsignedShort(off); 250 off += 2; 251 if (provides_count > 0) { 252 for (int i=0; i<provides_count; i++) { 253 String service = cr.readClass(off, buf).replace('/', '.'); 254 off += 2; 255 int with_count = cr.readUnsignedShort(off); 256 off += 2; 257 List<String> providers = new ArrayList<>(); 258 for (int j=0; j<with_count; j++) { 259 String cn = cr.readClass(off, buf).replace('/', '.'); 260 off += 2; 261 providers.add(cn); 262 } 263 builder.provides(service, providers); 264 } 265 } 266 267 return new ModuleAttribute(builder.build()); 268 } 269 270 @Override 271 protected ByteVector write(ClassWriter cw, 272 byte[] code, 273 int len, 274 int maxStack, 275 int maxLocals) 276 { 277 assert descriptor != null; 278 ByteVector attr = new ByteVector(); 279 280 // module_name 281 String mn = descriptor.name(); 282 int module_name_index = cw.newModule(mn); 283 attr.putShort(module_name_index); 284 285 // module_flags 286 int module_flags = 0; 287 if (descriptor.isOpen()) 288 module_flags |= ACC_OPEN; 289 if (descriptor.isSynthetic()) 290 module_flags |= ACC_SYNTHETIC; 291 attr.putShort(module_flags); 292 293 // module_version 294 Version v = descriptor.version().orElse(null); 295 if (v == null) { 296 attr.putShort(0); 297 } else { 298 int module_version_index = cw.newUTF8(v.toString()); 299 attr.putShort(module_version_index); 300 } 301 302 // requires_count 303 attr.putShort(descriptor.requires().size()); 304 305 // requires[requires_count] 306 for (Requires r : descriptor.requires()) { 307 int requires_index = cw.newModule(r.name()); 308 attr.putShort(requires_index); 309 310 int requires_flags = 0; 311 if (r.modifiers().contains(Requires.Modifier.TRANSITIVE)) 312 requires_flags |= ACC_TRANSITIVE; 313 if (r.modifiers().contains(Requires.Modifier.STATIC)) 314 requires_flags |= ACC_STATIC_PHASE; 315 if (r.modifiers().contains(Requires.Modifier.SYNTHETIC)) 316 requires_flags |= ACC_SYNTHETIC; 317 if (r.modifiers().contains(Requires.Modifier.MANDATED)) 318 requires_flags |= ACC_MANDATED; 319 attr.putShort(requires_flags); 320 321 int requires_version_index; 322 v = r.compiledVersion().orElse(null); 323 if (v == null) { 324 requires_version_index = 0; 325 } else { 326 requires_version_index = cw.newUTF8(v.toString()); 327 } 328 attr.putShort(requires_version_index); 329 } 330 331 // exports_count and exports[exports_count]; 332 attr.putShort(descriptor.exports().size()); 333 for (Exports e : descriptor.exports()) { 334 String pkg = e.source().replace('.', '/'); 335 attr.putShort(cw.newPackage(pkg)); 336 337 int exports_flags = 0; 338 if (e.modifiers().contains(Exports.Modifier.SYNTHETIC)) 339 exports_flags |= ACC_SYNTHETIC; 340 if (e.modifiers().contains(Exports.Modifier.MANDATED)) 341 exports_flags |= ACC_MANDATED; 342 attr.putShort(exports_flags); 343 344 if (e.isQualified()) { 345 Set<String> ts = e.targets(); 346 attr.putShort(ts.size()); 347 ts.forEach(target -> attr.putShort(cw.newModule(target))); 348 } else { 349 attr.putShort(0); 350 } 351 } 352 353 // opens_counts and opens[opens_counts] 354 attr.putShort(descriptor.opens().size()); 355 for (Opens obj : descriptor.opens()) { 356 String pkg = obj.source().replace('.', '/'); 357 attr.putShort(cw.newPackage(pkg)); 358 359 int opens_flags = 0; 360 if (obj.modifiers().contains(Opens.Modifier.SYNTHETIC)) 361 opens_flags |= ACC_SYNTHETIC; 362 if (obj.modifiers().contains(Opens.Modifier.MANDATED)) 363 opens_flags |= ACC_MANDATED; 364 attr.putShort(opens_flags); 365 366 if (obj.isQualified()) { 367 Set<String> ts = obj.targets(); 368 attr.putShort(ts.size()); 369 ts.forEach(target -> attr.putShort(cw.newModule(target))); 370 } else { 371 attr.putShort(0); 372 } 373 } 374 375 // uses_count and uses_index[uses_count] 376 if (descriptor.uses().isEmpty()) { 377 attr.putShort(0); 378 } else { 379 attr.putShort(descriptor.uses().size()); 380 for (String s : descriptor.uses()) { 381 String service = s.replace('.', '/'); 382 int index = cw.newClass(service); 383 attr.putShort(index); 384 } 385 } 386 387 // provides_count and provides[provides_count] 388 if (descriptor.provides().isEmpty()) { 389 attr.putShort(0); 400 } 401 } 402 403 return attr; 404 } 405 } 406 407 /** 408 * ModulePackages attribute. 409 * 410 * <pre> {@code 411 * 412 * ModulePackages_attribute { 413 * // index to CONSTANT_utf8_info structure in constant pool representing 414 * // the string "ModulePackages" 415 * u2 attribute_name_index; 416 * u4 attribute_length; 417 * 418 * // the number of entries in the packages table 419 * u2 packages_count; 420 * { // index to CONSTANT_Package_info structure with the package name 421 * u2 package_index 422 * } packages[package_count]; 423 * 424 * }</pre> 425 */ 426 public static class ModulePackagesAttribute extends Attribute { 427 private final Set<String> packages; 428 429 public ModulePackagesAttribute(Set<String> packages) { 430 super(MODULE_PACKAGES); 431 this.packages = packages; 432 } 433 434 public ModulePackagesAttribute() { 435 this(null); 436 } 437 438 @Override 439 protected Attribute read(ClassReader cr, 440 int off, 441 int len, 442 char[] buf, 443 int codeOff, 444 Label[] labels) 445 { 446 // package count 447 int package_count = cr.readUnsignedShort(off); 448 off += 2; 449 450 // packages 451 Set<String> packages = new HashSet<>(); 452 for (int i=0; i<package_count; i++) { 453 String pkg = cr.readPackage(off, buf).replace('/', '.'); 454 packages.add(pkg); 455 off += 2; 456 } 457 458 return new ModulePackagesAttribute(packages); 459 } 460 461 @Override 462 protected ByteVector write(ClassWriter cw, 463 byte[] code, 464 int len, 465 int maxStack, 466 int maxLocals) 467 { 468 assert packages != null; 469 470 ByteVector attr = new ByteVector(); 471 472 // package_count 473 attr.putShort(packages.size()); 474 475 // packages 476 packages.stream() 477 .map(p -> p.replace('.', '/')) 478 .forEach(p -> attr.putShort(cw.newPackage(p))); 479 480 return attr; 481 } 482 483 } 484 485 /** 486 * ModuleMainClass attribute. 487 * 488 * <pre> {@code 489 * 490 * MainClass_attribute { 491 * // index to CONSTANT_utf8_info structure in constant pool representing 492 * // the string "ModuleMainClass" 493 * u2 attribute_name_index; 494 * u4 attribute_length; 495 * 496 * // index to CONSTANT_Class_info structure with the main class name 497 * u2 main_class_index; 498 * } 499 * 500 * } </pre> 501 */ 502 public static class ModuleMainClassAttribute extends Attribute { 503 private final String mainClass; 504 505 public ModuleMainClassAttribute(String mainClass) { 506 super(MODULE_MAIN_CLASS); 507 this.mainClass = mainClass; 508 } 509 510 public ModuleMainClassAttribute() { 511 this(null); 512 } 513 514 @Override 515 protected Attribute read(ClassReader cr, 516 int off, 517 int len, 518 char[] buf, 519 int codeOff, 520 Label[] labels) 521 { 522 String value = cr.readClass(off, buf).replace('/', '.'); 523 return new ModuleMainClassAttribute(value); 524 } 525 526 @Override 527 protected ByteVector write(ClassWriter cw, 528 byte[] code, 529 int len, 530 int maxStack, 531 int maxLocals) 532 { 533 ByteVector attr = new ByteVector(); 534 int index = cw.newClass(mainClass.replace('.', '/')); 535 attr.putShort(index); 536 return attr; 537 } 538 } 539 540 /** 541 * ModuleTarget attribute. 542 * 543 * <pre> {@code 544 * 545 * TargetPlatform_attribute { 546 * // index to CONSTANT_utf8_info structure in constant pool representing 547 * // the string "ModuleTarget" 548 * u2 attribute_name_index; 549 * u4 attribute_length; 550 * 551 * // index to CONSTANT_utf8_info structure with the OS name 552 * u2 os_name_index; 553 * // index to CONSTANT_utf8_info structure with the OS arch 554 * u2 os_arch_index 555 * // index to CONSTANT_utf8_info structure with the OS version 556 * u2 os_version_index; 557 * } 558 * 559 * } </pre> 560 */ 561 public static class ModuleTargetAttribute extends Attribute { 562 private final String osName; 563 private final String osArch; 564 private final String osVersion; 565 566 public ModuleTargetAttribute(String osName, String osArch, String osVersion) { 567 super(MODULE_TARGET); 568 this.osName = osName; 569 this.osArch = osArch; 570 this.osVersion = osVersion; 571 } 572 573 public ModuleTargetAttribute() { 574 this(null, null, null); 575 } 632 return attr; 633 } 634 } 635 636 /** 637 * ModuleHashes attribute. 638 * 639 * <pre> {@code 640 * 641 * ModuleHashes_attribute { 642 * // index to CONSTANT_utf8_info structure in constant pool representing 643 * // the string "ModuleHashes" 644 * u2 attribute_name_index; 645 * u4 attribute_length; 646 * 647 * // index to CONSTANT_utf8_info structure with algorithm name 648 * u2 algorithm_index; 649 * 650 * // the number of entries in the hashes table 651 * u2 hashes_count; 652 * { u2 module_name_index (index to CONSTANT_Module_info structure) 653 * u2 hash_length; 654 * u1 hash[hash_length]; 655 * } hashes[hashes_count]; 656 * 657 * } </pre> 658 */ 659 static class ModuleHashesAttribute extends Attribute { 660 private final ModuleHashes hashes; 661 662 ModuleHashesAttribute(ModuleHashes hashes) { 663 super(MODULE_HASHES); 664 this.hashes = hashes; 665 } 666 667 ModuleHashesAttribute() { 668 this(null); 669 } 670 671 @Override 672 protected Attribute read(ClassReader cr, 673 int off, 674 int len, 675 char[] buf, 676 int codeOff, 677 Label[] labels) 678 { 679 String algorithm = cr.readUTF8(off, buf); 680 off += 2; 681 682 int hashes_count = cr.readUnsignedShort(off); 683 off += 2; 684 685 Map<String, byte[]> map = new HashMap<>(); 686 for (int i=0; i<hashes_count; i++) { 687 String mn = cr.readModule(off, buf); 688 off += 2; 689 690 int hash_length = cr.readUnsignedShort(off); 691 off += 2; 692 byte[] hash = new byte[hash_length]; 693 for (int j=0; j<hash_length; j++) { 694 hash[j] = (byte) (0xff & cr.readByte(off+j)); 695 } 696 off += hash_length; 697 698 map.put(mn, hash); 699 } 700 701 ModuleHashes hashes = new ModuleHashes(algorithm, map); 702 703 return new ModuleHashesAttribute(hashes); 704 } 705 706 @Override 707 protected ByteVector write(ClassWriter cw, 708 byte[] code, 709 int len, 710 int maxStack, 711 int maxLocals) 712 { 713 ByteVector attr = new ByteVector(); 714 715 int index = cw.newUTF8(hashes.algorithm()); 716 attr.putShort(index); 717 718 Set<String> names = hashes.names(); 719 attr.putShort(names.size()); 720 721 for (String mn : names) { 722 byte[] hash = hashes.hashFor(mn); 723 assert hash != null; 724 attr.putShort(cw.newModule(mn)); 725 726 attr.putShort(hash.length); 727 for (byte b: hash) { 728 attr.putByte(b); 729 } 730 } 731 732 return attr; 733 } 734 } 735 736 /** 737 * ModuleResolution_attribute { 738 * u2 attribute_name_index; // "ModuleResolution" 739 * u4 attribute_length; // 2 740 * u2 resolution_flags; 741 * 742 * The value of the resolution_flags item is a mask of flags used to denote 743 * properties of module resolution. The flags are as follows: 744 * 745 * // Optional 746 * 0x0001 (DO_NOT_RESOLVE_BY_DEFAULT) 747 * 748 * // At most one of: 749 * 0x0002 (WARN_DEPRECATED) 750 * 0x0004 (WARN_DEPRECATED_FOR_REMOVAL) 751 * 0x0008 (WARN_INCUBATING) 752 */ 753 static class ModuleResolutionAttribute extends Attribute { 754 private final int value; 755 756 ModuleResolutionAttribute() { 757 super(MODULE_RESOLUTION); 758 value = 0; 759 } 760 761 ModuleResolutionAttribute(int value) { 762 super(MODULE_RESOLUTION); 763 this.value = value; 764 } 765 766 @Override 767 protected Attribute read(ClassReader cr, 768 int off, 769 int len, 770 char[] buf, 771 int codeOff, 772 Label[] labels) 773 { 774 int flags = cr.readUnsignedShort(off); 775 return new ModuleResolutionAttribute(flags); 776 } 777 778 @Override 779 protected ByteVector write(ClassWriter cw, 780 byte[] code, 781 int len, 782 int maxStack, 783 int maxLocals) 784 { 785 ByteVector attr = new ByteVector(); 786 attr.putShort(value); 787 return attr; 788 } 789 } 790 } |