1 /*
   2  * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package jdk.internal.classfile.impl;
  27 
  28 import java.lang.classfile.*;
  29 import java.lang.classfile.attribute.*;
  30 import java.lang.classfile.constantpool.*;
  31 import java.util.ArrayList;
  32 import java.util.Collections;
  33 import java.util.List;
  34 import java.util.Objects;
  35 import java.util.Optional;
  36 import java.util.function.Function;
  37 
  38 import jdk.internal.access.SharedSecrets;
  39 
  40 import static java.lang.classfile.Attributes.*;
  41 
  42 public abstract sealed class BoundAttribute<T extends Attribute<T>>
  43         extends AbstractElement
  44         implements Attribute<T>, Util.Writable {
  45 
  46     static final int NAME_AND_LENGTH_PREFIX = 6;
  47     private final AttributeMapper<T> mapper;
  48     final ClassReaderImpl classReader;
  49     final int payloadStart;
  50 
  51     BoundAttribute(ClassReader classReader, AttributeMapper<T> mapper, int payloadStart) {
  52         this.mapper = mapper;
  53         this.classReader = (ClassReaderImpl)classReader;
  54         this.payloadStart = payloadStart;
  55     }
  56 
  57     public int payloadLen() {
  58         return classReader.readInt(payloadStart - 4);
  59     }
  60 
  61     @Override
  62     public String attributeName() {
  63         return mapper.name();
  64     }
  65 
  66     @Override
  67     public AttributeMapper<T> attributeMapper() {
  68         return mapper;
  69     }
  70 
  71     public byte[] contents() {
  72         return classReader.readBytes(payloadStart, payloadLen());
  73     }
  74 
  75     @Override
  76     public void writeTo(DirectClassBuilder builder) {
  77         builder.writeAttribute(this);
  78     }
  79 
  80     @Override
  81     public void writeTo(DirectCodeBuilder builder) {
  82         builder.writeAttribute(this);
  83     }
  84 
  85     @Override
  86     public void writeTo(DirectMethodBuilder builder) {
  87         builder.writeAttribute(this);
  88     }
  89 
  90     @Override
  91     public void writeTo(DirectFieldBuilder builder) {
  92         builder.writeAttribute(this);
  93     }
  94 
  95     @Override
  96     @SuppressWarnings("unchecked")
  97     public void writeTo(BufWriterImpl buf) {
  98         if (!buf.canWriteDirect(classReader))
  99             attributeMapper().writeAttribute(buf, (T) this);
 100         else
 101             classReader.copyBytesTo(buf, payloadStart - NAME_AND_LENGTH_PREFIX, payloadLen() + NAME_AND_LENGTH_PREFIX);
 102     }
 103 
 104     public ConstantPool constantPool() {
 105         return classReader;
 106     }
 107 
 108     @Override
 109     public String toString() {
 110         return String.format("Attribute[name=%s]", mapper.name());
 111     }
 112 
 113     <E extends PoolEntry> List<E> readEntryList(int p, Class<E> type) {
 114         int cnt = classReader.readU2(p);
 115         p += 2;
 116         var entries = new Object[cnt];
 117         int end = p + (cnt * 2);
 118         for (int i = 0; p < end; i++, p += 2) {
 119             entries[i] = classReader.readEntry(p, type);
 120         }
 121         return SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(entries);
 122     }
 123 
 124     public static List<Attribute<?>> readAttributes(AttributedElement enclosing, ClassReader reader, int pos,
 125                                                                   Function<Utf8Entry, AttributeMapper<?>> customAttributes) {
 126         int size = reader.readU2(pos);
 127         var filled = new ArrayList<Attribute<?>>(size);
 128         int p = pos + 2;
 129         int cfLen = reader.classfileLength();
 130         for (int i = 0; i < size; ++i) {
 131             Utf8Entry name = reader.readEntry(p, Utf8Entry.class);
 132             int len = reader.readInt(p + 2);
 133             p += 6;
 134             if (len < 0 || len > cfLen - p) {
 135                 throw new IllegalArgumentException("attribute " + name.stringValue() + " too big to handle");
 136             }
 137 
 138             var mapper = standardAttribute(name);
 139             if (mapper == null) {
 140                 mapper = customAttributes.apply(name);
 141             }
 142             if (mapper != null) {
 143                 filled.add(Objects.requireNonNull(mapper.readAttribute(enclosing, reader, p)));
 144             } else {
 145                 AttributeMapper<UnknownAttribute> fakeMapper = new AttributeMapper<>() {
 146                     @Override
 147                     public String name() {
 148                         return name.stringValue();
 149                     }
 150 
 151                     @Override
 152                     public UnknownAttribute readAttribute(AttributedElement enclosing, ClassReader cf, int pos) {
 153                         // Will never get called
 154                         throw new UnsupportedOperationException();
 155                     }
 156 
 157                     @Override
 158                     public void writeAttribute(BufWriter buf, UnknownAttribute attr) {
 159                         buf.writeIndex(name);
 160                         var cont = attr.contents();
 161                         buf.writeInt(cont.length);
 162                         buf.writeBytes(cont);
 163                     }
 164 
 165                     @Override
 166                     public boolean allowMultiple() {
 167                         return true;
 168                     }
 169 
 170                     @Override
 171                     public AttributeMapper.AttributeStability stability() {
 172                         return AttributeStability.UNKNOWN;
 173                     }
 174                 };
 175                 filled.add(new BoundUnknownAttribute(reader, fakeMapper, p));
 176             }
 177             p += len;
 178         }
 179         return Collections.unmodifiableList(filled);
 180     }
 181 
 182     public static final class BoundUnknownAttribute extends BoundAttribute<UnknownAttribute>
 183             implements UnknownAttribute {
 184         public BoundUnknownAttribute(ClassReader cf, AttributeMapper<UnknownAttribute> mapper, int pos) {
 185             super(cf, mapper, pos);
 186         }
 187     }
 188 
 189     public static final class BoundStackMapTableAttribute
 190             extends BoundAttribute<StackMapTableAttribute>
 191             implements StackMapTableAttribute {
 192         final MethodModel method;
 193         final LabelContext ctx;
 194         List<StackMapFrameInfo> entries = null;
 195 
 196         public BoundStackMapTableAttribute(CodeImpl code, ClassReader cf, AttributeMapper<StackMapTableAttribute> mapper, int pos) {
 197             super(cf, mapper, pos);
 198             method = code.parent().orElseThrow();
 199             ctx = code;
 200         }
 201 
 202         @Override
 203         public List<StackMapFrameInfo> entries() {
 204             if (entries == null) {
 205                 entries = new StackMapDecoder(classReader, payloadStart, ctx, StackMapDecoder.initFrameLocals(method)).entries();
 206             }
 207             return entries;
 208         }
 209     }
 210 
 211     public static final class BoundSyntheticAttribute extends BoundAttribute<SyntheticAttribute>
 212             implements SyntheticAttribute {
 213         public BoundSyntheticAttribute(ClassReader cf, AttributeMapper<SyntheticAttribute> mapper, int pos) {
 214             super(cf, mapper, pos);
 215         }
 216     }
 217 
 218     public static final class BoundLineNumberTableAttribute
 219             extends BoundAttribute<LineNumberTableAttribute>
 220             implements LineNumberTableAttribute {
 221         private List<LineNumberInfo> lineNumbers = null;
 222 
 223         public BoundLineNumberTableAttribute(ClassReader cf, AttributeMapper<LineNumberTableAttribute> mapper, int pos) {
 224             super(cf, mapper, pos);
 225         }
 226 
 227         @Override
 228         public List<LineNumberInfo> lineNumbers() {
 229             if (lineNumbers == null) {
 230                 int nLn = classReader.readU2(payloadStart);
 231                 LineNumberInfo[] elements = new LineNumberInfo[nLn];
 232                 int p = payloadStart + 2;
 233                 int pEnd = p + (nLn * 4);
 234                 for (int i = 0; p < pEnd; p += 4, i++) {
 235                     int startPc = classReader.readU2(p);
 236                     int lineNumber = classReader.readU2(p + 2);
 237                     elements[i] = LineNumberInfo.of(startPc, lineNumber);
 238                 }
 239                 lineNumbers = List.of(elements);
 240             }
 241             return lineNumbers;
 242         }
 243     }
 244 
 245     public static final class BoundCharacterRangeTableAttribute extends BoundAttribute<CharacterRangeTableAttribute> implements CharacterRangeTableAttribute {
 246         private List<CharacterRangeInfo> characterRangeTable = null;
 247 
 248         public BoundCharacterRangeTableAttribute(ClassReader cf, AttributeMapper<CharacterRangeTableAttribute> mapper, int pos) {
 249             super(cf, mapper, pos);
 250         }
 251 
 252         @Override
 253         public List<CharacterRangeInfo> characterRangeTable() {
 254             if (characterRangeTable == null) {
 255                 int nLn = classReader.readU2(payloadStart);
 256                 CharacterRangeInfo[] elements = new CharacterRangeInfo[nLn];
 257                 int p = payloadStart + 2;
 258                 int pEnd = p + (nLn * 14);
 259                 for (int i = 0; p < pEnd; p += 14, i++) {
 260                     int startPc = classReader.readU2(p);
 261                     int endPc = classReader.readU2(p + 2);
 262                     int characterRangeStart = classReader.readInt(p + 4);
 263                     int characterRangeEnd = classReader.readInt(p + 8);
 264                     int flags = classReader.readU2(p + 12);
 265                     elements[i] = CharacterRangeInfo.of(startPc, endPc, characterRangeStart, characterRangeEnd, flags);
 266                 }
 267                 characterRangeTable = List.of(elements);
 268             }
 269             return characterRangeTable;
 270         }
 271     }
 272 
 273     public static final class BoundLocalVariableTableAttribute
 274             extends BoundAttribute<LocalVariableTableAttribute>
 275             implements LocalVariableTableAttribute {
 276         private final CodeImpl codeAttribute;
 277         private List<LocalVariableInfo> localVars = null;
 278 
 279         public BoundLocalVariableTableAttribute(AttributedElement enclosing, ClassReader cf, AttributeMapper<LocalVariableTableAttribute> mapper, int pos) {
 280             super(cf, mapper, pos);
 281             if (enclosing instanceof CodeImpl ci) {
 282                 this.codeAttribute = ci;
 283             } else {
 284                 throw new IllegalArgumentException("Invalid LocalVariableTable attribute location");
 285             }
 286         }
 287 
 288         @Override
 289         public List<LocalVariableInfo> localVariables() {
 290             if (localVars == null) {
 291                 int cnt = classReader.readU2(payloadStart);
 292                 BoundLocalVariable[] elements = new BoundLocalVariable[cnt];
 293                 int p = payloadStart + 2;
 294                 int pEnd = p + (cnt * 10);
 295                 for (int i = 0; p < pEnd; p += 10, i++) {
 296                     elements[i] = new BoundLocalVariable(codeAttribute, p);
 297                 }
 298                 localVars = List.of(elements);
 299             }
 300             return localVars;
 301         }
 302     }
 303 
 304     public static final class BoundLocalVariableTypeTableAttribute
 305             extends BoundAttribute<LocalVariableTypeTableAttribute>
 306             implements LocalVariableTypeTableAttribute {
 307         private final CodeImpl codeAttribute;
 308         private List<LocalVariableTypeInfo> localVars = null;
 309 
 310         public BoundLocalVariableTypeTableAttribute(AttributedElement enclosing, ClassReader cf, AttributeMapper<LocalVariableTypeTableAttribute> mapper, int pos) {
 311             super(cf, mapper, pos);
 312             if (enclosing instanceof CodeImpl ci) {
 313                 this.codeAttribute = ci;
 314             } else {
 315                 throw new IllegalArgumentException("Invalid LocalVariableTypeTable attribute location");
 316             }
 317         }
 318 
 319         @Override
 320         public List<LocalVariableTypeInfo> localVariableTypes() {
 321             if (localVars == null) {
 322                 final int cnt = classReader.readU2(payloadStart);
 323                 BoundLocalVariableType[] elements = new BoundLocalVariableType[cnt];
 324                 int p = payloadStart + 2;
 325                 int pEnd = p + (cnt * 10);
 326                 for (int i = 0; p < pEnd; p += 10, i++) {
 327                     elements[i] = new BoundLocalVariableType(codeAttribute, p);
 328                 }
 329                 localVars = List.of(elements);
 330             }
 331             return localVars;
 332         }
 333     }
 334 
 335     public static final class BoundMethodParametersAttribute extends BoundAttribute<MethodParametersAttribute>
 336             implements MethodParametersAttribute {
 337         private List<MethodParameterInfo> parameters = null;
 338 
 339         public BoundMethodParametersAttribute(ClassReader cf, AttributeMapper<MethodParametersAttribute> mapper, int pos) {
 340             super(cf, mapper, pos);
 341         }
 342 
 343         @Override
 344         public List<MethodParameterInfo> parameters() {
 345             if (parameters == null) {
 346                 final int cnt = classReader.readU1(payloadStart);
 347                 MethodParameterInfo[] elements = new MethodParameterInfo[cnt];
 348                 int p = payloadStart + 1;
 349                 int pEnd = p + (cnt * 4);
 350                 for (int i = 0; p < pEnd; p += 4, i++) {
 351                     Utf8Entry name = classReader.readEntryOrNull(p, Utf8Entry.class);
 352                     int accessFlags = classReader.readU2(p + 2);
 353                     elements[i] = MethodParameterInfo.of(Optional.ofNullable(name), accessFlags);
 354                 }
 355                 parameters = List.of(elements);
 356             }
 357             return parameters;
 358         }
 359     }
 360 
 361     public static final class BoundModuleHashesAttribute extends BoundAttribute<ModuleHashesAttribute>
 362             implements ModuleHashesAttribute {
 363         private List<ModuleHashInfo> hashes = null;
 364 
 365         public BoundModuleHashesAttribute(ClassReader cf, AttributeMapper<ModuleHashesAttribute> mapper, int pos) {
 366             super(cf, mapper, pos);
 367         }
 368 
 369         @Override
 370         public Utf8Entry algorithm() {
 371             return classReader.readEntry(payloadStart, Utf8Entry.class);
 372         }
 373 
 374         @Override
 375         public List<ModuleHashInfo> hashes() {
 376             if (hashes == null) {
 377                 final int cnt = classReader.readU2(payloadStart + 2);
 378                 ModuleHashInfo[] elements = new ModuleHashInfo[cnt];
 379                 int p = payloadStart + 4;
 380                 //System.err.printf("%5d: ModuleHashesAttr alg = %s, cnt = %d%n", pos, algorithm(), cnt);
 381                 for (int i = 0; i < cnt; ++i) {
 382                     ModuleEntry module = classReader.readEntry(p, ModuleEntry.class);
 383                     int hashLength = classReader.readU2(p + 2);
 384                     //System.err.printf("%5d:     [%d] module = %s, hashLength = %d%n", p, i, module, hashLength);
 385                     p += 4;
 386                     elements[i] = ModuleHashInfo.of(module, classReader.readBytes(p, hashLength));
 387                     p += hashLength;
 388                 }
 389                 hashes = List.of(elements);
 390             }
 391             return hashes;
 392         }
 393     }
 394 
 395     public static final class BoundRecordAttribute extends BoundAttribute<RecordAttribute>
 396             implements RecordAttribute {
 397         private List<RecordComponentInfo> components = null;
 398 
 399         public BoundRecordAttribute(ClassReader cf, AttributeMapper<RecordAttribute> mapper, int pos) {
 400             super(cf, mapper, pos);
 401         }
 402 
 403         @Override
 404         public List<RecordComponentInfo> components() {
 405             if (components == null) {
 406                 final int cnt = classReader.readU2(payloadStart);
 407                 RecordComponentInfo[] elements = new RecordComponentInfo[cnt];
 408                 int p = payloadStart + 2;
 409                 for (int i = 0; i < cnt; i++) {
 410                     elements[i] = new BoundRecordComponentInfo(classReader, p);
 411                     p = classReader.skipAttributeHolder(p + 4);
 412                 }
 413                 components = List.of(elements);
 414             }
 415             return components;
 416         }
 417     }
 418 
 419     public static final class BoundDeprecatedAttribute extends BoundAttribute<DeprecatedAttribute>
 420             implements DeprecatedAttribute {
 421         public BoundDeprecatedAttribute(ClassReader cf, AttributeMapper<DeprecatedAttribute> mapper, int pos) {
 422             super(cf, mapper, pos);
 423         }
 424     }
 425 
 426     public static final class BoundSignatureAttribute extends BoundAttribute<SignatureAttribute>
 427             implements SignatureAttribute {
 428         public BoundSignatureAttribute(ClassReader cf, AttributeMapper<SignatureAttribute> mapper, int pos) {
 429             super(cf, mapper, pos);
 430         }
 431 
 432         @Override
 433         public Utf8Entry signature() {
 434             return classReader.readEntry(payloadStart, Utf8Entry.class);
 435         }
 436     }
 437 
 438     public static final class BoundSourceFileAttribute extends BoundAttribute<SourceFileAttribute>
 439             implements SourceFileAttribute {
 440         public BoundSourceFileAttribute(ClassReader cf, AttributeMapper<SourceFileAttribute> mapper, int pos) {
 441             super(cf, mapper, pos);
 442         }
 443 
 444         @Override
 445         public Utf8Entry sourceFile() {
 446             return classReader.readEntry(payloadStart, Utf8Entry.class);
 447         }
 448 
 449     }
 450 
 451     public static final class BoundModuleMainClassAttribute extends BoundAttribute<ModuleMainClassAttribute> implements ModuleMainClassAttribute {
 452         public BoundModuleMainClassAttribute(ClassReader cf, AttributeMapper<ModuleMainClassAttribute> mapper, int pos) {
 453             super(cf, mapper, pos);
 454         }
 455 
 456         @Override
 457         public ClassEntry mainClass() {
 458             return classReader.readEntry(payloadStart, ClassEntry.class);
 459         }
 460     }
 461 
 462     public static final class BoundNestHostAttribute extends BoundAttribute<NestHostAttribute>
 463             implements NestHostAttribute {
 464         public BoundNestHostAttribute(ClassReader cf, AttributeMapper<NestHostAttribute> mapper, int pos) {
 465             super(cf, mapper, pos);
 466         }
 467 
 468         @Override
 469         public ClassEntry nestHost() {
 470             return classReader.readEntry(payloadStart, ClassEntry.class);
 471         }
 472     }
 473 
 474     public static final class BoundSourceDebugExtensionAttribute extends BoundAttribute<SourceDebugExtensionAttribute>
 475             implements SourceDebugExtensionAttribute {
 476         public BoundSourceDebugExtensionAttribute(ClassReader cf, AttributeMapper<SourceDebugExtensionAttribute> mapper, int pos) {
 477             super(cf, mapper, pos);
 478         }
 479     }
 480 
 481     public static final class BoundConstantValueAttribute extends BoundAttribute<ConstantValueAttribute>
 482             implements ConstantValueAttribute {
 483         public BoundConstantValueAttribute(ClassReader cf, AttributeMapper<ConstantValueAttribute> mapper, int pos) {
 484             super(cf, mapper, pos);
 485         }
 486 
 487         @Override
 488         public ConstantValueEntry constant() {
 489             return classReader.readEntry(payloadStart, ConstantValueEntry.class);
 490         }
 491 
 492     }
 493 
 494     public static final class BoundModuleTargetAttribute extends BoundAttribute<ModuleTargetAttribute>
 495             implements ModuleTargetAttribute {
 496         public BoundModuleTargetAttribute(ClassReader cf, AttributeMapper<ModuleTargetAttribute> mapper, int pos) {
 497             super(cf, mapper, pos);
 498         }
 499 
 500         @Override
 501         public Utf8Entry targetPlatform() {
 502             return classReader.readEntry(payloadStart, Utf8Entry.class);
 503         }
 504     }
 505 
 506     public static final class BoundCompilationIDAttribute extends BoundAttribute<CompilationIDAttribute>
 507             implements CompilationIDAttribute {
 508         public BoundCompilationIDAttribute(ClassReader cf, AttributeMapper<CompilationIDAttribute> mapper, int pos) {
 509             super(cf, mapper, pos);
 510         }
 511 
 512         @Override
 513         public Utf8Entry compilationId() {
 514             return classReader.readEntry(payloadStart, Utf8Entry.class);
 515         }
 516     }
 517 
 518     public static final class BoundSourceIDAttribute extends BoundAttribute<SourceIDAttribute>
 519             implements SourceIDAttribute {
 520         public BoundSourceIDAttribute(ClassReader cf, AttributeMapper<SourceIDAttribute> mapper, int pos) {
 521             super(cf, mapper, pos);
 522         }
 523 
 524         @Override
 525         public Utf8Entry sourceId() {
 526             return classReader.readEntry(payloadStart, Utf8Entry.class);
 527         }
 528     }
 529 
 530     public static final class BoundModuleResolutionAttribute extends BoundAttribute<ModuleResolutionAttribute>
 531             implements ModuleResolutionAttribute {
 532         public BoundModuleResolutionAttribute(ClassReader cf, AttributeMapper<ModuleResolutionAttribute> mapper, int pos) {
 533             super(cf, mapper, pos);
 534         }
 535 
 536         @Override
 537         public int resolutionFlags() {
 538             return classReader.readU2(payloadStart);
 539         }
 540     }
 541 
 542     public static final class BoundExceptionsAttribute extends BoundAttribute<ExceptionsAttribute>
 543             implements ExceptionsAttribute {
 544         private List<ClassEntry> exceptions = null;
 545 
 546         public BoundExceptionsAttribute(ClassReader cf, AttributeMapper<ExceptionsAttribute> mapper, int pos) {
 547             super(cf, mapper, pos);
 548         }
 549 
 550         @Override
 551         public List<ClassEntry> exceptions() {
 552             if (exceptions == null) {
 553                 exceptions = readEntryList(payloadStart, ClassEntry.class);
 554             }
 555             return exceptions;
 556         }
 557     }
 558 
 559     public static final class BoundModuleAttribute extends BoundAttribute<ModuleAttribute>
 560             implements ModuleAttribute {
 561         private List<ModuleRequireInfo> requires = null;
 562         private List<ModuleExportInfo> exports = null;
 563         private List<ModuleOpenInfo> opens = null;
 564         private List<ClassEntry> uses = null;
 565         private List<ModuleProvideInfo> provides = null;
 566 
 567         public BoundModuleAttribute(ClassReader cf, AttributeMapper<ModuleAttribute> mapper, int pos) {
 568             super(cf, mapper, pos);
 569         }
 570 
 571         @Override
 572         public ModuleEntry moduleName() {
 573             return classReader.readEntry(payloadStart, ModuleEntry.class);
 574         }
 575 
 576         @Override
 577         public int moduleFlagsMask() {
 578             return classReader.readU2(payloadStart + 2);
 579         }
 580 
 581         @Override
 582         public Optional<Utf8Entry> moduleVersion() {
 583             return Optional.ofNullable(classReader.readEntryOrNull(payloadStart + 4, Utf8Entry.class));
 584         }
 585 
 586         @Override
 587         public List<ModuleRequireInfo> requires() {
 588             if (requires == null) {
 589                 structure();
 590             }
 591             return requires;
 592         }
 593 
 594         @Override
 595         public List<ModuleExportInfo> exports() {
 596             if (exports == null) {
 597                 structure();
 598             }
 599             return exports;
 600         }
 601 
 602         @Override
 603         public List<ModuleOpenInfo> opens() {
 604             if (opens == null) {
 605                 structure();
 606             }
 607             return opens;
 608         }
 609 
 610         @Override
 611         public List<ClassEntry> uses() {
 612             if (uses == null) {
 613                 structure();
 614             }
 615             return uses;
 616         }
 617 
 618         @Override
 619         public List<ModuleProvideInfo> provides() {
 620             if (provides == null) {
 621                 structure();
 622             }
 623             return provides;
 624         }
 625 
 626         private void structure() {
 627             int p = payloadStart + 8;
 628 
 629             {
 630                 int cnt = classReader.readU2(payloadStart + 6);
 631                 ModuleRequireInfo[] elements = new ModuleRequireInfo[cnt];
 632                 int end = p + (cnt * 6);
 633                 for (int i = 0; p < end; p += 6, i++) {
 634                     elements[i] = ModuleRequireInfo.of(classReader.readEntry(p, ModuleEntry.class),
 635                             classReader.readU2(p + 2),
 636                             classReader.readEntryOrNull(p + 4, Utf8Entry.class));
 637                 }
 638                 requires = List.of(elements);
 639             }
 640 
 641             {
 642                 int cnt = classReader.readU2(p);
 643                 p += 2;
 644                 ModuleExportInfo[] elements = new ModuleExportInfo[cnt];
 645                 for (int i = 0; i < cnt; i++) {
 646                     PackageEntry pe = classReader.readEntry(p, PackageEntry.class);
 647                     int exportFlags = classReader.readU2(p + 2);
 648                     p += 4;
 649                     List<ModuleEntry> exportsTo = readEntryList(p, ModuleEntry.class);
 650                     p += 2 + exportsTo.size() * 2;
 651                     elements[i] = ModuleExportInfo.of(pe, exportFlags, exportsTo);
 652                 }
 653                 exports = List.of(elements);
 654             }
 655 
 656             {
 657                 int cnt = classReader.readU2(p);
 658                 p += 2;
 659                 ModuleOpenInfo[] elements = new ModuleOpenInfo[cnt];
 660                 for (int i = 0; i < cnt; i++) {
 661                     PackageEntry po = classReader.readEntry(p, PackageEntry.class);
 662                     int opensFlags = classReader.readU2(p + 2);
 663                     p += 4;
 664                     List<ModuleEntry> opensTo = readEntryList(p, ModuleEntry.class);
 665                     p += 2 + opensTo.size() * 2;
 666                     elements[i] = ModuleOpenInfo.of(po, opensFlags, opensTo);
 667                 }
 668                 opens = List.of(elements);
 669             }
 670 
 671             {
 672                 uses = readEntryList(p, ClassEntry.class);
 673                 p += 2 + uses.size() * 2;
 674                 int cnt = classReader.readU2(p);
 675                 p += 2;
 676                 ModuleProvideInfo[] elements = new ModuleProvideInfo[cnt];
 677                 provides = new ArrayList<>(cnt);
 678                 for (int i = 0; i < cnt; i++) {
 679                     ClassEntry c = classReader.readEntry(p, ClassEntry.class);
 680                     p += 2;
 681                     List<ClassEntry> providesWith = readEntryList(p, ClassEntry.class);
 682                     p += 2 + providesWith.size() * 2;
 683                     elements[i] = ModuleProvideInfo.of(c, providesWith);
 684                 }
 685                 provides = List.of(elements);
 686             }
 687         }
 688     }
 689 
 690     public static final class BoundModulePackagesAttribute extends BoundAttribute<ModulePackagesAttribute>
 691             implements ModulePackagesAttribute {
 692         private List<PackageEntry> packages = null;
 693 
 694         public BoundModulePackagesAttribute(ClassReader cf, AttributeMapper<ModulePackagesAttribute> mapper, int pos) {
 695             super(cf, mapper, pos);
 696         }
 697 
 698         @Override
 699         public List<PackageEntry> packages() {
 700             if (packages == null) {
 701                 packages = readEntryList(payloadStart, PackageEntry.class);
 702             }
 703             return packages;
 704         }
 705     }
 706 
 707     public static final class BoundNestMembersAttribute extends BoundAttribute<NestMembersAttribute>
 708             implements NestMembersAttribute {
 709 
 710         private List<ClassEntry> members = null;
 711 
 712         public BoundNestMembersAttribute(ClassReader cf, AttributeMapper<NestMembersAttribute> mapper, int pos) {
 713             super(cf, mapper, pos);
 714         }
 715 
 716         @Override
 717         public List<ClassEntry> nestMembers() {
 718             if (members == null) {
 719                 members = readEntryList(payloadStart, ClassEntry.class);
 720             }
 721             return members;
 722         }
 723     }
 724 
 725     public static final class BoundBootstrapMethodsAttribute extends BoundAttribute<BootstrapMethodsAttribute>
 726             implements BootstrapMethodsAttribute {
 727 
 728         private List<BootstrapMethodEntry> bootstraps = null;
 729         private final int size;
 730 
 731         public BoundBootstrapMethodsAttribute(ClassReader reader, AttributeMapper<BootstrapMethodsAttribute> mapper, int pos) {
 732             super(reader, mapper, pos);
 733             size = classReader.readU2(pos);
 734         }
 735 
 736         @Override
 737         public int bootstrapMethodsSize() {
 738             return size;
 739         }
 740 
 741         @Override
 742         public List<BootstrapMethodEntry> bootstrapMethods() {
 743             if (bootstraps == null) {
 744                 BootstrapMethodEntry[] bs = new BootstrapMethodEntry[size];
 745                 int p = payloadStart + 2;
 746                 for (int i = 0; i < size; ++i) {
 747                     final var handle = classReader.readEntry(p, AbstractPoolEntry.MethodHandleEntryImpl.class);
 748                     final List<LoadableConstantEntry> args = readEntryList(p + 2, LoadableConstantEntry.class);
 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.readEntry(p, ClassEntry.class);
 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.readEntry(payloadStart, ClassEntry.class);
 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, ClassEntry.class);
 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 0x46699ff2 ->
 992                 name.equalsString(NAME_ANNOTATION_DEFAULT) ? annotationDefault() : null;
 993             case 0x5208e184 ->
 994                 name.equalsString(NAME_BOOTSTRAP_METHODS) ? bootstrapMethods() : null;
 995             case 0xcb60907a ->
 996                 name.equalsString(NAME_CHARACTER_RANGE_TABLE) ? characterRangeTable() : null;
 997             case 0x4020220d ->
 998                 name.equalsString(NAME_CODE) ? code() : null;
 999             case 0xc20dd1fe ->
1000                 name.equalsString(NAME_COMPILATION_ID) ? compilationId() : null;
1001             case 0xcab1940d ->
1002                 name.equalsString(NAME_CONSTANT_VALUE) ? constantValue() : null;
1003             case 0x558641d3 ->
1004                 name.equalsString(NAME_DEPRECATED) ? deprecated() : null;
1005             case 0x51d443cd ->
1006                 name.equalsString(NAME_ENCLOSING_METHOD) ? enclosingMethod() : null;
1007             case 0x687c1624 ->
1008                 name.equalsString(NAME_EXCEPTIONS) ? exceptions() : null;
1009             case 0x7adb2910 ->
1010                 name.equalsString(NAME_INNER_CLASSES) ? innerClasses() : null;
1011             case 0x653f0551 ->
1012                 name.equalsString(NAME_LINE_NUMBER_TABLE) ? lineNumberTable() : null;
1013             case 0x64c75927 ->
1014                 name.equalsString(NAME_LOCAL_VARIABLE_TABLE) ? localVariableTable() : null;
1015             case 0x6697f98d ->
1016                 name.equalsString(NAME_LOCAL_VARIABLE_TYPE_TABLE) ? localVariableTypeTable() : null;
1017             case 0xdbb0cdcb ->
1018                 name.equalsString(NAME_METHOD_PARAMETERS) ? methodParameters() : null;
1019             case 0xc9b0928c ->
1020                 name.equalsString(NAME_MODULE) ? module() : null;
1021             case 0x41cd27e8 ->
1022                 name.equalsString(NAME_MODULE_HASHES) ? moduleHashes() : null;
1023             case 0x7deb0a13 ->
1024                 name.equalsString(NAME_MODULE_MAIN_CLASS) ? moduleMainClass() : null;
1025             case 0x6706ff99 ->
1026                 name.equalsString(NAME_MODULE_PACKAGES) ? modulePackages() : null;
1027             case 0x60272858 ->
1028                 name.equalsString(NAME_MODULE_RESOLUTION) ? moduleResolution() : null;
1029             case 0x5646d73d ->
1030                 name.equalsString(NAME_MODULE_TARGET) ? moduleTarget() : null;
1031             case 0x50336c40 ->
1032                 name.equalsString(NAME_NEST_HOST) ? nestHost() : null;
1033             case 0x4735ab81 ->
1034                 name.equalsString(NAME_NEST_MEMBERS) ? nestMembers() : null;
1035             case 0x7100d9fe ->
1036                 name.equalsString(NAME_PERMITTED_SUBCLASSES) ? permittedSubclasses() : null;
1037             case 0xd1ab5871 ->
1038                 name.equalsString(NAME_RECORD) ? record() : null;
1039             case 0x7588550f ->
1040                 name.equalsString(NAME_RUNTIME_INVISIBLE_ANNOTATIONS) ? runtimeInvisibleAnnotations() : null;
1041             case 0xcc74da30 ->
1042                 name.equalsString(NAME_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS) ? runtimeInvisibleParameterAnnotations() : null;
1043             case 0xf67697f5 ->
1044                 name.equalsString(NAME_RUNTIME_INVISIBLE_TYPE_ANNOTATIONS) ? runtimeInvisibleTypeAnnotations() : null;
1045             case 0xe0837d2a ->
1046                 name.equalsString(NAME_RUNTIME_VISIBLE_ANNOTATIONS) ? runtimeVisibleAnnotations() : null;
1047             case 0xc945a075 ->
1048                 name.equalsString(NAME_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS) ? runtimeVisibleParameterAnnotations() : null;
1049             case 0x611a3a90 ->
1050                 name.equalsString(NAME_RUNTIME_VISIBLE_TYPE_ANNOTATIONS) ? runtimeVisibleTypeAnnotations() : null;
1051             case 0xf76fb898 ->
1052                 name.equalsString(NAME_SIGNATURE) ? signature() : null;
1053             case 0x6b41b047 ->
1054                 name.equalsString(NAME_SOURCE_DEBUG_EXTENSION) ? sourceDebugExtension() : null;
1055             case 0x748c2857 ->
1056                 name.equalsString(NAME_SOURCE_FILE) ? sourceFile() : null;
1057             case 0x6bf13a96 ->
1058                 name.equalsString(NAME_SOURCE_ID) ? sourceId() : null;
1059             case 0xfa85ee5a ->
1060                 name.equalsString(NAME_STACK_MAP_TABLE) ? stackMapTable() : null;
1061             case 0xf2670725 ->
1062                 name.equalsString(NAME_SYNTHETIC) ? synthetic() : null;
1063             default -> null;
1064         };
1065     }
1066 }