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