1 /* 2 * Copyright (c) 2022, 2024, 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.classfile.impl; 27 28 import java.lang.classfile.*; 29 import java.lang.classfile.attribute.*; 30 import java.lang.classfile.constantpool.*; 31 import java.util.ArrayList; 32 import java.util.Collections; 33 import java.util.List; 34 import java.util.Objects; 35 import java.util.Optional; 36 import java.util.function.Function; 37 38 import jdk.internal.access.SharedSecrets; 39 40 import static java.lang.classfile.Attributes.*; 41 42 public abstract sealed class BoundAttribute<T extends Attribute<T>> 43 extends AbstractElement 44 implements Attribute<T>, Util.Writable { 45 46 static final int NAME_AND_LENGTH_PREFIX = 6; 47 private final AttributeMapper<T> mapper; 48 final ClassReaderImpl classReader; 49 final int payloadStart; 50 51 BoundAttribute(ClassReader classReader, AttributeMapper<T> mapper, int payloadStart) { 52 this.mapper = mapper; 53 this.classReader = (ClassReaderImpl)classReader; 54 this.payloadStart = payloadStart; 55 } 56 57 public int payloadLen() { 58 return classReader.readInt(payloadStart - 4); 59 } 60 61 @Override 62 public String attributeName() { 63 return mapper.name(); 64 } 65 66 @Override 67 public AttributeMapper<T> attributeMapper() { 68 return mapper; 69 } 70 71 public byte[] contents() { 72 return classReader.readBytes(payloadStart, payloadLen()); 73 } 74 75 @Override 76 public void writeTo(DirectClassBuilder builder) { 77 builder.writeAttribute(this); 78 } 79 80 @Override 81 public void writeTo(DirectCodeBuilder builder) { 82 builder.writeAttribute(this); 83 } 84 85 @Override 86 public void writeTo(DirectMethodBuilder builder) { 87 builder.writeAttribute(this); 88 } 89 90 @Override 91 public void writeTo(DirectFieldBuilder builder) { 92 builder.writeAttribute(this); 93 } 94 95 @Override 96 @SuppressWarnings("unchecked") 97 public void writeTo(BufWriterImpl buf) { 98 if (!buf.canWriteDirect(classReader)) 99 attributeMapper().writeAttribute(buf, (T) this); 100 else 101 classReader.copyBytesTo(buf, payloadStart - NAME_AND_LENGTH_PREFIX, payloadLen() + NAME_AND_LENGTH_PREFIX); 102 } 103 104 public ConstantPool constantPool() { 105 return classReader; 106 } 107 108 @Override 109 public String toString() { 110 return String.format("Attribute[name=%s]", mapper.name()); 111 } 112 113 <E extends PoolEntry> List<E> readEntryList(int p, Class<E> type) { 114 int cnt = classReader.readU2(p); 115 p += 2; 116 var entries = new Object[cnt]; 117 int end = p + (cnt * 2); 118 for (int i = 0; p < end; i++, p += 2) { 119 entries[i] = classReader.readEntry(p, type); 120 } 121 return SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(entries); 122 } 123 124 public static List<Attribute<?>> readAttributes(AttributedElement enclosing, ClassReader reader, int pos, 125 Function<Utf8Entry, AttributeMapper<?>> customAttributes) { 126 int size = reader.readU2(pos); 127 var filled = new ArrayList<Attribute<?>>(size); 128 int p = pos + 2; 129 int cfLen = reader.classfileLength(); 130 for (int i = 0; i < size; ++i) { 131 Utf8Entry name = reader.readEntry(p, Utf8Entry.class); 132 int len = reader.readInt(p + 2); 133 p += 6; 134 if (len < 0 || len > cfLen - p) { 135 throw new IllegalArgumentException("attribute " + name.stringValue() + " too big to handle"); 136 } 137 138 var mapper = standardAttribute(name); 139 if (mapper == null) { 140 mapper = customAttributes.apply(name); 141 } 142 if (mapper != null) { 143 filled.add(Objects.requireNonNull(mapper.readAttribute(enclosing, reader, p))); 144 } else { 145 AttributeMapper<UnknownAttribute> fakeMapper = new AttributeMapper<>() { 146 @Override 147 public String name() { 148 return name.stringValue(); 149 } 150 151 @Override 152 public UnknownAttribute readAttribute(AttributedElement enclosing, ClassReader cf, int pos) { 153 // Will never get called 154 throw new UnsupportedOperationException(); 155 } 156 157 @Override 158 public void writeAttribute(BufWriter buf, UnknownAttribute attr) { 159 buf.writeIndex(name); 160 var cont = attr.contents(); 161 buf.writeInt(cont.length); 162 buf.writeBytes(cont); 163 } 164 165 @Override 166 public boolean allowMultiple() { 167 return true; 168 } 169 170 @Override 171 public AttributeMapper.AttributeStability stability() { 172 return AttributeStability.UNKNOWN; 173 } 174 }; 175 filled.add(new BoundUnknownAttribute(reader, fakeMapper, p)); 176 } 177 p += len; 178 } 179 return Collections.unmodifiableList(filled); 180 } 181 182 public static final class BoundUnknownAttribute extends BoundAttribute<UnknownAttribute> 183 implements UnknownAttribute { 184 public BoundUnknownAttribute(ClassReader cf, AttributeMapper<UnknownAttribute> mapper, int pos) { 185 super(cf, mapper, pos); 186 } 187 } 188 189 public static final class BoundStackMapTableAttribute 190 extends BoundAttribute<StackMapTableAttribute> 191 implements StackMapTableAttribute { 192 final MethodModel method; 193 final LabelContext ctx; 194 List<StackMapFrameInfo> entries = null; 195 196 public BoundStackMapTableAttribute(CodeImpl code, ClassReader cf, AttributeMapper<StackMapTableAttribute> mapper, int pos) { 197 super(cf, mapper, pos); 198 method = code.parent().orElseThrow(); 199 ctx = code; 200 } 201 202 @Override 203 public List<StackMapFrameInfo> entries() { 204 if (entries == null) { 205 entries = new StackMapDecoder(classReader, payloadStart, ctx, StackMapDecoder.initFrameLocals(method)).entries(); 206 } 207 return entries; 208 } 209 } 210 211 public static final class BoundSyntheticAttribute extends BoundAttribute<SyntheticAttribute> 212 implements SyntheticAttribute { 213 public BoundSyntheticAttribute(ClassReader cf, AttributeMapper<SyntheticAttribute> mapper, int pos) { 214 super(cf, mapper, pos); 215 } 216 } 217 218 public static final class BoundLineNumberTableAttribute 219 extends BoundAttribute<LineNumberTableAttribute> 220 implements LineNumberTableAttribute { 221 private List<LineNumberInfo> lineNumbers = null; 222 223 public BoundLineNumberTableAttribute(ClassReader cf, AttributeMapper<LineNumberTableAttribute> mapper, int pos) { 224 super(cf, mapper, pos); 225 } 226 227 @Override 228 public List<LineNumberInfo> lineNumbers() { 229 if (lineNumbers == null) { 230 int nLn = classReader.readU2(payloadStart); 231 LineNumberInfo[] elements = new LineNumberInfo[nLn]; 232 int p = payloadStart + 2; 233 int pEnd = p + (nLn * 4); 234 for (int i = 0; p < pEnd; p += 4, i++) { 235 int startPc = classReader.readU2(p); 236 int lineNumber = classReader.readU2(p + 2); 237 elements[i] = LineNumberInfo.of(startPc, lineNumber); 238 } 239 lineNumbers = List.of(elements); 240 } 241 return lineNumbers; 242 } 243 } 244 245 public static final class BoundCharacterRangeTableAttribute extends BoundAttribute<CharacterRangeTableAttribute> implements CharacterRangeTableAttribute { 246 private List<CharacterRangeInfo> characterRangeTable = null; 247 248 public BoundCharacterRangeTableAttribute(ClassReader cf, AttributeMapper<CharacterRangeTableAttribute> mapper, int pos) { 249 super(cf, mapper, pos); 250 } 251 252 @Override 253 public List<CharacterRangeInfo> characterRangeTable() { 254 if (characterRangeTable == null) { 255 int nLn = classReader.readU2(payloadStart); 256 CharacterRangeInfo[] elements = new CharacterRangeInfo[nLn]; 257 int p = payloadStart + 2; 258 int pEnd = p + (nLn * 14); 259 for (int i = 0; p < pEnd; p += 14, i++) { 260 int startPc = classReader.readU2(p); 261 int endPc = classReader.readU2(p + 2); 262 int characterRangeStart = classReader.readInt(p + 4); 263 int characterRangeEnd = classReader.readInt(p + 8); 264 int flags = classReader.readU2(p + 12); 265 elements[i] = CharacterRangeInfo.of(startPc, endPc, characterRangeStart, characterRangeEnd, flags); 266 } 267 characterRangeTable = List.of(elements); 268 } 269 return characterRangeTable; 270 } 271 } 272 273 public static final class BoundLocalVariableTableAttribute 274 extends BoundAttribute<LocalVariableTableAttribute> 275 implements LocalVariableTableAttribute { 276 private final CodeImpl codeAttribute; 277 private List<LocalVariableInfo> localVars = null; 278 279 public BoundLocalVariableTableAttribute(AttributedElement enclosing, ClassReader cf, AttributeMapper<LocalVariableTableAttribute> mapper, int pos) { 280 super(cf, mapper, pos); 281 if (enclosing instanceof CodeImpl ci) { 282 this.codeAttribute = ci; 283 } else { 284 throw new IllegalArgumentException("Invalid LocalVariableTable attribute location"); 285 } 286 } 287 288 @Override 289 public List<LocalVariableInfo> localVariables() { 290 if (localVars == null) { 291 int cnt = classReader.readU2(payloadStart); 292 BoundLocalVariable[] elements = new BoundLocalVariable[cnt]; 293 int p = payloadStart + 2; 294 int pEnd = p + (cnt * 10); 295 for (int i = 0; p < pEnd; p += 10, i++) { 296 elements[i] = new BoundLocalVariable(codeAttribute, p); 297 } 298 localVars = List.of(elements); 299 } 300 return localVars; 301 } 302 } 303 304 public static final class BoundLocalVariableTypeTableAttribute 305 extends BoundAttribute<LocalVariableTypeTableAttribute> 306 implements LocalVariableTypeTableAttribute { 307 private final CodeImpl codeAttribute; 308 private List<LocalVariableTypeInfo> localVars = null; 309 310 public BoundLocalVariableTypeTableAttribute(AttributedElement enclosing, ClassReader cf, AttributeMapper<LocalVariableTypeTableAttribute> mapper, int pos) { 311 super(cf, mapper, pos); 312 if (enclosing instanceof CodeImpl ci) { 313 this.codeAttribute = ci; 314 } else { 315 throw new IllegalArgumentException("Invalid LocalVariableTypeTable attribute location"); 316 } 317 } 318 319 @Override 320 public List<LocalVariableTypeInfo> localVariableTypes() { 321 if (localVars == null) { 322 final int cnt = classReader.readU2(payloadStart); 323 BoundLocalVariableType[] elements = new BoundLocalVariableType[cnt]; 324 int p = payloadStart + 2; 325 int pEnd = p + (cnt * 10); 326 for (int i = 0; p < pEnd; p += 10, i++) { 327 elements[i] = new BoundLocalVariableType(codeAttribute, p); 328 } 329 localVars = List.of(elements); 330 } 331 return localVars; 332 } 333 } 334 335 public static final class BoundMethodParametersAttribute extends BoundAttribute<MethodParametersAttribute> 336 implements MethodParametersAttribute { 337 private List<MethodParameterInfo> parameters = null; 338 339 public BoundMethodParametersAttribute(ClassReader cf, AttributeMapper<MethodParametersAttribute> mapper, int pos) { 340 super(cf, mapper, pos); 341 } 342 343 @Override 344 public List<MethodParameterInfo> parameters() { 345 if (parameters == null) { 346 final int cnt = classReader.readU1(payloadStart); 347 MethodParameterInfo[] elements = new MethodParameterInfo[cnt]; 348 int p = payloadStart + 1; 349 int pEnd = p + (cnt * 4); 350 for (int i = 0; p < pEnd; p += 4, i++) { 351 Utf8Entry name = classReader.readEntryOrNull(p, Utf8Entry.class); 352 int accessFlags = classReader.readU2(p + 2); 353 elements[i] = MethodParameterInfo.of(Optional.ofNullable(name), accessFlags); 354 } 355 parameters = List.of(elements); 356 } 357 return parameters; 358 } 359 } 360 361 public static final class BoundModuleHashesAttribute extends BoundAttribute<ModuleHashesAttribute> 362 implements ModuleHashesAttribute { 363 private List<ModuleHashInfo> hashes = null; 364 365 public BoundModuleHashesAttribute(ClassReader cf, AttributeMapper<ModuleHashesAttribute> mapper, int pos) { 366 super(cf, mapper, pos); 367 } 368 369 @Override 370 public Utf8Entry algorithm() { 371 return classReader.readEntry(payloadStart, Utf8Entry.class); 372 } 373 374 @Override 375 public List<ModuleHashInfo> hashes() { 376 if (hashes == null) { 377 final int cnt = classReader.readU2(payloadStart + 2); 378 ModuleHashInfo[] elements = new ModuleHashInfo[cnt]; 379 int p = payloadStart + 4; 380 //System.err.printf("%5d: ModuleHashesAttr alg = %s, cnt = %d%n", pos, algorithm(), cnt); 381 for (int i = 0; i < cnt; ++i) { 382 ModuleEntry module = classReader.readEntry(p, ModuleEntry.class); 383 int hashLength = classReader.readU2(p + 2); 384 //System.err.printf("%5d: [%d] module = %s, hashLength = %d%n", p, i, module, hashLength); 385 p += 4; 386 elements[i] = ModuleHashInfo.of(module, classReader.readBytes(p, hashLength)); 387 p += hashLength; 388 } 389 hashes = List.of(elements); 390 } 391 return hashes; 392 } 393 } 394 395 public static final class BoundRecordAttribute extends BoundAttribute<RecordAttribute> 396 implements RecordAttribute { 397 private List<RecordComponentInfo> components = null; 398 399 public BoundRecordAttribute(ClassReader cf, AttributeMapper<RecordAttribute> mapper, int pos) { 400 super(cf, mapper, pos); 401 } 402 403 @Override 404 public List<RecordComponentInfo> components() { 405 if (components == null) { 406 final int cnt = classReader.readU2(payloadStart); 407 RecordComponentInfo[] elements = new RecordComponentInfo[cnt]; 408 int p = payloadStart + 2; 409 for (int i = 0; i < cnt; i++) { 410 elements[i] = new BoundRecordComponentInfo(classReader, p); 411 p = classReader.skipAttributeHolder(p + 4); 412 } 413 components = List.of(elements); 414 } 415 return components; 416 } 417 } 418 419 public static final class BoundDeprecatedAttribute extends BoundAttribute<DeprecatedAttribute> 420 implements DeprecatedAttribute { 421 public BoundDeprecatedAttribute(ClassReader cf, AttributeMapper<DeprecatedAttribute> mapper, int pos) { 422 super(cf, mapper, pos); 423 } 424 } 425 426 public static final class BoundSignatureAttribute extends BoundAttribute<SignatureAttribute> 427 implements SignatureAttribute { 428 public BoundSignatureAttribute(ClassReader cf, AttributeMapper<SignatureAttribute> mapper, int pos) { 429 super(cf, mapper, pos); 430 } 431 432 @Override 433 public Utf8Entry signature() { 434 return classReader.readEntry(payloadStart, Utf8Entry.class); 435 } 436 } 437 438 public static final class BoundSourceFileAttribute extends BoundAttribute<SourceFileAttribute> 439 implements SourceFileAttribute { 440 public BoundSourceFileAttribute(ClassReader cf, AttributeMapper<SourceFileAttribute> mapper, int pos) { 441 super(cf, mapper, pos); 442 } 443 444 @Override 445 public Utf8Entry sourceFile() { 446 return classReader.readEntry(payloadStart, Utf8Entry.class); 447 } 448 449 } 450 451 public static final class BoundModuleMainClassAttribute extends BoundAttribute<ModuleMainClassAttribute> implements ModuleMainClassAttribute { 452 public BoundModuleMainClassAttribute(ClassReader cf, AttributeMapper<ModuleMainClassAttribute> mapper, int pos) { 453 super(cf, mapper, pos); 454 } 455 456 @Override 457 public ClassEntry mainClass() { 458 return classReader.readEntry(payloadStart, ClassEntry.class); 459 } 460 } 461 462 public static final class BoundNestHostAttribute extends BoundAttribute<NestHostAttribute> 463 implements NestHostAttribute { 464 public BoundNestHostAttribute(ClassReader cf, AttributeMapper<NestHostAttribute> mapper, int pos) { 465 super(cf, mapper, pos); 466 } 467 468 @Override 469 public ClassEntry nestHost() { 470 return classReader.readEntry(payloadStart, ClassEntry.class); 471 } 472 } 473 474 public static final class BoundSourceDebugExtensionAttribute extends BoundAttribute<SourceDebugExtensionAttribute> 475 implements SourceDebugExtensionAttribute { 476 public BoundSourceDebugExtensionAttribute(ClassReader cf, AttributeMapper<SourceDebugExtensionAttribute> mapper, int pos) { 477 super(cf, mapper, pos); 478 } 479 } 480 481 public static final class BoundConstantValueAttribute extends BoundAttribute<ConstantValueAttribute> 482 implements ConstantValueAttribute { 483 public BoundConstantValueAttribute(ClassReader cf, AttributeMapper<ConstantValueAttribute> mapper, int pos) { 484 super(cf, mapper, pos); 485 } 486 487 @Override 488 public ConstantValueEntry constant() { 489 return classReader.readEntry(payloadStart, ConstantValueEntry.class); 490 } 491 492 } 493 494 public static final class BoundModuleTargetAttribute extends BoundAttribute<ModuleTargetAttribute> 495 implements ModuleTargetAttribute { 496 public BoundModuleTargetAttribute(ClassReader cf, AttributeMapper<ModuleTargetAttribute> mapper, int pos) { 497 super(cf, mapper, pos); 498 } 499 500 @Override 501 public Utf8Entry targetPlatform() { 502 return classReader.readEntry(payloadStart, Utf8Entry.class); 503 } 504 } 505 506 public static final class BoundCompilationIDAttribute extends BoundAttribute<CompilationIDAttribute> 507 implements CompilationIDAttribute { 508 public BoundCompilationIDAttribute(ClassReader cf, AttributeMapper<CompilationIDAttribute> mapper, int pos) { 509 super(cf, mapper, pos); 510 } 511 512 @Override 513 public Utf8Entry compilationId() { 514 return classReader.readEntry(payloadStart, Utf8Entry.class); 515 } 516 } 517 518 public static final class BoundSourceIDAttribute extends BoundAttribute<SourceIDAttribute> 519 implements SourceIDAttribute { 520 public BoundSourceIDAttribute(ClassReader cf, AttributeMapper<SourceIDAttribute> mapper, int pos) { 521 super(cf, mapper, pos); 522 } 523 524 @Override 525 public Utf8Entry sourceId() { 526 return classReader.readEntry(payloadStart, Utf8Entry.class); 527 } 528 } 529 530 public static final class BoundModuleResolutionAttribute extends BoundAttribute<ModuleResolutionAttribute> 531 implements ModuleResolutionAttribute { 532 public BoundModuleResolutionAttribute(ClassReader cf, AttributeMapper<ModuleResolutionAttribute> mapper, int pos) { 533 super(cf, mapper, pos); 534 } 535 536 @Override 537 public int resolutionFlags() { 538 return classReader.readU2(payloadStart); 539 } 540 } 541 542 public static final class BoundExceptionsAttribute extends BoundAttribute<ExceptionsAttribute> 543 implements ExceptionsAttribute { 544 private List<ClassEntry> exceptions = null; 545 546 public BoundExceptionsAttribute(ClassReader cf, AttributeMapper<ExceptionsAttribute> mapper, int pos) { 547 super(cf, mapper, pos); 548 } 549 550 @Override 551 public List<ClassEntry> exceptions() { 552 if (exceptions == null) { 553 exceptions = readEntryList(payloadStart, ClassEntry.class); 554 } 555 return exceptions; 556 } 557 } 558 559 public static final class BoundModuleAttribute extends BoundAttribute<ModuleAttribute> 560 implements ModuleAttribute { 561 private List<ModuleRequireInfo> requires = null; 562 private List<ModuleExportInfo> exports = null; 563 private List<ModuleOpenInfo> opens = null; 564 private List<ClassEntry> uses = null; 565 private List<ModuleProvideInfo> provides = null; 566 567 public BoundModuleAttribute(ClassReader cf, AttributeMapper<ModuleAttribute> mapper, int pos) { 568 super(cf, mapper, pos); 569 } 570 571 @Override 572 public ModuleEntry moduleName() { 573 return classReader.readEntry(payloadStart, ModuleEntry.class); 574 } 575 576 @Override 577 public int moduleFlagsMask() { 578 return classReader.readU2(payloadStart + 2); 579 } 580 581 @Override 582 public Optional<Utf8Entry> moduleVersion() { 583 return Optional.ofNullable(classReader.readEntryOrNull(payloadStart + 4, Utf8Entry.class)); 584 } 585 586 @Override 587 public List<ModuleRequireInfo> requires() { 588 if (requires == null) { 589 structure(); 590 } 591 return requires; 592 } 593 594 @Override 595 public List<ModuleExportInfo> exports() { 596 if (exports == null) { 597 structure(); 598 } 599 return exports; 600 } 601 602 @Override 603 public List<ModuleOpenInfo> opens() { 604 if (opens == null) { 605 structure(); 606 } 607 return opens; 608 } 609 610 @Override 611 public List<ClassEntry> uses() { 612 if (uses == null) { 613 structure(); 614 } 615 return uses; 616 } 617 618 @Override 619 public List<ModuleProvideInfo> provides() { 620 if (provides == null) { 621 structure(); 622 } 623 return provides; 624 } 625 626 private void structure() { 627 int p = payloadStart + 8; 628 629 { 630 int cnt = classReader.readU2(payloadStart + 6); 631 ModuleRequireInfo[] elements = new ModuleRequireInfo[cnt]; 632 int end = p + (cnt * 6); 633 for (int i = 0; p < end; p += 6, i++) { 634 elements[i] = ModuleRequireInfo.of(classReader.readEntry(p, ModuleEntry.class), 635 classReader.readU2(p + 2), 636 classReader.readEntryOrNull(p + 4, Utf8Entry.class)); 637 } 638 requires = List.of(elements); 639 } 640 641 { 642 int cnt = classReader.readU2(p); 643 p += 2; 644 ModuleExportInfo[] elements = new ModuleExportInfo[cnt]; 645 for (int i = 0; i < cnt; i++) { 646 PackageEntry pe = classReader.readEntry(p, PackageEntry.class); 647 int exportFlags = classReader.readU2(p + 2); 648 p += 4; 649 List<ModuleEntry> exportsTo = readEntryList(p, ModuleEntry.class); 650 p += 2 + exportsTo.size() * 2; 651 elements[i] = ModuleExportInfo.of(pe, exportFlags, exportsTo); 652 } 653 exports = List.of(elements); 654 } 655 656 { 657 int cnt = classReader.readU2(p); 658 p += 2; 659 ModuleOpenInfo[] elements = new ModuleOpenInfo[cnt]; 660 for (int i = 0; i < cnt; i++) { 661 PackageEntry po = classReader.readEntry(p, PackageEntry.class); 662 int opensFlags = classReader.readU2(p + 2); 663 p += 4; 664 List<ModuleEntry> opensTo = readEntryList(p, ModuleEntry.class); 665 p += 2 + opensTo.size() * 2; 666 elements[i] = ModuleOpenInfo.of(po, opensFlags, opensTo); 667 } 668 opens = List.of(elements); 669 } 670 671 { 672 uses = readEntryList(p, ClassEntry.class); 673 p += 2 + uses.size() * 2; 674 int cnt = classReader.readU2(p); 675 p += 2; 676 ModuleProvideInfo[] elements = new ModuleProvideInfo[cnt]; 677 provides = new ArrayList<>(cnt); 678 for (int i = 0; i < cnt; i++) { 679 ClassEntry c = classReader.readEntry(p, ClassEntry.class); 680 p += 2; 681 List<ClassEntry> providesWith = readEntryList(p, ClassEntry.class); 682 p += 2 + providesWith.size() * 2; 683 elements[i] = ModuleProvideInfo.of(c, providesWith); 684 } 685 provides = List.of(elements); 686 } 687 } 688 } 689 690 public static final class BoundModulePackagesAttribute extends BoundAttribute<ModulePackagesAttribute> 691 implements ModulePackagesAttribute { 692 private List<PackageEntry> packages = null; 693 694 public BoundModulePackagesAttribute(ClassReader cf, AttributeMapper<ModulePackagesAttribute> mapper, int pos) { 695 super(cf, mapper, pos); 696 } 697 698 @Override 699 public List<PackageEntry> packages() { 700 if (packages == null) { 701 packages = readEntryList(payloadStart, PackageEntry.class); 702 } 703 return packages; 704 } 705 } 706 707 public static final class BoundNestMembersAttribute extends BoundAttribute<NestMembersAttribute> 708 implements NestMembersAttribute { 709 710 private List<ClassEntry> members = null; 711 712 public BoundNestMembersAttribute(ClassReader cf, AttributeMapper<NestMembersAttribute> mapper, int pos) { 713 super(cf, mapper, pos); 714 } 715 716 @Override 717 public List<ClassEntry> nestMembers() { 718 if (members == null) { 719 members = readEntryList(payloadStart, ClassEntry.class); 720 } 721 return members; 722 } 723 } 724 725 public static final class BoundBootstrapMethodsAttribute extends BoundAttribute<BootstrapMethodsAttribute> 726 implements BootstrapMethodsAttribute { 727 728 private List<BootstrapMethodEntry> bootstraps = null; 729 private final int size; 730 731 public BoundBootstrapMethodsAttribute(ClassReader reader, AttributeMapper<BootstrapMethodsAttribute> mapper, int pos) { 732 super(reader, mapper, pos); 733 size = classReader.readU2(pos); 734 } 735 736 @Override 737 public int bootstrapMethodsSize() { 738 return size; 739 } 740 741 @Override 742 public List<BootstrapMethodEntry> bootstrapMethods() { 743 if (bootstraps == null) { 744 BootstrapMethodEntry[] bs = new BootstrapMethodEntry[size]; 745 int p = payloadStart + 2; 746 for (int i = 0; i < size; ++i) { 747 final var handle = classReader.readEntry(p, AbstractPoolEntry.MethodHandleEntryImpl.class); 748 final List<LoadableConstantEntry> args = readEntryList(p + 2, LoadableConstantEntry.class); 749 p += 4 + args.size() * 2; 750 int hash = BootstrapMethodEntryImpl.computeHashCode(handle, args); 751 bs[i] = new BootstrapMethodEntryImpl(classReader, i, hash, handle, args); 752 } 753 bootstraps = List.of(bs); 754 } 755 return bootstraps; 756 } 757 } 758 759 public static final class BoundInnerClassesAttribute extends BoundAttribute<InnerClassesAttribute> 760 implements InnerClassesAttribute { 761 private List<InnerClassInfo> classes; 762 763 public BoundInnerClassesAttribute(ClassReader cf, AttributeMapper<InnerClassesAttribute> mapper, int pos) { 764 super(cf, mapper, pos); 765 } 766 767 @Override 768 public List<InnerClassInfo> classes() { 769 if (classes == null) { 770 final int cnt = classReader.readU2(payloadStart); 771 int p = payloadStart + 2; 772 InnerClassInfo[] elements = new InnerClassInfo[cnt]; 773 for (int i = 0; i < cnt; i++) { 774 ClassEntry innerClass = classReader.readEntry(p, ClassEntry.class); 775 var outerClass = classReader.readEntryOrNull(p + 2, ClassEntry.class); 776 var innerName = classReader.readEntryOrNull(p + 4, Utf8Entry.class); 777 int flags = classReader.readU2(p + 6); 778 p += 8; 779 elements[i] = InnerClassInfo.of(innerClass, Optional.ofNullable(outerClass), Optional.ofNullable(innerName), flags); 780 } 781 classes = List.of(elements); 782 } 783 return classes; 784 } 785 } 786 787 public static final class BoundEnclosingMethodAttribute extends BoundAttribute<EnclosingMethodAttribute> 788 implements EnclosingMethodAttribute { 789 public BoundEnclosingMethodAttribute(ClassReader cf, AttributeMapper<EnclosingMethodAttribute> mapper, int pos) { 790 super(cf, mapper, pos); 791 } 792 793 @Override 794 public ClassEntry enclosingClass() { 795 return classReader.readEntry(payloadStart, ClassEntry.class); 796 } 797 798 @Override 799 public Optional<NameAndTypeEntry> enclosingMethod() { 800 return Optional.ofNullable(classReader.readEntryOrNull(payloadStart + 2, NameAndTypeEntry.class)); 801 } 802 } 803 804 public static final class BoundAnnotationDefaultAttr 805 extends BoundAttribute<AnnotationDefaultAttribute> 806 implements AnnotationDefaultAttribute { 807 private AnnotationValue annotationValue; 808 809 public BoundAnnotationDefaultAttr(ClassReader cf, AttributeMapper<AnnotationDefaultAttribute> mapper, int pos) { 810 super(cf, mapper, pos); 811 } 812 813 @Override 814 public AnnotationValue defaultValue() { 815 if (annotationValue == null) 816 annotationValue = AnnotationReader.readElementValue(classReader, payloadStart); 817 return annotationValue; 818 } 819 } 820 821 public static final class BoundRuntimeVisibleTypeAnnotationsAttribute extends BoundAttribute<RuntimeVisibleTypeAnnotationsAttribute> 822 implements RuntimeVisibleTypeAnnotationsAttribute { 823 824 private final LabelContext labelContext; 825 826 public BoundRuntimeVisibleTypeAnnotationsAttribute(AttributedElement enclosing, ClassReader cf, AttributeMapper<RuntimeVisibleTypeAnnotationsAttribute> mapper, int pos) { 827 super(cf, mapper, pos); 828 this.labelContext = (enclosing instanceof LabelContext lc) ? lc : null; 829 } 830 831 @Override 832 public List<TypeAnnotation> annotations() { 833 return AnnotationReader.readTypeAnnotations(classReader, payloadStart, labelContext); 834 } 835 } 836 837 public static final class BoundRuntimeInvisibleTypeAnnotationsAttribute 838 extends BoundAttribute<RuntimeInvisibleTypeAnnotationsAttribute> 839 implements RuntimeInvisibleTypeAnnotationsAttribute { 840 public BoundRuntimeInvisibleTypeAnnotationsAttribute(AttributedElement enclosing, ClassReader cf, AttributeMapper<RuntimeInvisibleTypeAnnotationsAttribute> mapper, int pos) { 841 super(cf, mapper, pos); 842 this.labelContext = (enclosing instanceof LabelContext lc) ? lc : null; 843 } 844 845 private final LabelContext labelContext; 846 847 @Override 848 public List<TypeAnnotation> annotations() { 849 return AnnotationReader.readTypeAnnotations(classReader, payloadStart, labelContext); 850 } 851 } 852 853 public static final class BoundRuntimeVisibleParameterAnnotationsAttribute 854 extends BoundAttribute<RuntimeVisibleParameterAnnotationsAttribute> 855 implements RuntimeVisibleParameterAnnotationsAttribute { 856 857 public BoundRuntimeVisibleParameterAnnotationsAttribute(ClassReader cf, AttributeMapper<RuntimeVisibleParameterAnnotationsAttribute> mapper, int pos) { 858 super(cf, mapper, pos); 859 } 860 861 @Override 862 public List<List<Annotation>> parameterAnnotations() { 863 return AnnotationReader.readParameterAnnotations(classReader, payloadStart); 864 } 865 } 866 867 public static final class BoundRuntimeInvisibleParameterAnnotationsAttribute 868 extends BoundAttribute<RuntimeInvisibleParameterAnnotationsAttribute> 869 implements RuntimeInvisibleParameterAnnotationsAttribute { 870 871 public BoundRuntimeInvisibleParameterAnnotationsAttribute(ClassReader cf, AttributeMapper<RuntimeInvisibleParameterAnnotationsAttribute> mapper, int pos) { 872 super(cf, mapper, pos); 873 } 874 875 @Override 876 public List<List<Annotation>> parameterAnnotations() { 877 return AnnotationReader.readParameterAnnotations(classReader, payloadStart); 878 } 879 } 880 881 public static final class BoundRuntimeInvisibleAnnotationsAttribute 882 extends BoundAttribute<RuntimeInvisibleAnnotationsAttribute> 883 implements RuntimeInvisibleAnnotationsAttribute { 884 private List<Annotation> inflated; 885 886 public BoundRuntimeInvisibleAnnotationsAttribute(ClassReader cf, 887 int payloadStart) { 888 super(cf, Attributes.runtimeInvisibleAnnotations(), payloadStart); 889 } 890 891 @Override 892 public List<Annotation> annotations() { 893 if (inflated == null) 894 inflated = AnnotationReader.readAnnotations(classReader, payloadStart); 895 return inflated; 896 } 897 } 898 899 public static final class BoundRuntimeVisibleAnnotationsAttribute 900 extends BoundAttribute<RuntimeVisibleAnnotationsAttribute> 901 implements RuntimeVisibleAnnotationsAttribute { 902 private List<Annotation> inflated; 903 904 public BoundRuntimeVisibleAnnotationsAttribute(ClassReader cf, 905 int payloadStart) { 906 super(cf, Attributes.runtimeVisibleAnnotations(), payloadStart); 907 } 908 909 @Override 910 public List<Annotation> annotations() { 911 if (inflated == null) 912 inflated = AnnotationReader.readAnnotations(classReader, payloadStart); 913 return inflated; 914 } 915 } 916 917 public static final class BoundPermittedSubclassesAttribute extends BoundAttribute<PermittedSubclassesAttribute> 918 implements PermittedSubclassesAttribute { 919 private List<ClassEntry> permittedSubclasses = null; 920 921 public BoundPermittedSubclassesAttribute(ClassReader cf, AttributeMapper<PermittedSubclassesAttribute> mapper, int pos) { 922 super(cf, mapper, pos); 923 } 924 925 @Override 926 public List<ClassEntry> permittedSubclasses() { 927 if (permittedSubclasses == null) { 928 permittedSubclasses = readEntryList(payloadStart, ClassEntry.class); 929 } 930 return permittedSubclasses; 931 } 932 } 933 934 public abstract static sealed class BoundCodeAttribute 935 extends BoundAttribute<CodeAttribute> 936 implements CodeAttribute 937 permits CodeImpl { 938 protected final int codeStart; 939 protected final int codeLength; 940 protected final int codeEnd; 941 protected final int attributePos; 942 protected final int exceptionHandlerPos; 943 protected final int exceptionHandlerCnt; 944 protected final MethodModel enclosingMethod; 945 946 public BoundCodeAttribute(AttributedElement enclosing, 947 ClassReader reader, 948 AttributeMapper<CodeAttribute> mapper, 949 int payloadStart) { 950 super(reader, mapper, payloadStart); 951 this.codeLength = classReader.readInt(payloadStart + 4); 952 this.enclosingMethod = (MethodModel) enclosing; 953 this.codeStart = payloadStart + 8; 954 this.codeEnd = codeStart + codeLength; 955 this.exceptionHandlerPos = codeEnd; 956 this.exceptionHandlerCnt = classReader.readU2(exceptionHandlerPos); 957 this.attributePos = exceptionHandlerPos + 2 + exceptionHandlerCnt * 8; 958 } 959 960 // CodeAttribute 961 962 @Override 963 public int maxStack() { 964 return classReader.readU2(payloadStart); 965 } 966 967 @Override 968 public int maxLocals() { 969 return classReader.readU2(payloadStart + 2); 970 } 971 972 @Override 973 public int codeLength() { 974 return codeLength; 975 } 976 977 @Override 978 public byte[] codeArray() { 979 return classReader.readBytes(payloadStart + 8, codeLength()); 980 } 981 } 982 983 /** 984 * {@return the attribute mapper for a standard attribute} 985 * 986 * @param name the name of the attribute to find 987 */ 988 public static AttributeMapper<?> standardAttribute(Utf8Entry name) { 989 // critical bootstrap path, so no lambdas nor method handles here 990 return switch (name.hashCode()) { 991 case 0x46699ff2 -> 992 name.equalsString(NAME_ANNOTATION_DEFAULT) ? annotationDefault() : null; 993 case 0x5208e184 -> 994 name.equalsString(NAME_BOOTSTRAP_METHODS) ? bootstrapMethods() : null; 995 case 0xcb60907a -> 996 name.equalsString(NAME_CHARACTER_RANGE_TABLE) ? characterRangeTable() : null; 997 case 0x4020220d -> 998 name.equalsString(NAME_CODE) ? code() : null; 999 case 0xc20dd1fe -> 1000 name.equalsString(NAME_COMPILATION_ID) ? compilationId() : null; 1001 case 0xcab1940d -> 1002 name.equalsString(NAME_CONSTANT_VALUE) ? constantValue() : null; 1003 case 0x558641d3 -> 1004 name.equalsString(NAME_DEPRECATED) ? deprecated() : null; 1005 case 0x51d443cd -> 1006 name.equalsString(NAME_ENCLOSING_METHOD) ? enclosingMethod() : null; 1007 case 0x687c1624 -> 1008 name.equalsString(NAME_EXCEPTIONS) ? exceptions() : null; 1009 case 0x7adb2910 -> 1010 name.equalsString(NAME_INNER_CLASSES) ? innerClasses() : null; 1011 case 0x653f0551 -> 1012 name.equalsString(NAME_LINE_NUMBER_TABLE) ? lineNumberTable() : null; 1013 case 0x64c75927 -> 1014 name.equalsString(NAME_LOCAL_VARIABLE_TABLE) ? localVariableTable() : null; 1015 case 0x6697f98d -> 1016 name.equalsString(NAME_LOCAL_VARIABLE_TYPE_TABLE) ? localVariableTypeTable() : null; 1017 case 0xdbb0cdcb -> 1018 name.equalsString(NAME_METHOD_PARAMETERS) ? methodParameters() : null; 1019 case 0xc9b0928c -> 1020 name.equalsString(NAME_MODULE) ? module() : null; 1021 case 0x41cd27e8 -> 1022 name.equalsString(NAME_MODULE_HASHES) ? moduleHashes() : null; 1023 case 0x7deb0a13 -> 1024 name.equalsString(NAME_MODULE_MAIN_CLASS) ? moduleMainClass() : null; 1025 case 0x6706ff99 -> 1026 name.equalsString(NAME_MODULE_PACKAGES) ? modulePackages() : null; 1027 case 0x60272858 -> 1028 name.equalsString(NAME_MODULE_RESOLUTION) ? moduleResolution() : null; 1029 case 0x5646d73d -> 1030 name.equalsString(NAME_MODULE_TARGET) ? moduleTarget() : null; 1031 case 0x50336c40 -> 1032 name.equalsString(NAME_NEST_HOST) ? nestHost() : null; 1033 case 0x4735ab81 -> 1034 name.equalsString(NAME_NEST_MEMBERS) ? nestMembers() : null; 1035 case 0x7100d9fe -> 1036 name.equalsString(NAME_PERMITTED_SUBCLASSES) ? permittedSubclasses() : null; 1037 case 0xd1ab5871 -> 1038 name.equalsString(NAME_RECORD) ? record() : null; 1039 case 0x7588550f -> 1040 name.equalsString(NAME_RUNTIME_INVISIBLE_ANNOTATIONS) ? runtimeInvisibleAnnotations() : null; 1041 case 0xcc74da30 -> 1042 name.equalsString(NAME_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS) ? runtimeInvisibleParameterAnnotations() : null; 1043 case 0xf67697f5 -> 1044 name.equalsString(NAME_RUNTIME_INVISIBLE_TYPE_ANNOTATIONS) ? runtimeInvisibleTypeAnnotations() : null; 1045 case 0xe0837d2a -> 1046 name.equalsString(NAME_RUNTIME_VISIBLE_ANNOTATIONS) ? runtimeVisibleAnnotations() : null; 1047 case 0xc945a075 -> 1048 name.equalsString(NAME_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS) ? runtimeVisibleParameterAnnotations() : null; 1049 case 0x611a3a90 -> 1050 name.equalsString(NAME_RUNTIME_VISIBLE_TYPE_ANNOTATIONS) ? runtimeVisibleTypeAnnotations() : null; 1051 case 0xf76fb898 -> 1052 name.equalsString(NAME_SIGNATURE) ? signature() : null; 1053 case 0x6b41b047 -> 1054 name.equalsString(NAME_SOURCE_DEBUG_EXTENSION) ? sourceDebugExtension() : null; 1055 case 0x748c2857 -> 1056 name.equalsString(NAME_SOURCE_FILE) ? sourceFile() : null; 1057 case 0x6bf13a96 -> 1058 name.equalsString(NAME_SOURCE_ID) ? sourceId() : null; 1059 case 0xfa85ee5a -> 1060 name.equalsString(NAME_STACK_MAP_TABLE) ? stackMapTable() : null; 1061 case 0xf2670725 -> 1062 name.equalsString(NAME_SYNTHETIC) ? synthetic() : null; 1063 default -> null; 1064 }; 1065 } 1066 }