1 /*
   2  * Copyright (c) 2022, 2025, 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 = Util.sanitizeU2List(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 = Util.sanitizeU2List(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 = Util.sanitizeU2List(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 = Util.sanitizeU2List(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 = Util.sanitizeU1List(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 = Util.sanitizeU2List(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 List<PackageEntry> packages;
 450 
 451         public UnboundModulePackagesAttribute(Collection<PackageEntry> packages) {
 452             super(Attributes.modulePackages());
 453             this.packages = Util.sanitizeU2List(packages);
 454         }
 455 
 456         @Override
 457         public List<PackageEntry> packages() {
 458             return 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 = Util.checkU2(flags, "resolution 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 = Util.sanitizeU2List(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 = Util.sanitizeU2List(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 = Util.sanitizeU2List(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 = Util.sanitizeU2List(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 = Util.sanitizeU2List(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 = Util.sanitizeU2List(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 = Util.sanitizeU2List(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 = Util.sanitizeU2List(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             this.elements = Util.sanitizeParameterAnnotations(elements);
 814         }
 815 
 816         @Override
 817         public List<List<Annotation>> parameterAnnotations() {
 818             return elements;
 819         }
 820 
 821         @Override
 822         public Utf8Entry attributeName() {
 823             return NAME;
 824         }
 825     }
 826 
 827     public static final class UnboundRuntimeInvisibleParameterAnnotationsAttribute
 828             extends UnboundAttribute<RuntimeInvisibleParameterAnnotationsAttribute>
 829             implements RuntimeInvisibleParameterAnnotationsAttribute {
 830 
 831         private static final Utf8Entry NAME = TemporaryConstantPool.INSTANCE.utf8Entry(Attributes.NAME_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS);
 832 
 833         private final List<List<Annotation>> elements;
 834 
 835         public UnboundRuntimeInvisibleParameterAnnotationsAttribute(List<List<Annotation>> elements) {
 836             super(Attributes.runtimeInvisibleParameterAnnotations());
 837             this.elements = Util.sanitizeParameterAnnotations(elements);
 838         }
 839 
 840         @Override
 841         public List<List<Annotation>> parameterAnnotations() {
 842             return elements;
 843         }
 844 
 845         @Override
 846         public Utf8Entry attributeName() {
 847             return NAME;
 848         }
 849     }
 850 
 851     public static final class UnboundRuntimeVisibleTypeAnnotationsAttribute
 852             extends UnboundAttribute<RuntimeVisibleTypeAnnotationsAttribute>
 853             implements RuntimeVisibleTypeAnnotationsAttribute {
 854 
 855         private static final Utf8Entry NAME = TemporaryConstantPool.INSTANCE.utf8Entry(Attributes.NAME_RUNTIME_VISIBLE_TYPE_ANNOTATIONS);
 856 
 857         private final List<TypeAnnotation> elements;
 858 
 859         public UnboundRuntimeVisibleTypeAnnotationsAttribute(List<TypeAnnotation> elements) {
 860             super(Attributes.runtimeVisibleTypeAnnotations());
 861             this.elements = Util.sanitizeU2List(elements);
 862         }
 863 
 864         @Override
 865         public List<TypeAnnotation> annotations() {
 866             return elements;
 867         }
 868 
 869         @Override
 870         public Utf8Entry attributeName() {
 871             return NAME;
 872         }
 873     }
 874 
 875     public static final class UnboundRuntimeInvisibleTypeAnnotationsAttribute
 876             extends UnboundAttribute<RuntimeInvisibleTypeAnnotationsAttribute>
 877             implements RuntimeInvisibleTypeAnnotationsAttribute {
 878 
 879         private static final Utf8Entry NAME = TemporaryConstantPool.INSTANCE.utf8Entry(Attributes.NAME_RUNTIME_INVISIBLE_TYPE_ANNOTATIONS);
 880 
 881         private final List<TypeAnnotation> elements;
 882 
 883         public UnboundRuntimeInvisibleTypeAnnotationsAttribute(List<TypeAnnotation> elements) {
 884             super(Attributes.runtimeInvisibleTypeAnnotations());
 885             this.elements = Util.sanitizeU2List(elements);
 886         }
 887 
 888         @Override
 889         public List<TypeAnnotation> annotations() {
 890             return elements;
 891         }
 892 
 893         @Override
 894         public Utf8Entry attributeName() {
 895             return NAME;
 896         }
 897     }
 898 
 899     public record UnboundCharacterRangeInfo(int startPc, int endPc,
 900                                             int characterRangeStart,
 901                                             int characterRangeEnd,
 902                                             int flags)
 903             implements CharacterRangeInfo {
 904 
 905         public UnboundCharacterRangeInfo {
 906             Util.checkU2(startPc, "start pc");
 907             Util.checkU2(endPc, "end pc");
 908             Util.checkU2(flags, "flags");
 909         }
 910     }
 911 
 912     public record UnboundInnerClassInfo(ClassEntry innerClass,
 913                                         Optional<ClassEntry> outerClass,
 914                                         Optional<Utf8Entry> innerName,
 915                                         int flagsMask)
 916             implements InnerClassInfo {
 917         public UnboundInnerClassInfo {
 918             requireNonNull(innerClass);
 919             requireNonNull(outerClass);
 920             requireNonNull(innerName);
 921             Util.checkFlags(flagsMask);
 922         }
 923     }
 924 
 925     public record UnboundLineNumberInfo(int startPc, int lineNumber)
 926             implements LineNumberInfo {
 927         public UnboundLineNumberInfo {
 928             Util.checkU2(startPc, "start pc");
 929             Util.checkU2(lineNumber, "line number");
 930         }
 931     }
 932 
 933     public record UnboundLocalVariableInfo(int startPc, int length,
 934                                            Utf8Entry name,
 935                                            Utf8Entry type,
 936                                            int slot)
 937             implements LocalVariableInfo {
 938         public UnboundLocalVariableInfo {
 939             requireNonNull(name);
 940             requireNonNull(type);
 941         }
 942     }
 943 
 944     public record UnboundLocalVariableTypeInfo(int startPc, int length,
 945                                                Utf8Entry name,
 946                                                Utf8Entry signature,
 947                                                int slot)
 948             implements LocalVariableTypeInfo {
 949         public UnboundLocalVariableTypeInfo {
 950             requireNonNull(name);
 951             requireNonNull(signature);
 952         }
 953     }
 954 
 955     public record UnboundMethodParameterInfo(Optional<Utf8Entry> name, int flagsMask)
 956             implements MethodParameterInfo {
 957         public UnboundMethodParameterInfo {
 958             requireNonNull(name);
 959             Util.checkFlags(flagsMask);
 960         }
 961     }
 962 
 963     public record UnboundModuleExportInfo(PackageEntry exportedPackage,
 964                                           int exportsFlagsMask,
 965                                           List<ModuleEntry> exportsTo)
 966             implements ModuleExportInfo {
 967         public UnboundModuleExportInfo {
 968             requireNonNull(exportedPackage);
 969             Util.checkFlags(exportsFlagsMask);
 970             exportsTo = Util.sanitizeU2List(exportsTo);
 971         }
 972     }
 973 
 974     public record UnboundModuleHashInfo(ModuleEntry moduleName,
 975                                         byte[] hash) implements ModuleHashInfo {
 976         public UnboundModuleHashInfo {
 977             requireNonNull(moduleName);
 978             requireNonNull(hash);
 979         }
 980     }
 981 
 982     public record UnboundModuleOpenInfo(PackageEntry openedPackage, int opensFlagsMask,
 983                                         List<ModuleEntry> opensTo)
 984             implements ModuleOpenInfo {
 985         public UnboundModuleOpenInfo {
 986             requireNonNull(openedPackage);
 987             Util.checkFlags(opensFlagsMask);
 988             opensTo = Util.sanitizeU2List(opensTo);
 989         }
 990     }
 991 
 992     public record UnboundModuleProvideInfo(ClassEntry provides,
 993                                            List<ClassEntry> providesWith)
 994             implements ModuleProvideInfo {
 995         public UnboundModuleProvideInfo {
 996             requireNonNull(provides);
 997             providesWith = Util.sanitizeU2List(providesWith);
 998         }
 999     }
1000 
1001     public record UnboundModuleRequiresInfo(ModuleEntry requires, int requiresFlagsMask,
1002                                             Optional<Utf8Entry> requiresVersion)
1003             implements ModuleRequireInfo {
1004         public UnboundModuleRequiresInfo {
1005             requireNonNull(requires);
1006             Util.checkFlags(requiresFlagsMask);
1007             requireNonNull(requiresVersion);
1008         }
1009     }
1010 
1011     public record UnboundRecordComponentInfo(Utf8Entry name,
1012                                              Utf8Entry descriptor,
1013                                              List<Attribute<?>> attributes)
1014             implements RecordComponentInfo {
1015         public UnboundRecordComponentInfo {
1016             requireNonNull(name);
1017             requireNonNull(descriptor);
1018             attributes = Util.sanitizeU2List(attributes);
1019         }
1020     }
1021 
1022     public record UnboundTypeAnnotation(TargetInfo targetInfo,
1023                                         List<TypePathComponent> targetPath,
1024                                         Annotation annotation) implements TypeAnnotation {
1025 
1026         public UnboundTypeAnnotation {
1027             requireNonNull(targetInfo);
1028             targetPath = Util.sanitizeU1List(targetPath);
1029             requireNonNull(annotation);
1030         }
1031     }
1032 
1033     public record TypePathComponentImpl(TypeAnnotation.TypePathComponent.Kind typePathKind, int typeArgumentIndex)
1034             implements TypeAnnotation.TypePathComponent {}
1035 
1036     public static final class UnboundModuleAttribute extends UnboundAttribute<ModuleAttribute> implements ModuleAttribute {
1037 
1038         private static final Utf8Entry NAME = TemporaryConstantPool.INSTANCE.utf8Entry(Attributes.NAME_MODULE);
1039 
1040         private final ModuleEntry moduleName;
1041         private final int moduleFlags;
1042         private final Utf8Entry moduleVersion;
1043         private final List<ModuleRequireInfo> requires;
1044         private final List<ModuleExportInfo> exports;
1045         private final List<ModuleOpenInfo> opens;
1046         private final List<ClassEntry> uses;
1047         private final List<ModuleProvideInfo> provides;
1048 
1049         public UnboundModuleAttribute(ModuleEntry moduleName,
1050                                       int moduleFlags,
1051                                       Utf8Entry moduleVersion,
1052                                       Collection<ModuleRequireInfo> requires,
1053                                       Collection<ModuleExportInfo> exports,
1054                                       Collection<ModuleOpenInfo> opens,
1055                                       Collection<ClassEntry> uses,
1056                                       Collection<ModuleProvideInfo> provides)
1057         {
1058             super(Attributes.module());
1059             this.moduleName = requireNonNull(moduleName);
1060             this.moduleFlags = Util.checkFlags(moduleFlags);
1061             this.moduleVersion = moduleVersion;
1062             this.requires = Util.sanitizeU2List(requires);
1063             this.exports = Util.sanitizeU2List(exports);
1064             this.opens = Util.sanitizeU2List(opens);
1065             this.uses = Util.sanitizeU2List(uses);
1066             this.provides = Util.sanitizeU2List(provides);
1067         }
1068 
1069         @Override
1070         public ModuleEntry moduleName() {
1071             return moduleName;
1072         }
1073 
1074         @Override
1075         public int moduleFlagsMask() {
1076             return moduleFlags;
1077         }
1078 
1079         @Override
1080         public Optional<Utf8Entry> moduleVersion() {
1081             return Optional.ofNullable(moduleVersion);
1082         }
1083 
1084         @Override
1085         public List<ModuleRequireInfo> requires() {
1086             return requires;
1087         }
1088 
1089         @Override
1090         public List<ModuleExportInfo> exports() {
1091             return exports;
1092         }
1093 
1094         @Override
1095         public List<ModuleOpenInfo> opens() {
1096             return opens;
1097         }
1098 
1099         @Override
1100         public List<ClassEntry> uses() {
1101             return uses;
1102         }
1103 
1104         @Override
1105         public List<ModuleProvideInfo> provides() {
1106             return provides;
1107         }
1108 
1109         @Override
1110         public Utf8Entry attributeName() {
1111             return NAME;
1112         }
1113     }
1114 
1115     public abstract static non-sealed class AdHocAttribute<T extends Attribute<T>>
1116             extends UnboundAttribute<T> {
1117 
1118         public AdHocAttribute(AttributeMapper<T> mapper) {
1119             super(mapper);
1120         }
1121 
1122         public abstract void writeBody(BufWriterImpl b);
1123 
1124         @Override
1125         public void writeTo(BufWriterImpl b) {
1126             b.writeIndex(b.constantPool().utf8Entry(mapper.name()));
1127             int lengthIndex = b.skip(4);
1128             writeBody(b);
1129             int written = b.size() - lengthIndex - 4;
1130             b.patchInt(lengthIndex, written);
1131         }
1132     }
1133 
1134     public static final class EmptyBootstrapAttribute
1135             extends UnboundAttribute<BootstrapMethodsAttribute>
1136             implements BootstrapMethodsAttribute {
1137 
1138         private static final Utf8Entry NAME = TemporaryConstantPool.INSTANCE.utf8Entry(Attributes.NAME_BOOTSTRAP_METHODS);
1139 
1140         public EmptyBootstrapAttribute() {
1141             super(Attributes.bootstrapMethods());
1142         }
1143 
1144         @Override
1145         public int bootstrapMethodsSize() {
1146             return 0;
1147         }
1148 
1149         @Override
1150         public List<BootstrapMethodEntry> bootstrapMethods() {
1151             return List.of();
1152         }
1153 
1154         @Override
1155         public Utf8Entry attributeName() {
1156             return NAME;
1157         }
1158     }
1159 }