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 package jdk.internal.classfile.impl;
  26 
  27 import java.lang.classfile.*;
  28 import java.lang.classfile.attribute.*;
  29 import java.lang.classfile.constantpool.ClassEntry;
  30 import java.lang.classfile.constantpool.ConstantValueEntry;
  31 import java.lang.classfile.constantpool.ModuleEntry;
  32 import java.lang.classfile.constantpool.NameAndTypeEntry;
  33 import java.lang.classfile.constantpool.PackageEntry;
  34 import java.lang.classfile.constantpool.Utf8Entry;
  35 import java.util.Collection;
  36 import java.util.List;
  37 import java.util.Optional;
  38 
  39 import jdk.internal.access.SharedSecrets;
  40 
  41 import static java.util.Objects.requireNonNull;
  42 
  43 public abstract sealed class UnboundAttribute<T extends Attribute<T>>
  44         extends AbstractElement
  45         implements Attribute<T>, Util.Writable {
  46     protected final AttributeMapper<T> mapper;
  47 
  48     public UnboundAttribute(AttributeMapper<T> mapper) {
  49         this.mapper = mapper;
  50     }
  51 
  52     @Override
  53     public AttributeMapper<T> attributeMapper() {
  54         return mapper;
  55     }
  56 
  57     @Override
  58     @SuppressWarnings("unchecked")
  59     public void writeTo(BufWriterImpl buf) {
  60         mapper.writeAttribute(buf, (T) this);
  61     }
  62 
  63     @Override
  64     public void writeTo(DirectClassBuilder builder) {
  65         builder.writeAttribute(this);
  66     }
  67 
  68     @Override
  69     public void writeTo(DirectCodeBuilder builder) {
  70         builder.writeAttribute(this);
  71     }
  72 
  73     @Override
  74     public void writeTo(DirectMethodBuilder builder) {
  75         builder.writeAttribute(this);
  76     }
  77 
  78     @Override
  79     public void writeTo(DirectFieldBuilder builder) {
  80         builder.writeAttribute(this);
  81     }
  82 
  83     @Override
  84     public String toString() {
  85         return String.format("Attribute[name=%s]", mapper.name());
  86     }
  87     public static final class UnboundConstantValueAttribute
  88             extends UnboundAttribute<ConstantValueAttribute>
  89             implements ConstantValueAttribute {
  90 
  91         private static final Utf8Entry NAME = TemporaryConstantPool.INSTANCE.utf8Entry(Attributes.NAME_CONSTANT_VALUE);
  92 
  93         private final ConstantValueEntry entry;
  94 
  95         public UnboundConstantValueAttribute(ConstantValueEntry entry) {
  96             super(Attributes.constantValue());
  97             this.entry = requireNonNull(entry);
  98         }
  99 
 100         @Override
 101         public ConstantValueEntry constant() {
 102             return entry;
 103         }
 104 
 105         @Override
 106         public Utf8Entry attributeName() {
 107             return NAME;
 108         }
 109     }
 110 
 111     public static final class UnboundDeprecatedAttribute
 112             extends UnboundAttribute<DeprecatedAttribute>
 113             implements DeprecatedAttribute {
 114 
 115         private static final Utf8Entry NAME = TemporaryConstantPool.INSTANCE.utf8Entry(Attributes.NAME_DEPRECATED);
 116 
 117         public UnboundDeprecatedAttribute() {
 118             super(Attributes.deprecated());
 119         }
 120 
 121         @Override
 122         public Utf8Entry attributeName() {
 123             return NAME;
 124         }
 125     }
 126 
 127     public static final class UnboundSyntheticAttribute
 128             extends UnboundAttribute<SyntheticAttribute>
 129             implements SyntheticAttribute {
 130 
 131         private static final Utf8Entry NAME = TemporaryConstantPool.INSTANCE.utf8Entry(Attributes.NAME_SYNTHETIC);
 132 
 133         public UnboundSyntheticAttribute() {
 134             super(Attributes.synthetic());
 135         }
 136 
 137         @Override
 138         public Utf8Entry attributeName() {
 139             return NAME;
 140         }
 141     }
 142 
 143     public static final class UnboundSignatureAttribute
 144             extends UnboundAttribute<SignatureAttribute>
 145             implements SignatureAttribute {
 146 
 147         private static final Utf8Entry NAME = TemporaryConstantPool.INSTANCE.utf8Entry(Attributes.NAME_SIGNATURE);
 148 
 149         private final Utf8Entry signature;
 150 
 151         public UnboundSignatureAttribute(Utf8Entry signature) {
 152             super(Attributes.signature());
 153             this.signature = requireNonNull(signature);
 154         }
 155 
 156         @Override
 157         public Utf8Entry signature() {
 158             return signature;
 159         }
 160 
 161         @Override
 162         public Utf8Entry attributeName() {
 163             return NAME;
 164         }
 165     }
 166 
 167     public static final class UnboundExceptionsAttribute
 168             extends UnboundAttribute<ExceptionsAttribute>
 169             implements ExceptionsAttribute {
 170 
 171         private static final Utf8Entry NAME = TemporaryConstantPool.INSTANCE.utf8Entry(Attributes.NAME_EXCEPTIONS);
 172 
 173         private final List<ClassEntry> exceptions;
 174 
 175         public UnboundExceptionsAttribute(List<ClassEntry> exceptions) {
 176             super(Attributes.exceptions());
 177             this.exceptions = List.copyOf(exceptions);
 178         }
 179 
 180         @Override
 181         public List<ClassEntry> exceptions() {
 182             return exceptions;
 183         }
 184 
 185         @Override
 186         public Utf8Entry attributeName() {
 187             return NAME;
 188         }
 189     }
 190 
 191     public static final class UnboundAnnotationDefaultAttribute
 192             extends UnboundAttribute<AnnotationDefaultAttribute>
 193             implements AnnotationDefaultAttribute {
 194 
 195         private static final Utf8Entry NAME = TemporaryConstantPool.INSTANCE.utf8Entry(Attributes.NAME_ANNOTATION_DEFAULT);
 196 
 197         private final AnnotationValue annotationDefault;
 198 
 199         public UnboundAnnotationDefaultAttribute(AnnotationValue annotationDefault) {
 200             super(Attributes.annotationDefault());
 201             this.annotationDefault = requireNonNull(annotationDefault);
 202         }
 203 
 204         @Override
 205         public AnnotationValue defaultValue() {
 206             return annotationDefault;
 207         }
 208 
 209         @Override
 210         public Utf8Entry attributeName() {
 211             return NAME;
 212         }
 213     }
 214 
 215     public static final class UnboundSourceFileAttribute extends UnboundAttribute<SourceFileAttribute>
 216             implements SourceFileAttribute {
 217 
 218         private static final Utf8Entry NAME = TemporaryConstantPool.INSTANCE.utf8Entry(Attributes.NAME_SOURCE_FILE);
 219 
 220         private final Utf8Entry sourceFile;
 221 
 222         public UnboundSourceFileAttribute(Utf8Entry sourceFile) {
 223             super(Attributes.sourceFile());
 224             this.sourceFile = requireNonNull(sourceFile);
 225         }
 226 
 227         @Override
 228         public Utf8Entry sourceFile() {
 229             return sourceFile;
 230         }
 231 
 232         @Override
 233         public Utf8Entry attributeName() {
 234             return NAME;
 235         }
 236     }
 237 
 238     public static final class UnboundStackMapTableAttribute extends UnboundAttribute<StackMapTableAttribute>
 239             implements StackMapTableAttribute {
 240 
 241         private static final Utf8Entry NAME = TemporaryConstantPool.INSTANCE.utf8Entry(Attributes.NAME_STACK_MAP_TABLE);
 242 
 243         private final List<StackMapFrameInfo> entries;
 244 
 245         public UnboundStackMapTableAttribute(List<StackMapFrameInfo> entries) {
 246             super(Attributes.stackMapTable());
 247             this.entries = List.copyOf(entries);
 248         }
 249 
 250         @Override
 251         public List<StackMapFrameInfo> entries() {
 252             return entries;
 253         }
 254 
 255         @Override
 256         public Utf8Entry attributeName() {
 257             return NAME;
 258         }
 259     }
 260 
 261     public static final class UnboundInnerClassesAttribute
 262             extends UnboundAttribute<InnerClassesAttribute>
 263             implements InnerClassesAttribute {
 264 
 265         private static final Utf8Entry NAME = TemporaryConstantPool.INSTANCE.utf8Entry(Attributes.NAME_INNER_CLASSES);
 266 
 267         private final List<InnerClassInfo> innerClasses;
 268 
 269         public UnboundInnerClassesAttribute(List<InnerClassInfo> innerClasses) {
 270             super(Attributes.innerClasses());
 271             this.innerClasses = List.copyOf(innerClasses);
 272         }
 273 
 274         @Override
 275         public List<InnerClassInfo> classes() {
 276             return innerClasses;
 277         }
 278 
 279         @Override
 280         public Utf8Entry attributeName() {
 281             return NAME;
 282         }
 283     }
 284 
 285     public static final class UnboundRecordAttribute
 286             extends UnboundAttribute<RecordAttribute>
 287             implements RecordAttribute {
 288 
 289         private static final Utf8Entry NAME = TemporaryConstantPool.INSTANCE.utf8Entry(Attributes.NAME_RECORD);
 290 
 291         private final List<RecordComponentInfo> components;
 292 
 293         public UnboundRecordAttribute(List<RecordComponentInfo> components) {
 294             super(Attributes.record());
 295             this.components = List.copyOf(components);
 296         }
 297 
 298         @Override
 299         public List<RecordComponentInfo> components() {
 300             return components;
 301         }
 302 
 303         @Override
 304         public Utf8Entry attributeName() {
 305             return NAME;
 306         }
 307     }
 308 
 309     public static final class UnboundEnclosingMethodAttribute
 310             extends UnboundAttribute<EnclosingMethodAttribute>
 311             implements EnclosingMethodAttribute {
 312 
 313         private static final Utf8Entry NAME = TemporaryConstantPool.INSTANCE.utf8Entry(Attributes.NAME_ENCLOSING_METHOD);
 314 
 315         private final ClassEntry classEntry;
 316         private final NameAndTypeEntry method;
 317 
 318         public UnboundEnclosingMethodAttribute(ClassEntry classEntry, NameAndTypeEntry method) {
 319             super(Attributes.enclosingMethod());
 320             this.classEntry = requireNonNull(classEntry);
 321             this.method = method;
 322         }
 323 
 324         @Override
 325         public ClassEntry enclosingClass() {
 326             return classEntry;
 327         }
 328 
 329         @Override
 330         public Optional<NameAndTypeEntry> enclosingMethod() {
 331             return Optional.ofNullable(method);
 332         }
 333 
 334         @Override
 335         public Utf8Entry attributeName() {
 336             return NAME;
 337         }
 338     }
 339 
 340     public static final class UnboundMethodParametersAttribute
 341             extends UnboundAttribute<MethodParametersAttribute>
 342             implements MethodParametersAttribute {
 343 
 344         private static final Utf8Entry NAME = TemporaryConstantPool.INSTANCE.utf8Entry(Attributes.NAME_METHOD_PARAMETERS);
 345 
 346         private final List<MethodParameterInfo> parameters;
 347 
 348         public UnboundMethodParametersAttribute(List<MethodParameterInfo> parameters) {
 349             super(Attributes.methodParameters());
 350             this.parameters = List.copyOf(parameters);
 351         }
 352 
 353         @Override
 354         public List<MethodParameterInfo> parameters() {
 355             return parameters;
 356         }
 357 
 358         @Override
 359         public Utf8Entry attributeName() {
 360             return NAME;
 361         }
 362     }
 363 
 364     public static final class UnboundModuleTargetAttribute
 365             extends UnboundAttribute<ModuleTargetAttribute>
 366             implements ModuleTargetAttribute {
 367 
 368         private static final Utf8Entry NAME = TemporaryConstantPool.INSTANCE.utf8Entry(Attributes.NAME_MODULE_TARGET);
 369 
 370         final Utf8Entry moduleTarget;
 371 
 372         public UnboundModuleTargetAttribute(Utf8Entry moduleTarget) {
 373             super(Attributes.moduleTarget());
 374             this.moduleTarget = requireNonNull(moduleTarget);
 375         }
 376 
 377         @Override
 378         public Utf8Entry targetPlatform() {
 379             return moduleTarget;
 380         }
 381 
 382         @Override
 383         public Utf8Entry attributeName() {
 384             return NAME;
 385         }
 386     }
 387 
 388     public static final class UnboundModuleMainClassAttribute
 389             extends UnboundAttribute<ModuleMainClassAttribute>
 390             implements ModuleMainClassAttribute {
 391 
 392         private static final Utf8Entry NAME = TemporaryConstantPool.INSTANCE.utf8Entry(Attributes.NAME_MODULE_MAIN_CLASS);
 393 
 394         final ClassEntry mainClass;
 395 
 396         public UnboundModuleMainClassAttribute(ClassEntry mainClass) {
 397             super(Attributes.moduleMainClass());
 398             this.mainClass = requireNonNull(mainClass);
 399         }
 400 
 401         @Override
 402         public ClassEntry mainClass() {
 403             return mainClass;
 404         }
 405 
 406         @Override
 407         public Utf8Entry attributeName() {
 408             return NAME;
 409         }
 410     }
 411 
 412     public static final class UnboundModuleHashesAttribute
 413             extends UnboundAttribute<ModuleHashesAttribute>
 414             implements ModuleHashesAttribute {
 415 
 416         private static final Utf8Entry NAME = TemporaryConstantPool.INSTANCE.utf8Entry(Attributes.NAME_MODULE_HASHES);
 417 
 418         private final Utf8Entry algorithm;
 419         private final List<ModuleHashInfo> hashes;
 420 
 421         public UnboundModuleHashesAttribute(Utf8Entry algorithm, List<ModuleHashInfo> hashes) {
 422             super(Attributes.moduleHashes());
 423             this.algorithm = requireNonNull(algorithm);
 424             this.hashes = List.copyOf(hashes);
 425         }
 426 
 427         @Override
 428         public Utf8Entry algorithm() {
 429             return algorithm;
 430         }
 431 
 432         @Override
 433         public List<ModuleHashInfo> hashes() {
 434             return hashes;
 435         }
 436 
 437         @Override
 438         public Utf8Entry attributeName() {
 439             return NAME;
 440         }
 441     }
 442 
 443     public static final class UnboundModulePackagesAttribute
 444             extends UnboundAttribute<ModulePackagesAttribute>
 445             implements ModulePackagesAttribute {
 446 
 447         private static final Utf8Entry NAME = TemporaryConstantPool.INSTANCE.utf8Entry(Attributes.NAME_MODULE_PACKAGES);
 448 
 449         private final Collection<PackageEntry> packages;
 450 
 451         public UnboundModulePackagesAttribute(Collection<PackageEntry> packages) {
 452             super(Attributes.modulePackages());
 453             this.packages = List.copyOf(packages);
 454         }
 455 
 456         @Override
 457         public List<PackageEntry> packages() {
 458             return List.copyOf(packages);
 459         }
 460 
 461         @Override
 462         public Utf8Entry attributeName() {
 463             return NAME;
 464         }
 465     }
 466 
 467     public static final class UnboundModuleResolutionAttribute
 468             extends UnboundAttribute<ModuleResolutionAttribute>
 469             implements ModuleResolutionAttribute {
 470 
 471         private static final Utf8Entry NAME = TemporaryConstantPool.INSTANCE.utf8Entry(Attributes.NAME_MODULE_RESOLUTION);
 472 
 473         private final int resolutionFlags;
 474 
 475         public UnboundModuleResolutionAttribute(int flags) {
 476             super(Attributes.moduleResolution());
 477             resolutionFlags = flags;
 478         }
 479 
 480         @Override
 481         public int resolutionFlags() {
 482             return resolutionFlags;
 483         }
 484 
 485         @Override
 486         public Utf8Entry attributeName() {
 487             return NAME;
 488         }
 489     }
 490 
 491     public static final class UnboundPermittedSubclassesAttribute
 492             extends UnboundAttribute<PermittedSubclassesAttribute>
 493             implements PermittedSubclassesAttribute {
 494 
 495         private static final Utf8Entry NAME = TemporaryConstantPool.INSTANCE.utf8Entry(Attributes.NAME_PERMITTED_SUBCLASSES);
 496 
 497         private final List<ClassEntry> permittedSubclasses;
 498 
 499         public UnboundPermittedSubclassesAttribute(List<ClassEntry> permittedSubclasses) {
 500             super(Attributes.permittedSubclasses());
 501             this.permittedSubclasses = List.copyOf(permittedSubclasses);
 502         }
 503 
 504         @Override
 505         public List<ClassEntry> permittedSubclasses() {
 506             return permittedSubclasses;
 507         }
 508 
 509         @Override
 510         public Utf8Entry attributeName() {
 511             return NAME;
 512         }
 513     }
 514 
 515     public static final class UnboundLoadableDescriptorsAttribute
 516             extends UnboundAttribute<LoadableDescriptorsAttribute>
 517             implements LoadableDescriptorsAttribute {
 518 
 519         private static final Utf8Entry NAME = TemporaryConstantPool.INSTANCE.utf8Entry(Attributes.NAME_LOADABLE_DESCRIPTORS);
 520 
 521         private final List<Utf8Entry> loadableDescriptors;
 522 
 523         public UnboundLoadableDescriptorsAttribute(List<Utf8Entry> loadableDescriptors) {
 524             super(Attributes.loadableDescriptors());
 525             this.loadableDescriptors = List.copyOf(loadableDescriptors);
 526         }
 527 
 528         @Override
 529         public List<Utf8Entry> loadableDescriptors() {
 530             return loadableDescriptors;
 531         }
 532 
 533         @Override
 534         public Utf8Entry attributeName() {
 535             return NAME;
 536         }
 537     }
 538 
 539     public static final class UnboundNestMembersAttribute
 540             extends UnboundAttribute<NestMembersAttribute>
 541             implements NestMembersAttribute {
 542 
 543         private static final Utf8Entry NAME = TemporaryConstantPool.INSTANCE.utf8Entry(Attributes.NAME_NEST_MEMBERS);
 544 
 545         private final List<ClassEntry> memberEntries;
 546 
 547         public UnboundNestMembersAttribute(List<ClassEntry> memberEntries) {
 548             super(Attributes.nestMembers());
 549             this.memberEntries = List.copyOf(memberEntries);
 550         }
 551 
 552         @Override
 553         public List<ClassEntry> nestMembers() {
 554             return memberEntries;
 555         }
 556 
 557         @Override
 558         public Utf8Entry attributeName() {
 559             return NAME;
 560         }
 561     }
 562 
 563     public static final class UnboundNestHostAttribute
 564             extends UnboundAttribute<NestHostAttribute>
 565             implements NestHostAttribute {
 566 
 567         private static final Utf8Entry NAME = TemporaryConstantPool.INSTANCE.utf8Entry(Attributes.NAME_NEST_HOST);
 568 
 569         private final ClassEntry hostEntry;
 570 
 571         public UnboundNestHostAttribute(ClassEntry hostEntry) {
 572             super(Attributes.nestHost());
 573             this.hostEntry = requireNonNull(hostEntry);
 574         }
 575 
 576         @Override
 577         public ClassEntry nestHost() {
 578             return hostEntry;
 579         }
 580 
 581         @Override
 582         public Utf8Entry attributeName() {
 583             return NAME;
 584         }
 585     }
 586 
 587     public static final class UnboundCompilationIDAttribute
 588             extends UnboundAttribute<CompilationIDAttribute>
 589             implements CompilationIDAttribute {
 590 
 591         private static final Utf8Entry NAME = TemporaryConstantPool.INSTANCE.utf8Entry(Attributes.NAME_COMPILATION_ID);
 592 
 593         private final Utf8Entry idEntry;
 594 
 595         public UnboundCompilationIDAttribute(Utf8Entry idEntry) {
 596             super(Attributes.compilationId());
 597             this.idEntry = requireNonNull(idEntry);
 598         }
 599 
 600         @Override
 601         public Utf8Entry compilationId() {
 602             return idEntry;
 603         }
 604 
 605         @Override
 606         public Utf8Entry attributeName() {
 607             return NAME;
 608         }
 609     }
 610 
 611     public static final class UnboundSourceIDAttribute
 612             extends UnboundAttribute<SourceIDAttribute>
 613             implements SourceIDAttribute {
 614 
 615         private static final Utf8Entry NAME = TemporaryConstantPool.INSTANCE.utf8Entry(Attributes.NAME_SOURCE_ID);
 616 
 617         private final Utf8Entry idEntry;
 618 
 619         public UnboundSourceIDAttribute(Utf8Entry idEntry) {
 620             super(Attributes.sourceId());
 621             this.idEntry = requireNonNull(idEntry);
 622         }
 623 
 624         @Override
 625         public Utf8Entry sourceId() {
 626             return idEntry;
 627         }
 628 
 629         @Override
 630         public Utf8Entry attributeName() {
 631             return NAME;
 632         }
 633     }
 634 
 635     public static final class UnboundSourceDebugExtensionAttribute
 636         extends UnboundAttribute<SourceDebugExtensionAttribute>
 637             implements SourceDebugExtensionAttribute {
 638 
 639         private static final Utf8Entry NAME = TemporaryConstantPool.INSTANCE.utf8Entry(Attributes.NAME_SOURCE_DEBUG_EXTENSION);
 640 
 641         private final byte[] contents;
 642 
 643         public UnboundSourceDebugExtensionAttribute(byte[] contents) {
 644             super(Attributes.sourceDebugExtension());
 645             this.contents = requireNonNull(contents);
 646         }
 647 
 648         @Override
 649         public byte[] contents() {
 650             return contents;
 651         }
 652 
 653         @Override
 654         public Utf8Entry attributeName() {
 655             return NAME;
 656         }
 657     }
 658 
 659     public static final class UnboundCharacterRangeTableAttribute
 660         extends UnboundAttribute<CharacterRangeTableAttribute>
 661             implements CharacterRangeTableAttribute {
 662 
 663         private static final Utf8Entry NAME = TemporaryConstantPool.INSTANCE.utf8Entry(Attributes.NAME_CHARACTER_RANGE_TABLE);
 664 
 665         private final List<CharacterRangeInfo> ranges;
 666 
 667         public UnboundCharacterRangeTableAttribute(List<CharacterRangeInfo> ranges) {
 668             super(Attributes.characterRangeTable());
 669             this.ranges = List.copyOf(ranges);
 670         }
 671 
 672         @Override
 673         public List<CharacterRangeInfo> characterRangeTable() {
 674             return ranges;
 675         }
 676 
 677         @Override
 678         public Utf8Entry attributeName() {
 679             return NAME;
 680         }
 681     }
 682 
 683     public static final class UnboundLineNumberTableAttribute
 684         extends UnboundAttribute<LineNumberTableAttribute>
 685             implements LineNumberTableAttribute {
 686 
 687         private static final Utf8Entry NAME = TemporaryConstantPool.INSTANCE.utf8Entry(Attributes.NAME_LINE_NUMBER_TABLE);
 688 
 689         private final List<LineNumberInfo> lines;
 690 
 691         public UnboundLineNumberTableAttribute(List<LineNumberInfo> lines) {
 692             super(Attributes.lineNumberTable());
 693             this.lines = List.copyOf(lines);
 694         }
 695 
 696         @Override
 697         public List<LineNumberInfo> lineNumbers() {
 698             return lines;
 699         }
 700 
 701         @Override
 702         public Utf8Entry attributeName() {
 703             return NAME;
 704         }
 705     }
 706 
 707     public static final class UnboundLocalVariableTableAttribute
 708         extends UnboundAttribute<LocalVariableTableAttribute>
 709             implements LocalVariableTableAttribute {
 710 
 711         private static final Utf8Entry NAME = TemporaryConstantPool.INSTANCE.utf8Entry(Attributes.NAME_LOCAL_VARIABLE_TABLE);
 712 
 713         private final List<LocalVariableInfo> locals;
 714 
 715         public UnboundLocalVariableTableAttribute(List<LocalVariableInfo> locals) {
 716             super(Attributes.localVariableTable());
 717             this.locals = List.copyOf(locals);
 718         }
 719 
 720         @Override
 721         public List<LocalVariableInfo> localVariables() {
 722             return locals;
 723         }
 724 
 725         @Override
 726         public Utf8Entry attributeName() {
 727             return NAME;
 728         }
 729     }
 730 
 731     public static final class UnboundLocalVariableTypeTableAttribute
 732         extends UnboundAttribute<LocalVariableTypeTableAttribute>
 733             implements LocalVariableTypeTableAttribute {
 734 
 735         private static final Utf8Entry NAME = TemporaryConstantPool.INSTANCE.utf8Entry(Attributes.NAME_LOCAL_VARIABLE_TYPE_TABLE);
 736 
 737         private final List<LocalVariableTypeInfo> locals;
 738 
 739         public UnboundLocalVariableTypeTableAttribute(List<LocalVariableTypeInfo> locals) {
 740             super(Attributes.localVariableTypeTable());
 741             this.locals = List.copyOf(locals);
 742         }
 743 
 744         @Override
 745         public List<LocalVariableTypeInfo> localVariableTypes() {
 746             return locals;
 747         }
 748 
 749         @Override
 750         public Utf8Entry attributeName() {
 751             return NAME;
 752         }
 753     }
 754 
 755     public static final class UnboundRuntimeVisibleAnnotationsAttribute
 756             extends UnboundAttribute<RuntimeVisibleAnnotationsAttribute>
 757             implements RuntimeVisibleAnnotationsAttribute {
 758 
 759         private static final Utf8Entry NAME = TemporaryConstantPool.INSTANCE.utf8Entry(Attributes.NAME_RUNTIME_VISIBLE_ANNOTATIONS);
 760 
 761         private final List<Annotation> elements;
 762 
 763         public UnboundRuntimeVisibleAnnotationsAttribute(List<Annotation> elements) {
 764             super(Attributes.runtimeVisibleAnnotations());
 765             this.elements = List.copyOf(elements);
 766         }
 767 
 768         @Override
 769         public List<Annotation> annotations() {
 770             return elements;
 771         }
 772 
 773         @Override
 774         public Utf8Entry attributeName() {
 775             return NAME;
 776         }
 777     }
 778 
 779     public static final class UnboundRuntimeInvisibleAnnotationsAttribute
 780             extends UnboundAttribute<RuntimeInvisibleAnnotationsAttribute>
 781             implements RuntimeInvisibleAnnotationsAttribute {
 782 
 783         private static final Utf8Entry NAME = TemporaryConstantPool.INSTANCE.utf8Entry(Attributes.NAME_RUNTIME_INVISIBLE_ANNOTATIONS);
 784 
 785         private final List<Annotation> elements;
 786 
 787         public UnboundRuntimeInvisibleAnnotationsAttribute(List<Annotation> elements) {
 788             super(Attributes.runtimeInvisibleAnnotations());
 789             this.elements = List.copyOf(elements);
 790         }
 791 
 792         @Override
 793         public List<Annotation> annotations() {
 794             return elements;
 795         }
 796 
 797         @Override
 798         public Utf8Entry attributeName() {
 799             return NAME;
 800         }
 801     }
 802 
 803     public static final class UnboundRuntimeVisibleParameterAnnotationsAttribute
 804             extends UnboundAttribute<RuntimeVisibleParameterAnnotationsAttribute>
 805             implements RuntimeVisibleParameterAnnotationsAttribute {
 806 
 807         private static final Utf8Entry NAME = TemporaryConstantPool.INSTANCE.utf8Entry(Attributes.NAME_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS);
 808 
 809         private final List<List<Annotation>> elements;
 810 
 811         public UnboundRuntimeVisibleParameterAnnotationsAttribute(List<List<Annotation>> elements) {
 812             super(Attributes.runtimeVisibleParameterAnnotations());
 813             // deep copy
 814             var array = elements.toArray().clone();
 815             for (int i = 0; i < array.length; i++) {
 816                 array[i] = List.copyOf((List<?>) array[i]);
 817             }
 818 
 819             this.elements = SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(array);
 820         }
 821 
 822         @Override
 823         public List<List<Annotation>> parameterAnnotations() {
 824             return elements;
 825         }
 826 
 827         @Override
 828         public Utf8Entry attributeName() {
 829             return NAME;
 830         }
 831     }
 832 
 833     public static final class UnboundRuntimeInvisibleParameterAnnotationsAttribute
 834             extends UnboundAttribute<RuntimeInvisibleParameterAnnotationsAttribute>
 835             implements RuntimeInvisibleParameterAnnotationsAttribute {
 836 
 837         private static final Utf8Entry NAME = TemporaryConstantPool.INSTANCE.utf8Entry(Attributes.NAME_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS);
 838 
 839         private final List<List<Annotation>> elements;
 840 
 841         public UnboundRuntimeInvisibleParameterAnnotationsAttribute(List<List<Annotation>> elements) {
 842             super(Attributes.runtimeInvisibleParameterAnnotations());
 843             // deep copy
 844             var array = elements.toArray().clone();
 845             for (int i = 0; i < array.length; i++) {
 846                 array[i] = List.copyOf((List<?>) array[i]);
 847             }
 848 
 849             this.elements = SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(array);
 850         }
 851 
 852         @Override
 853         public List<List<Annotation>> parameterAnnotations() {
 854             return elements;
 855         }
 856 
 857         @Override
 858         public Utf8Entry attributeName() {
 859             return NAME;
 860         }
 861     }
 862 
 863     public static final class UnboundRuntimeVisibleTypeAnnotationsAttribute
 864             extends UnboundAttribute<RuntimeVisibleTypeAnnotationsAttribute>
 865             implements RuntimeVisibleTypeAnnotationsAttribute {
 866 
 867         private static final Utf8Entry NAME = TemporaryConstantPool.INSTANCE.utf8Entry(Attributes.NAME_RUNTIME_VISIBLE_TYPE_ANNOTATIONS);
 868 
 869         private final List<TypeAnnotation> elements;
 870 
 871         public UnboundRuntimeVisibleTypeAnnotationsAttribute(List<TypeAnnotation> elements) {
 872             super(Attributes.runtimeVisibleTypeAnnotations());
 873             this.elements = List.copyOf(elements);
 874         }
 875 
 876         @Override
 877         public List<TypeAnnotation> annotations() {
 878             return elements;
 879         }
 880 
 881         @Override
 882         public Utf8Entry attributeName() {
 883             return NAME;
 884         }
 885     }
 886 
 887     public static final class UnboundRuntimeInvisibleTypeAnnotationsAttribute
 888             extends UnboundAttribute<RuntimeInvisibleTypeAnnotationsAttribute>
 889             implements RuntimeInvisibleTypeAnnotationsAttribute {
 890 
 891         private static final Utf8Entry NAME = TemporaryConstantPool.INSTANCE.utf8Entry(Attributes.NAME_RUNTIME_INVISIBLE_TYPE_ANNOTATIONS);
 892 
 893         private final List<TypeAnnotation> elements;
 894 
 895         public UnboundRuntimeInvisibleTypeAnnotationsAttribute(List<TypeAnnotation> elements) {
 896             super(Attributes.runtimeInvisibleTypeAnnotations());
 897             this.elements = List.copyOf(elements);
 898         }
 899 
 900         @Override
 901         public List<TypeAnnotation> annotations() {
 902             return elements;
 903         }
 904 
 905         @Override
 906         public Utf8Entry attributeName() {
 907             return NAME;
 908         }
 909     }
 910 
 911     public record UnboundCharacterRangeInfo(int startPc, int endPc,
 912                                             int characterRangeStart,
 913                                             int characterRangeEnd,
 914                                             int flags)
 915             implements CharacterRangeInfo { }
 916 
 917     public record UnboundInnerClassInfo(ClassEntry innerClass,
 918                                         Optional<ClassEntry> outerClass,
 919                                         Optional<Utf8Entry> innerName,
 920                                         int flagsMask)
 921             implements InnerClassInfo {
 922         public UnboundInnerClassInfo {
 923             requireNonNull(innerClass);
 924             requireNonNull(outerClass);
 925             requireNonNull(innerName);
 926         }
 927     }
 928 
 929     public record UnboundLineNumberInfo(int startPc, int lineNumber)
 930             implements LineNumberInfo { }
 931 
 932     public record UnboundLocalVariableInfo(int startPc, int length,
 933                                            Utf8Entry name,
 934                                            Utf8Entry type,
 935                                            int slot)
 936             implements LocalVariableInfo {
 937         public UnboundLocalVariableInfo {
 938             requireNonNull(name);
 939             requireNonNull(type);
 940         }
 941     }
 942 
 943     public record UnboundLocalVariableTypeInfo(int startPc, int length,
 944                                                Utf8Entry name,
 945                                                Utf8Entry signature,
 946                                                int slot)
 947             implements LocalVariableTypeInfo {
 948         public UnboundLocalVariableTypeInfo {
 949             requireNonNull(name);
 950             requireNonNull(signature);
 951         }
 952     }
 953 
 954     public record UnboundMethodParameterInfo(Optional<Utf8Entry> name, int flagsMask)
 955             implements MethodParameterInfo {
 956         public UnboundMethodParameterInfo {
 957             requireNonNull(name);
 958         }
 959     }
 960 
 961     public record UnboundModuleExportInfo(PackageEntry exportedPackage,
 962                                           int exportsFlagsMask,
 963                                           List<ModuleEntry> exportsTo)
 964             implements ModuleExportInfo {
 965         public UnboundModuleExportInfo {
 966             requireNonNull(exportedPackage);
 967             exportsTo = List.copyOf(exportsTo);
 968         }
 969     }
 970 
 971     public record UnboundModuleHashInfo(ModuleEntry moduleName,
 972                                         byte[] hash) implements ModuleHashInfo {
 973         public UnboundModuleHashInfo {
 974             requireNonNull(moduleName);
 975             requireNonNull(hash);
 976         }
 977     }
 978 
 979     public record UnboundModuleOpenInfo(PackageEntry openedPackage, int opensFlagsMask,
 980                                         List<ModuleEntry> opensTo)
 981             implements ModuleOpenInfo {
 982         public UnboundModuleOpenInfo {
 983             requireNonNull(openedPackage);
 984             opensTo = List.copyOf(opensTo);
 985         }
 986     }
 987 
 988     public record UnboundModuleProvideInfo(ClassEntry provides,
 989                                            List<ClassEntry> providesWith)
 990             implements ModuleProvideInfo {
 991         public UnboundModuleProvideInfo {
 992             requireNonNull(provides);
 993             providesWith = List.copyOf(providesWith);
 994         }
 995     }
 996 
 997     public record UnboundModuleRequiresInfo(ModuleEntry requires, int requiresFlagsMask,
 998                                             Optional<Utf8Entry> requiresVersion)
 999             implements ModuleRequireInfo {
1000         public UnboundModuleRequiresInfo {
1001             requireNonNull(requires);
1002             requireNonNull(requiresVersion);
1003         }
1004     }
1005 
1006     public record UnboundRecordComponentInfo(Utf8Entry name,
1007                                              Utf8Entry descriptor,
1008                                              List<Attribute<?>> attributes)
1009             implements RecordComponentInfo {
1010         public UnboundRecordComponentInfo {
1011             requireNonNull(name);
1012             requireNonNull(descriptor);
1013             attributes = List.copyOf(attributes);
1014         }
1015     }
1016 
1017     public record UnboundTypeAnnotation(TargetInfo targetInfo,
1018                                         List<TypePathComponent> targetPath,
1019                                         Annotation annotation) implements TypeAnnotation {
1020 
1021         public UnboundTypeAnnotation {
1022             requireNonNull(targetInfo);
1023             targetPath = List.copyOf(targetPath);
1024             requireNonNull(annotation);
1025         }
1026     }
1027 
1028     public record TypePathComponentImpl(TypeAnnotation.TypePathComponent.Kind typePathKind, int typeArgumentIndex)
1029             implements TypeAnnotation.TypePathComponent {}
1030 
1031     public static final class UnboundModuleAttribute extends UnboundAttribute<ModuleAttribute> implements ModuleAttribute {
1032 
1033         private static final Utf8Entry NAME = TemporaryConstantPool.INSTANCE.utf8Entry(Attributes.NAME_MODULE);
1034 
1035         private final ModuleEntry moduleName;
1036         private final int moduleFlags;
1037         private final Utf8Entry moduleVersion;
1038         private final List<ModuleRequireInfo> requires;
1039         private final List<ModuleExportInfo> exports;
1040         private final List<ModuleOpenInfo> opens;
1041         private final List<ClassEntry> uses;
1042         private final List<ModuleProvideInfo> provides;
1043 
1044         public UnboundModuleAttribute(ModuleEntry moduleName,
1045                                       int moduleFlags,
1046                                       Utf8Entry moduleVersion,
1047                                       Collection<ModuleRequireInfo> requires,
1048                                       Collection<ModuleExportInfo> exports,
1049                                       Collection<ModuleOpenInfo> opens,
1050                                       Collection<ClassEntry> uses,
1051                                       Collection<ModuleProvideInfo> provides)
1052         {
1053             super(Attributes.module());
1054             this.moduleName = requireNonNull(moduleName);
1055             this.moduleFlags = moduleFlags;
1056             this.moduleVersion = moduleVersion;
1057             this.requires = List.copyOf(requires);
1058             this.exports = List.copyOf(exports);
1059             this.opens = List.copyOf(opens);
1060             this.uses = List.copyOf(uses);
1061             this.provides = List.copyOf(provides);
1062         }
1063 
1064         @Override
1065         public ModuleEntry moduleName() {
1066             return moduleName;
1067         }
1068 
1069         @Override
1070         public int moduleFlagsMask() {
1071             return moduleFlags;
1072         }
1073 
1074         @Override
1075         public Optional<Utf8Entry> moduleVersion() {
1076             return Optional.ofNullable(moduleVersion);
1077         }
1078 
1079         @Override
1080         public List<ModuleRequireInfo> requires() {
1081             return requires;
1082         }
1083 
1084         @Override
1085         public List<ModuleExportInfo> exports() {
1086             return exports;
1087         }
1088 
1089         @Override
1090         public List<ModuleOpenInfo> opens() {
1091             return opens;
1092         }
1093 
1094         @Override
1095         public List<ClassEntry> uses() {
1096             return uses;
1097         }
1098 
1099         @Override
1100         public List<ModuleProvideInfo> provides() {
1101             return provides;
1102         }
1103 
1104         @Override
1105         public Utf8Entry attributeName() {
1106             return NAME;
1107         }
1108     }
1109 
1110     public abstract static non-sealed class AdHocAttribute<T extends Attribute<T>>
1111             extends UnboundAttribute<T> {
1112 
1113         public AdHocAttribute(AttributeMapper<T> mapper) {
1114             super(mapper);
1115         }
1116 
1117         public abstract void writeBody(BufWriterImpl b);
1118 
1119         @Override
1120         public void writeTo(BufWriterImpl b) {
1121             b.writeIndex(b.constantPool().utf8Entry(mapper.name()));
1122             int lengthIndex = b.skip(4);
1123             writeBody(b);
1124             int written = b.size() - lengthIndex - 4;
1125             b.patchInt(lengthIndex, written);
1126         }
1127     }
1128 
1129     public static final class EmptyBootstrapAttribute
1130             extends UnboundAttribute<BootstrapMethodsAttribute>
1131             implements BootstrapMethodsAttribute {
1132 
1133         private static final Utf8Entry NAME = TemporaryConstantPool.INSTANCE.utf8Entry(Attributes.NAME_BOOTSTRAP_METHODS);
1134 
1135         public EmptyBootstrapAttribute() {
1136             super(Attributes.bootstrapMethods());
1137         }
1138 
1139         @Override
1140         public int bootstrapMethodsSize() {
1141             return 0;
1142         }
1143 
1144         @Override
1145         public List<BootstrapMethodEntry> bootstrapMethods() {
1146             return List.of();
1147         }
1148 
1149         @Override
1150         public Utf8Entry attributeName() {
1151             return NAME;
1152         }
1153     }
1154 }