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 abstract static sealed class BoundCodeAttribute
 943             extends BoundAttribute<CodeAttribute>
 944             implements CodeAttribute
 945             permits CodeImpl {
 946         protected final int codeStart;
 947         protected final int codeLength;
 948         protected final int codeEnd;
 949         protected final int attributePos;
 950         protected final int exceptionHandlerPos;
 951         protected final int exceptionHandlerCnt;
 952         protected final MethodModel enclosingMethod;
 953 
 954         public BoundCodeAttribute(AttributedElement enclosing,
 955                                   ClassReader reader,
 956                                   AttributeMapper<CodeAttribute> mapper,
 957                                   int payloadStart) {
 958             super(reader, mapper, payloadStart);
 959             this.codeLength = classReader.readInt(payloadStart + 4);
 960             this.enclosingMethod = (MethodModel) enclosing;
 961             this.codeStart = payloadStart + 8;
 962             this.codeEnd = codeStart + codeLength;
 963             this.exceptionHandlerPos = codeEnd;
 964             this.exceptionHandlerCnt = classReader.readU2(exceptionHandlerPos);
 965             this.attributePos = exceptionHandlerPos + 2 + exceptionHandlerCnt * 8;
 966         }
 967 
 968         // CodeAttribute
 969 
 970         @Override
 971         public int maxStack() {
 972             return classReader.readU2(payloadStart);
 973         }
 974 
 975         @Override
 976         public int maxLocals() {
 977             return classReader.readU2(payloadStart + 2);
 978         }
 979 
 980         @Override
 981         public int codeLength() {
 982             return codeLength;
 983         }
 984 
 985         @Override
 986         public byte[] codeArray() {
 987             return classReader.readBytes(payloadStart + 8, codeLength());
 988         }
 989     }
 990 
 991     /**
 992      * {@return the attribute mapper for a standard attribute}
 993      *
 994      * @param name the name of the attribute to find
 995      */
 996     public static AttributeMapper<?> standardAttribute(Utf8Entry name) {
 997         // critical bootstrap path, so no lambdas nor method handles here
 998         return switch (name.hashCode()) {
 999             case 0x46699ff2 ->
1000                 name.equalsString(NAME_ANNOTATION_DEFAULT) ? annotationDefault() : null;
1001             case 0x5208e184 ->
1002                 name.equalsString(NAME_BOOTSTRAP_METHODS) ? bootstrapMethods() : null;
1003             case 0xcb60907a ->
1004                 name.equalsString(NAME_CHARACTER_RANGE_TABLE) ? characterRangeTable() : null;
1005             case 0x4020220d ->
1006                 name.equalsString(NAME_CODE) ? code() : null;
1007             case 0xc20dd1fe ->
1008                 name.equalsString(NAME_COMPILATION_ID) ? compilationId() : null;
1009             case 0xcab1940d ->
1010                 name.equalsString(NAME_CONSTANT_VALUE) ? constantValue() : null;
1011             case 0x558641d3 ->
1012                 name.equalsString(NAME_DEPRECATED) ? deprecated() : null;
1013             case 0x51d443cd ->
1014                 name.equalsString(NAME_ENCLOSING_METHOD) ? enclosingMethod() : null;
1015             case 0x687c1624 ->
1016                 name.equalsString(NAME_EXCEPTIONS) ? exceptions() : null;
1017             case 0x7adb2910 ->
1018                 name.equalsString(NAME_INNER_CLASSES) ? innerClasses() : null;
1019             case 0x653f0551 ->
1020                 name.equalsString(NAME_LINE_NUMBER_TABLE) ? lineNumberTable() : null;
1021             case 0x64c75927 ->
1022                 name.equalsString(NAME_LOCAL_VARIABLE_TABLE) ? localVariableTable() : null;
1023             case 0x6697f98d ->
1024                 name.equalsString(NAME_LOCAL_VARIABLE_TYPE_TABLE) ? localVariableTypeTable() : null;
1025             case 0xdbb0cdcb ->
1026                 name.equalsString(NAME_METHOD_PARAMETERS) ? methodParameters() : null;
1027             case 0xc9b0928c ->
1028                 name.equalsString(NAME_MODULE) ? module() : null;
1029             case 0x41cd27e8 ->
1030                 name.equalsString(NAME_MODULE_HASHES) ? moduleHashes() : null;
1031             case 0x7deb0a13 ->
1032                 name.equalsString(NAME_MODULE_MAIN_CLASS) ? moduleMainClass() : null;
1033             case 0x6706ff99 ->
1034                 name.equalsString(NAME_MODULE_PACKAGES) ? modulePackages() : null;
1035             case 0x60272858 ->
1036                 name.equalsString(NAME_MODULE_RESOLUTION) ? moduleResolution() : null;
1037             case 0x5646d73d ->
1038                 name.equalsString(NAME_MODULE_TARGET) ? moduleTarget() : null;
1039             case 0x50336c40 ->
1040                 name.equalsString(NAME_NEST_HOST) ? nestHost() : null;
1041             case 0x4735ab81 ->
1042                 name.equalsString(NAME_NEST_MEMBERS) ? nestMembers() : null;
1043             case 0x7100d9fe ->
1044                 name.equalsString(NAME_PERMITTED_SUBCLASSES) ? permittedSubclasses() : null;
1045             case 0xd1ab5871 ->
1046                 name.equalsString(NAME_RECORD) ? record() : null;
1047             case 0x7588550f ->
1048                 name.equalsString(NAME_RUNTIME_INVISIBLE_ANNOTATIONS) ? runtimeInvisibleAnnotations() : null;
1049             case 0xcc74da30 ->
1050                 name.equalsString(NAME_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS) ? runtimeInvisibleParameterAnnotations() : null;
1051             case 0xf67697f5 ->
1052                 name.equalsString(NAME_RUNTIME_INVISIBLE_TYPE_ANNOTATIONS) ? runtimeInvisibleTypeAnnotations() : null;
1053             case 0xe0837d2a ->
1054                 name.equalsString(NAME_RUNTIME_VISIBLE_ANNOTATIONS) ? runtimeVisibleAnnotations() : null;
1055             case 0xc945a075 ->
1056                 name.equalsString(NAME_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS) ? runtimeVisibleParameterAnnotations() : null;
1057             case 0x611a3a90 ->
1058                 name.equalsString(NAME_RUNTIME_VISIBLE_TYPE_ANNOTATIONS) ? runtimeVisibleTypeAnnotations() : null;
1059             case 0xf76fb898 ->
1060                 name.equalsString(NAME_SIGNATURE) ? signature() : null;
1061             case 0x6b41b047 ->
1062                 name.equalsString(NAME_SOURCE_DEBUG_EXTENSION) ? sourceDebugExtension() : null;
1063             case 0x748c2857 ->
1064                 name.equalsString(NAME_SOURCE_FILE) ? sourceFile() : null;
1065             case 0x6bf13a96 ->
1066                 name.equalsString(NAME_SOURCE_ID) ? sourceId() : null;
1067             case 0xfa85ee5a ->
1068                 name.equalsString(NAME_STACK_MAP_TABLE) ? stackMapTable() : null;
1069             case 0xf2670725 ->
1070                 name.equalsString(NAME_SYNTHETIC) ? synthetic() : null;
1071             default -> null;
1072         };
1073     }
1074 }