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