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