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