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