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 UnboundNestMembersAttribute
 516             extends UnboundAttribute<NestMembersAttribute>
 517             implements NestMembersAttribute {
 518 
 519         private static final Utf8Entry NAME = TemporaryConstantPool.INSTANCE.utf8Entry(Attributes.NAME_NEST_MEMBERS);
 520 
 521         private final List<ClassEntry> memberEntries;
 522 
 523         public UnboundNestMembersAttribute(List<ClassEntry> memberEntries) {
 524             super(Attributes.nestMembers());
 525             this.memberEntries = Util.sanitizeU2List(memberEntries);
 526         }
 527 
 528         @Override
 529         public List<ClassEntry> nestMembers() {
 530             return memberEntries;
 531         }
 532 
 533         @Override
 534         public Utf8Entry attributeName() {
 535             return NAME;
 536         }
 537     }
 538 
 539     public static final class UnboundNestHostAttribute
 540             extends UnboundAttribute<NestHostAttribute>
 541             implements NestHostAttribute {
 542 
 543         private static final Utf8Entry NAME = TemporaryConstantPool.INSTANCE.utf8Entry(Attributes.NAME_NEST_HOST);
 544 
 545         private final ClassEntry hostEntry;
 546 
 547         public UnboundNestHostAttribute(ClassEntry hostEntry) {
 548             super(Attributes.nestHost());
 549             this.hostEntry = requireNonNull(hostEntry);
 550         }
 551 
 552         @Override
 553         public ClassEntry nestHost() {
 554             return hostEntry;
 555         }
 556 
 557         @Override
 558         public Utf8Entry attributeName() {
 559             return NAME;
 560         }
 561     }
 562 
 563     public static final class UnboundCompilationIDAttribute
 564             extends UnboundAttribute<CompilationIDAttribute>
 565             implements CompilationIDAttribute {
 566 
 567         private static final Utf8Entry NAME = TemporaryConstantPool.INSTANCE.utf8Entry(Attributes.NAME_COMPILATION_ID);
 568 
 569         private final Utf8Entry idEntry;
 570 
 571         public UnboundCompilationIDAttribute(Utf8Entry idEntry) {
 572             super(Attributes.compilationId());
 573             this.idEntry = requireNonNull(idEntry);
 574         }
 575 
 576         @Override
 577         public Utf8Entry compilationId() {
 578             return idEntry;
 579         }
 580 
 581         @Override
 582         public Utf8Entry attributeName() {
 583             return NAME;
 584         }
 585     }
 586 
 587     public static final class UnboundSourceIDAttribute
 588             extends UnboundAttribute<SourceIDAttribute>
 589             implements SourceIDAttribute {
 590 
 591         private static final Utf8Entry NAME = TemporaryConstantPool.INSTANCE.utf8Entry(Attributes.NAME_SOURCE_ID);
 592 
 593         private final Utf8Entry idEntry;
 594 
 595         public UnboundSourceIDAttribute(Utf8Entry idEntry) {
 596             super(Attributes.sourceId());
 597             this.idEntry = requireNonNull(idEntry);
 598         }
 599 
 600         @Override
 601         public Utf8Entry sourceId() {
 602             return idEntry;
 603         }
 604 
 605         @Override
 606         public Utf8Entry attributeName() {
 607             return NAME;
 608         }
 609     }
 610 
 611     public static final class UnboundSourceDebugExtensionAttribute
 612         extends UnboundAttribute<SourceDebugExtensionAttribute>
 613             implements SourceDebugExtensionAttribute {
 614 
 615         private static final Utf8Entry NAME = TemporaryConstantPool.INSTANCE.utf8Entry(Attributes.NAME_SOURCE_DEBUG_EXTENSION);
 616 
 617         private final byte[] contents;
 618 
 619         public UnboundSourceDebugExtensionAttribute(byte[] contents) {
 620             super(Attributes.sourceDebugExtension());
 621             this.contents = requireNonNull(contents);
 622         }
 623 
 624         @Override
 625         public byte[] contents() {
 626             return contents;
 627         }
 628 
 629         @Override
 630         public Utf8Entry attributeName() {
 631             return NAME;
 632         }
 633     }
 634 
 635     public static final class UnboundCharacterRangeTableAttribute
 636         extends UnboundAttribute<CharacterRangeTableAttribute>
 637             implements CharacterRangeTableAttribute {
 638 
 639         private static final Utf8Entry NAME = TemporaryConstantPool.INSTANCE.utf8Entry(Attributes.NAME_CHARACTER_RANGE_TABLE);
 640 
 641         private final List<CharacterRangeInfo> ranges;
 642 
 643         public UnboundCharacterRangeTableAttribute(List<CharacterRangeInfo> ranges) {
 644             super(Attributes.characterRangeTable());
 645             this.ranges = Util.sanitizeU2List(ranges);
 646         }
 647 
 648         @Override
 649         public List<CharacterRangeInfo> characterRangeTable() {
 650             return ranges;
 651         }
 652 
 653         @Override
 654         public Utf8Entry attributeName() {
 655             return NAME;
 656         }
 657     }
 658 
 659     public static final class UnboundLineNumberTableAttribute
 660         extends UnboundAttribute<LineNumberTableAttribute>
 661             implements LineNumberTableAttribute {
 662 
 663         private static final Utf8Entry NAME = TemporaryConstantPool.INSTANCE.utf8Entry(Attributes.NAME_LINE_NUMBER_TABLE);
 664 
 665         private final List<LineNumberInfo> lines;
 666 
 667         public UnboundLineNumberTableAttribute(List<LineNumberInfo> lines) {
 668             super(Attributes.lineNumberTable());
 669             this.lines = Util.sanitizeU2List(lines);
 670         }
 671 
 672         @Override
 673         public List<LineNumberInfo> lineNumbers() {
 674             return lines;
 675         }
 676 
 677         @Override
 678         public Utf8Entry attributeName() {
 679             return NAME;
 680         }
 681     }
 682 
 683     public static final class UnboundLocalVariableTableAttribute
 684         extends UnboundAttribute<LocalVariableTableAttribute>
 685             implements LocalVariableTableAttribute {
 686 
 687         private static final Utf8Entry NAME = TemporaryConstantPool.INSTANCE.utf8Entry(Attributes.NAME_LOCAL_VARIABLE_TABLE);
 688 
 689         private final List<LocalVariableInfo> locals;
 690 
 691         public UnboundLocalVariableTableAttribute(List<LocalVariableInfo> locals) {
 692             super(Attributes.localVariableTable());
 693             this.locals = Util.sanitizeU2List(locals);
 694         }
 695 
 696         @Override
 697         public List<LocalVariableInfo> localVariables() {
 698             return locals;
 699         }
 700 
 701         @Override
 702         public Utf8Entry attributeName() {
 703             return NAME;
 704         }
 705     }
 706 
 707     public static final class UnboundLocalVariableTypeTableAttribute
 708         extends UnboundAttribute<LocalVariableTypeTableAttribute>
 709             implements LocalVariableTypeTableAttribute {
 710 
 711         private static final Utf8Entry NAME = TemporaryConstantPool.INSTANCE.utf8Entry(Attributes.NAME_LOCAL_VARIABLE_TYPE_TABLE);
 712 
 713         private final List<LocalVariableTypeInfo> locals;
 714 
 715         public UnboundLocalVariableTypeTableAttribute(List<LocalVariableTypeInfo> locals) {
 716             super(Attributes.localVariableTypeTable());
 717             this.locals = Util.sanitizeU2List(locals);
 718         }
 719 
 720         @Override
 721         public List<LocalVariableTypeInfo> localVariableTypes() {
 722             return locals;
 723         }
 724 
 725         @Override
 726         public Utf8Entry attributeName() {
 727             return NAME;
 728         }
 729     }
 730 
 731     public static final class UnboundRuntimeVisibleAnnotationsAttribute
 732             extends UnboundAttribute<RuntimeVisibleAnnotationsAttribute>
 733             implements RuntimeVisibleAnnotationsAttribute {
 734 
 735         private static final Utf8Entry NAME = TemporaryConstantPool.INSTANCE.utf8Entry(Attributes.NAME_RUNTIME_VISIBLE_ANNOTATIONS);
 736 
 737         private final List<Annotation> elements;
 738 
 739         public UnboundRuntimeVisibleAnnotationsAttribute(List<Annotation> elements) {
 740             super(Attributes.runtimeVisibleAnnotations());
 741             this.elements = Util.sanitizeU2List(elements);
 742         }
 743 
 744         @Override
 745         public List<Annotation> annotations() {
 746             return elements;
 747         }
 748 
 749         @Override
 750         public Utf8Entry attributeName() {
 751             return NAME;
 752         }
 753     }
 754 
 755     public static final class UnboundRuntimeInvisibleAnnotationsAttribute
 756             extends UnboundAttribute<RuntimeInvisibleAnnotationsAttribute>
 757             implements RuntimeInvisibleAnnotationsAttribute {
 758 
 759         private static final Utf8Entry NAME = TemporaryConstantPool.INSTANCE.utf8Entry(Attributes.NAME_RUNTIME_INVISIBLE_ANNOTATIONS);
 760 
 761         private final List<Annotation> elements;
 762 
 763         public UnboundRuntimeInvisibleAnnotationsAttribute(List<Annotation> elements) {
 764             super(Attributes.runtimeInvisibleAnnotations());
 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 UnboundRuntimeVisibleParameterAnnotationsAttribute
 780             extends UnboundAttribute<RuntimeVisibleParameterAnnotationsAttribute>
 781             implements RuntimeVisibleParameterAnnotationsAttribute {
 782 
 783         private static final Utf8Entry NAME = TemporaryConstantPool.INSTANCE.utf8Entry(Attributes.NAME_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS);
 784 
 785         private final List<List<Annotation>> elements;
 786 
 787         public UnboundRuntimeVisibleParameterAnnotationsAttribute(List<List<Annotation>> elements) {
 788             super(Attributes.runtimeVisibleParameterAnnotations());
 789             this.elements = Util.sanitizeParameterAnnotations(elements);
 790         }
 791 
 792         @Override
 793         public List<List<Annotation>> parameterAnnotations() {
 794             return elements;
 795         }
 796 
 797         @Override
 798         public Utf8Entry attributeName() {
 799             return NAME;
 800         }
 801     }
 802 
 803     public static final class UnboundRuntimeInvisibleParameterAnnotationsAttribute
 804             extends UnboundAttribute<RuntimeInvisibleParameterAnnotationsAttribute>
 805             implements RuntimeInvisibleParameterAnnotationsAttribute {
 806 
 807         private static final Utf8Entry NAME = TemporaryConstantPool.INSTANCE.utf8Entry(Attributes.NAME_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS);
 808 
 809         private final List<List<Annotation>> elements;
 810 
 811         public UnboundRuntimeInvisibleParameterAnnotationsAttribute(List<List<Annotation>> elements) {
 812             super(Attributes.runtimeInvisibleParameterAnnotations());
 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 UnboundRuntimeVisibleTypeAnnotationsAttribute
 828             extends UnboundAttribute<RuntimeVisibleTypeAnnotationsAttribute>
 829             implements RuntimeVisibleTypeAnnotationsAttribute {
 830 
 831         private static final Utf8Entry NAME = TemporaryConstantPool.INSTANCE.utf8Entry(Attributes.NAME_RUNTIME_VISIBLE_TYPE_ANNOTATIONS);
 832 
 833         private final List<TypeAnnotation> elements;
 834 
 835         public UnboundRuntimeVisibleTypeAnnotationsAttribute(List<TypeAnnotation> elements) {
 836             super(Attributes.runtimeVisibleTypeAnnotations());
 837             this.elements = Util.sanitizeU2List(elements);
 838         }
 839 
 840         @Override
 841         public List<TypeAnnotation> annotations() {
 842             return elements;
 843         }
 844 
 845         @Override
 846         public Utf8Entry attributeName() {
 847             return NAME;
 848         }
 849     }
 850 
 851     public static final class UnboundRuntimeInvisibleTypeAnnotationsAttribute
 852             extends UnboundAttribute<RuntimeInvisibleTypeAnnotationsAttribute>
 853             implements RuntimeInvisibleTypeAnnotationsAttribute {
 854 
 855         private static final Utf8Entry NAME = TemporaryConstantPool.INSTANCE.utf8Entry(Attributes.NAME_RUNTIME_INVISIBLE_TYPE_ANNOTATIONS);
 856 
 857         private final List<TypeAnnotation> elements;
 858 
 859         public UnboundRuntimeInvisibleTypeAnnotationsAttribute(List<TypeAnnotation> elements) {
 860             super(Attributes.runtimeInvisibleTypeAnnotations());
 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 record UnboundCharacterRangeInfo(int startPc, int endPc,
 876                                             int characterRangeStart,
 877                                             int characterRangeEnd,
 878                                             int flags)
 879             implements CharacterRangeInfo {
 880 
 881         public UnboundCharacterRangeInfo {
 882             Util.checkU2(startPc, "start pc");
 883             Util.checkU2(endPc, "end pc");
 884             Util.checkU2(flags, "flags");
 885         }
 886     }
 887 
 888     public record UnboundInnerClassInfo(ClassEntry innerClass,
 889                                         Optional<ClassEntry> outerClass,
 890                                         Optional<Utf8Entry> innerName,
 891                                         int flagsMask)
 892             implements InnerClassInfo {
 893         public UnboundInnerClassInfo {
 894             requireNonNull(innerClass);
 895             requireNonNull(outerClass);
 896             requireNonNull(innerName);
 897             Util.checkFlags(flagsMask);
 898         }
 899     }
 900 
 901     public record UnboundLineNumberInfo(int startPc, int lineNumber)
 902             implements LineNumberInfo {
 903         public UnboundLineNumberInfo {
 904             Util.checkU2(startPc, "start pc");
 905             Util.checkU2(lineNumber, "line number");
 906         }
 907     }
 908 
 909     public record UnboundLocalVariableInfo(int startPc, int length,
 910                                            Utf8Entry name,
 911                                            Utf8Entry type,
 912                                            int slot)
 913             implements LocalVariableInfo {
 914         public UnboundLocalVariableInfo {
 915             requireNonNull(name);
 916             requireNonNull(type);
 917         }
 918     }
 919 
 920     public record UnboundLocalVariableTypeInfo(int startPc, int length,
 921                                                Utf8Entry name,
 922                                                Utf8Entry signature,
 923                                                int slot)
 924             implements LocalVariableTypeInfo {
 925         public UnboundLocalVariableTypeInfo {
 926             requireNonNull(name);
 927             requireNonNull(signature);
 928         }
 929     }
 930 
 931     public record UnboundMethodParameterInfo(Optional<Utf8Entry> name, int flagsMask)
 932             implements MethodParameterInfo {
 933         public UnboundMethodParameterInfo {
 934             requireNonNull(name);
 935             Util.checkFlags(flagsMask);
 936         }
 937     }
 938 
 939     public record UnboundModuleExportInfo(PackageEntry exportedPackage,
 940                                           int exportsFlagsMask,
 941                                           List<ModuleEntry> exportsTo)
 942             implements ModuleExportInfo {
 943         public UnboundModuleExportInfo {
 944             requireNonNull(exportedPackage);
 945             Util.checkFlags(exportsFlagsMask);
 946             exportsTo = Util.sanitizeU2List(exportsTo);
 947         }
 948     }
 949 
 950     public record UnboundModuleHashInfo(ModuleEntry moduleName,
 951                                         byte[] hash) implements ModuleHashInfo {
 952         public UnboundModuleHashInfo {
 953             requireNonNull(moduleName);
 954             requireNonNull(hash);
 955         }
 956     }
 957 
 958     public record UnboundModuleOpenInfo(PackageEntry openedPackage, int opensFlagsMask,
 959                                         List<ModuleEntry> opensTo)
 960             implements ModuleOpenInfo {
 961         public UnboundModuleOpenInfo {
 962             requireNonNull(openedPackage);
 963             Util.checkFlags(opensFlagsMask);
 964             opensTo = Util.sanitizeU2List(opensTo);
 965         }
 966     }
 967 
 968     public record UnboundModuleProvideInfo(ClassEntry provides,
 969                                            List<ClassEntry> providesWith)
 970             implements ModuleProvideInfo {
 971         public UnboundModuleProvideInfo {
 972             requireNonNull(provides);
 973             providesWith = Util.sanitizeU2List(providesWith);
 974         }
 975     }
 976 
 977     public record UnboundModuleRequiresInfo(ModuleEntry requires, int requiresFlagsMask,
 978                                             Optional<Utf8Entry> requiresVersion)
 979             implements ModuleRequireInfo {
 980         public UnboundModuleRequiresInfo {
 981             requireNonNull(requires);
 982             Util.checkFlags(requiresFlagsMask);
 983             requireNonNull(requiresVersion);
 984         }
 985     }
 986 
 987     public record UnboundRecordComponentInfo(Utf8Entry name,
 988                                              Utf8Entry descriptor,
 989                                              List<Attribute<?>> attributes)
 990             implements RecordComponentInfo {
 991         public UnboundRecordComponentInfo {
 992             requireNonNull(name);
 993             requireNonNull(descriptor);
 994             attributes = Util.sanitizeU2List(attributes);
 995         }
 996     }
 997 
 998     public record UnboundTypeAnnotation(TargetInfo targetInfo,
 999                                         List<TypePathComponent> targetPath,
1000                                         Annotation annotation) implements TypeAnnotation {
1001 
1002         public UnboundTypeAnnotation {
1003             requireNonNull(targetInfo);
1004             targetPath = Util.sanitizeU1List(targetPath);
1005             requireNonNull(annotation);
1006         }
1007     }
1008 
1009     public record TypePathComponentImpl(TypeAnnotation.TypePathComponent.Kind typePathKind, int typeArgumentIndex)
1010             implements TypeAnnotation.TypePathComponent {}
1011 
1012     public static final class UnboundModuleAttribute extends UnboundAttribute<ModuleAttribute> implements ModuleAttribute {
1013 
1014         private static final Utf8Entry NAME = TemporaryConstantPool.INSTANCE.utf8Entry(Attributes.NAME_MODULE);
1015 
1016         private final ModuleEntry moduleName;
1017         private final int moduleFlags;
1018         private final Utf8Entry moduleVersion;
1019         private final List<ModuleRequireInfo> requires;
1020         private final List<ModuleExportInfo> exports;
1021         private final List<ModuleOpenInfo> opens;
1022         private final List<ClassEntry> uses;
1023         private final List<ModuleProvideInfo> provides;
1024 
1025         public UnboundModuleAttribute(ModuleEntry moduleName,
1026                                       int moduleFlags,
1027                                       Utf8Entry moduleVersion,
1028                                       Collection<ModuleRequireInfo> requires,
1029                                       Collection<ModuleExportInfo> exports,
1030                                       Collection<ModuleOpenInfo> opens,
1031                                       Collection<ClassEntry> uses,
1032                                       Collection<ModuleProvideInfo> provides)
1033         {
1034             super(Attributes.module());
1035             this.moduleName = requireNonNull(moduleName);
1036             this.moduleFlags = Util.checkFlags(moduleFlags);
1037             this.moduleVersion = moduleVersion;
1038             this.requires = Util.sanitizeU2List(requires);
1039             this.exports = Util.sanitizeU2List(exports);
1040             this.opens = Util.sanitizeU2List(opens);
1041             this.uses = Util.sanitizeU2List(uses);
1042             this.provides = Util.sanitizeU2List(provides);
1043         }
1044 
1045         @Override
1046         public ModuleEntry moduleName() {
1047             return moduleName;
1048         }
1049 
1050         @Override
1051         public int moduleFlagsMask() {
1052             return moduleFlags;
1053         }
1054 
1055         @Override
1056         public Optional<Utf8Entry> moduleVersion() {
1057             return Optional.ofNullable(moduleVersion);
1058         }
1059 
1060         @Override
1061         public List<ModuleRequireInfo> requires() {
1062             return requires;
1063         }
1064 
1065         @Override
1066         public List<ModuleExportInfo> exports() {
1067             return exports;
1068         }
1069 
1070         @Override
1071         public List<ModuleOpenInfo> opens() {
1072             return opens;
1073         }
1074 
1075         @Override
1076         public List<ClassEntry> uses() {
1077             return uses;
1078         }
1079 
1080         @Override
1081         public List<ModuleProvideInfo> provides() {
1082             return provides;
1083         }
1084 
1085         @Override
1086         public Utf8Entry attributeName() {
1087             return NAME;
1088         }
1089     }
1090 
1091     public abstract static non-sealed class AdHocAttribute<T extends Attribute<T>>
1092             extends UnboundAttribute<T> {
1093 
1094         public AdHocAttribute(AttributeMapper<T> mapper) {
1095             super(mapper);
1096         }
1097 
1098         public abstract void writeBody(BufWriterImpl b);
1099 
1100         @Override
1101         public void writeTo(BufWriterImpl b) {
1102             b.writeIndex(b.constantPool().utf8Entry(mapper.name()));
1103             int lengthIndex = b.skip(4);
1104             writeBody(b);
1105             int written = b.size() - lengthIndex - 4;
1106             b.patchInt(lengthIndex, written);
1107         }
1108     }
1109 
1110     public static final class EmptyBootstrapAttribute
1111             extends UnboundAttribute<BootstrapMethodsAttribute>
1112             implements BootstrapMethodsAttribute {
1113 
1114         private static final Utf8Entry NAME = TemporaryConstantPool.INSTANCE.utf8Entry(Attributes.NAME_BOOTSTRAP_METHODS);
1115 
1116         public EmptyBootstrapAttribute() {
1117             super(Attributes.bootstrapMethods());
1118         }
1119 
1120         @Override
1121         public int bootstrapMethodsSize() {
1122             return 0;
1123         }
1124 
1125         @Override
1126         public List<BootstrapMethodEntry> bootstrapMethods() {
1127             return List.of();
1128         }
1129 
1130         @Override
1131         public Utf8Entry attributeName() {
1132             return NAME;
1133         }
1134     }
1135 }