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