1 /*
  2  * Copyright (c) 2022, 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.util.Collection;
 28 import java.util.List;
 29 import java.util.Optional;
 30 
 31 import java.lang.classfile.Annotation;
 32 import java.lang.classfile.AnnotationElement;
 33 import java.lang.classfile.AnnotationValue;
 34 import java.lang.classfile.Attribute;
 35 import java.lang.classfile.AttributeMapper;
 36 import java.lang.classfile.Attributes;
 37 import java.lang.classfile.BootstrapMethodEntry;
 38 import java.lang.classfile.BufWriter;
 39 import java.lang.classfile.constantpool.ClassEntry;
 40 import java.lang.classfile.Label;
 41 import java.lang.classfile.TypeAnnotation;
 42 import java.lang.classfile.attribute.AnnotationDefaultAttribute;
 43 import java.lang.classfile.attribute.BootstrapMethodsAttribute;
 44 import java.lang.classfile.attribute.CharacterRangeInfo;
 45 import java.lang.classfile.attribute.CharacterRangeTableAttribute;
 46 import java.lang.classfile.attribute.CompilationIDAttribute;
 47 import java.lang.classfile.attribute.ConstantValueAttribute;
 48 import java.lang.classfile.attribute.DeprecatedAttribute;
 49 import java.lang.classfile.attribute.EnclosingMethodAttribute;
 50 import java.lang.classfile.attribute.ExceptionsAttribute;
 51 import java.lang.classfile.attribute.InnerClassInfo;
 52 import java.lang.classfile.attribute.InnerClassesAttribute;
 53 import java.lang.classfile.attribute.LineNumberInfo;
 54 import java.lang.classfile.attribute.LineNumberTableAttribute;
 55 import java.lang.classfile.attribute.LocalVariableInfo;
 56 import java.lang.classfile.attribute.LocalVariableTableAttribute;
 57 import java.lang.classfile.attribute.LocalVariableTypeInfo;
 58 import java.lang.classfile.attribute.LocalVariableTypeTableAttribute;
 59 import java.lang.classfile.attribute.MethodParameterInfo;
 60 import java.lang.classfile.attribute.MethodParametersAttribute;
 61 import java.lang.classfile.attribute.ModuleAttribute;
 62 import java.lang.classfile.attribute.ModuleExportInfo;
 63 import java.lang.classfile.attribute.ModuleHashInfo;
 64 import java.lang.classfile.attribute.ModuleHashesAttribute;
 65 import java.lang.classfile.attribute.ModuleMainClassAttribute;
 66 import java.lang.classfile.attribute.ModuleOpenInfo;
 67 import java.lang.classfile.attribute.ModulePackagesAttribute;
 68 import java.lang.classfile.attribute.ModuleProvideInfo;
 69 import java.lang.classfile.attribute.ModuleRequireInfo;
 70 import java.lang.classfile.attribute.ModuleResolutionAttribute;
 71 import java.lang.classfile.attribute.ModuleTargetAttribute;
 72 import java.lang.classfile.attribute.NestHostAttribute;
 73 import java.lang.classfile.attribute.NestMembersAttribute;
 74 import java.lang.classfile.attribute.PermittedSubclassesAttribute;
 75 import java.lang.classfile.attribute.RecordAttribute;
 76 import java.lang.classfile.attribute.RecordComponentInfo;
 77 import java.lang.classfile.attribute.RuntimeInvisibleAnnotationsAttribute;
 78 import java.lang.classfile.attribute.RuntimeInvisibleParameterAnnotationsAttribute;
 79 import java.lang.classfile.attribute.RuntimeInvisibleTypeAnnotationsAttribute;
 80 import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute;
 81 import java.lang.classfile.attribute.RuntimeVisibleParameterAnnotationsAttribute;
 82 import java.lang.classfile.attribute.RuntimeVisibleTypeAnnotationsAttribute;
 83 import java.lang.classfile.attribute.SignatureAttribute;
 84 import java.lang.classfile.attribute.SourceDebugExtensionAttribute;
 85 import java.lang.classfile.attribute.SourceFileAttribute;
 86 import java.lang.classfile.attribute.SourceIDAttribute;
 87 import java.lang.classfile.attribute.StackMapTableAttribute;
 88 import java.lang.classfile.attribute.StackMapFrameInfo;
 89 import java.lang.classfile.attribute.SyntheticAttribute;
 90 import java.lang.classfile.constantpool.ConstantValueEntry;
 91 import java.lang.classfile.constantpool.ModuleEntry;
 92 import java.lang.classfile.constantpool.NameAndTypeEntry;
 93 import java.lang.classfile.constantpool.PackageEntry;
 94 import java.lang.classfile.constantpool.Utf8Entry;
 95 
 96 public abstract sealed class UnboundAttribute<T extends Attribute<T>>
 97         extends AbstractElement
 98         implements Attribute<T> {
 99     protected final AttributeMapper<T> mapper;
100 
101     public UnboundAttribute(AttributeMapper<T> mapper) {
102         this.mapper = mapper;
103     }
104 
105     @Override
106     public AttributeMapper<T> attributeMapper() {
107         return mapper;
108     }
109 
110     @Override
111     public String attributeName() {
112         return mapper.name();
113     }
114 
115     @Override
116     @SuppressWarnings("unchecked")
117     public void writeTo(BufWriter buf) {
118         mapper.writeAttribute(buf, (T) this);
119     }
120 
121     @Override
122     public void writeTo(DirectClassBuilder builder) {
123         builder.writeAttribute(this);
124     }
125 
126     @Override
127     public void writeTo(DirectCodeBuilder builder) {
128         builder.writeAttribute(this);
129     }
130 
131     @Override
132     public void writeTo(DirectMethodBuilder builder) {
133         builder.writeAttribute(this);
134     }
135 
136     @Override
137     public void writeTo(DirectFieldBuilder builder) {
138         builder.writeAttribute(this);
139     }
140 
141     @Override
142     public String toString() {
143         return String.format("Attribute[name=%s]", mapper.name());
144     }
145     public static final class UnboundConstantValueAttribute
146             extends UnboundAttribute<ConstantValueAttribute>
147             implements ConstantValueAttribute {
148 
149         private final ConstantValueEntry entry;
150 
151         public UnboundConstantValueAttribute(ConstantValueEntry entry) {
152             super(Attributes.CONSTANT_VALUE);
153             this.entry = entry;
154         }
155 
156         @Override
157         public ConstantValueEntry constant() {
158             return entry;
159         }
160 
161     }
162 
163     public static final class UnboundDeprecatedAttribute
164             extends UnboundAttribute<DeprecatedAttribute>
165             implements DeprecatedAttribute {
166         public UnboundDeprecatedAttribute() {
167             super(Attributes.DEPRECATED);
168         }
169     }
170 
171     public static final class UnboundSyntheticAttribute
172             extends UnboundAttribute<SyntheticAttribute>
173             implements SyntheticAttribute {
174         public UnboundSyntheticAttribute() {
175             super(Attributes.SYNTHETIC);
176         }
177     }
178 
179     public static final class UnboundSignatureAttribute
180             extends UnboundAttribute<SignatureAttribute>
181             implements SignatureAttribute {
182         private final Utf8Entry signature;
183 
184         public UnboundSignatureAttribute(Utf8Entry signature) {
185             super(Attributes.SIGNATURE);
186             this.signature = signature;
187         }
188 
189         @Override
190         public Utf8Entry signature() {
191             return signature;
192         }
193     }
194 
195     public static final class UnboundExceptionsAttribute
196             extends UnboundAttribute<ExceptionsAttribute>
197             implements ExceptionsAttribute {
198         private final List<ClassEntry> exceptions;
199 
200         public UnboundExceptionsAttribute(List<ClassEntry> exceptions) {
201             super(Attributes.EXCEPTIONS);
202             this.exceptions = List.copyOf(exceptions);
203         }
204 
205         @Override
206         public List<ClassEntry> exceptions() {
207             return exceptions;
208         }
209     }
210 
211     public static final class UnboundAnnotationDefaultAttribute
212             extends UnboundAttribute<AnnotationDefaultAttribute>
213             implements AnnotationDefaultAttribute {
214         private final AnnotationValue annotationDefault;
215 
216         public UnboundAnnotationDefaultAttribute(AnnotationValue annotationDefault) {
217             super(Attributes.ANNOTATION_DEFAULT);
218             this.annotationDefault = annotationDefault;
219         }
220 
221         @Override
222         public AnnotationValue defaultValue() {
223             return annotationDefault;
224         }
225     }
226 
227     public static final class UnboundSourceFileAttribute extends UnboundAttribute<SourceFileAttribute>
228             implements SourceFileAttribute {
229         private final Utf8Entry sourceFile;
230 
231         public UnboundSourceFileAttribute(Utf8Entry sourceFile) {
232             super(Attributes.SOURCE_FILE);
233             this.sourceFile = sourceFile;
234         }
235 
236         @Override
237         public Utf8Entry sourceFile() {
238             return sourceFile;
239         }
240 
241     }
242 
243     public static final class UnboundStackMapTableAttribute extends UnboundAttribute<StackMapTableAttribute>
244             implements StackMapTableAttribute {
245         private final List<StackMapFrameInfo> entries;
246 
247         public UnboundStackMapTableAttribute(List<StackMapFrameInfo> entries) {
248             super(Attributes.STACK_MAP_TABLE);
249             this.entries = List.copyOf(entries);
250         }
251 
252         @Override
253         public List<StackMapFrameInfo> entries() {
254             return entries;
255         }
256     }
257 
258     public static final class UnboundInnerClassesAttribute
259             extends UnboundAttribute<InnerClassesAttribute>
260             implements InnerClassesAttribute {
261         private final List<InnerClassInfo> innerClasses;
262 
263         public UnboundInnerClassesAttribute(List<InnerClassInfo> innerClasses) {
264             super(Attributes.INNER_CLASSES);
265             this.innerClasses = List.copyOf(innerClasses);
266         }
267 
268         @Override
269         public List<InnerClassInfo> classes() {
270             return innerClasses;
271         }
272     }
273 
274     public static final class UnboundRecordAttribute
275             extends UnboundAttribute<RecordAttribute>
276             implements RecordAttribute {
277         private final List<RecordComponentInfo> components;
278 
279         public UnboundRecordAttribute(List<RecordComponentInfo> components) {
280             super(Attributes.RECORD);
281             this.components = List.copyOf(components);
282         }
283 
284         @Override
285         public List<RecordComponentInfo> components() {
286             return components;
287         }
288     }
289 
290     public static final class UnboundEnclosingMethodAttribute
291             extends UnboundAttribute<EnclosingMethodAttribute>
292             implements EnclosingMethodAttribute {
293         private final ClassEntry classEntry;
294         private final NameAndTypeEntry method;
295 
296         public UnboundEnclosingMethodAttribute(ClassEntry classEntry, NameAndTypeEntry method) {
297             super(Attributes.ENCLOSING_METHOD);
298             this.classEntry = classEntry;
299             this.method = method;
300         }
301 
302         @Override
303         public ClassEntry enclosingClass() {
304             return classEntry;
305         }
306 
307         @Override
308         public Optional<NameAndTypeEntry> enclosingMethod() {
309             return Optional.ofNullable(method);
310         }
311     }
312 
313     public static final class UnboundMethodParametersAttribute
314             extends UnboundAttribute<MethodParametersAttribute>
315             implements MethodParametersAttribute {
316         private final List<MethodParameterInfo> parameters;
317 
318         public UnboundMethodParametersAttribute(List<MethodParameterInfo> parameters) {
319             super(Attributes.METHOD_PARAMETERS);
320             this.parameters = List.copyOf(parameters);
321         }
322 
323         @Override
324         public List<MethodParameterInfo> parameters() {
325             return parameters;
326         }
327     }
328 
329     public static final class UnboundModuleTargetAttribute
330             extends UnboundAttribute<ModuleTargetAttribute>
331             implements ModuleTargetAttribute {
332         final Utf8Entry moduleTarget;
333 
334         public UnboundModuleTargetAttribute(Utf8Entry moduleTarget) {
335             super(Attributes.MODULE_TARGET);
336             this.moduleTarget = moduleTarget;
337         }
338 
339         @Override
340         public Utf8Entry targetPlatform() {
341             return moduleTarget;
342         }
343     }
344 
345     public static final class UnboundModuleMainClassAttribute
346             extends UnboundAttribute<ModuleMainClassAttribute>
347             implements ModuleMainClassAttribute {
348         final ClassEntry mainClass;
349 
350         public UnboundModuleMainClassAttribute(ClassEntry mainClass) {
351             super(Attributes.MODULE_MAIN_CLASS);
352             this.mainClass = mainClass;
353         }
354 
355         @Override
356         public ClassEntry mainClass() {
357             return mainClass;
358         }
359     }
360 
361     public static final class UnboundModuleHashesAttribute
362             extends UnboundAttribute<ModuleHashesAttribute>
363             implements ModuleHashesAttribute {
364         private final Utf8Entry algorithm;
365         private final List<ModuleHashInfo> hashes;
366 
367         public UnboundModuleHashesAttribute(Utf8Entry algorithm, List<ModuleHashInfo> hashes) {
368             super(Attributes.MODULE_HASHES);
369             this.algorithm = algorithm;
370             this.hashes = List.copyOf(hashes);
371         }
372 
373         @Override
374         public Utf8Entry algorithm() {
375             return algorithm;
376         }
377 
378         @Override
379         public List<ModuleHashInfo> hashes() {
380             return hashes;
381         }
382     }
383 
384     public static final class UnboundModulePackagesAttribute
385             extends UnboundAttribute<ModulePackagesAttribute>
386             implements ModulePackagesAttribute {
387         private final Collection<PackageEntry> packages;
388 
389         public UnboundModulePackagesAttribute(Collection<PackageEntry> packages) {
390             super(Attributes.MODULE_PACKAGES);
391             this.packages = List.copyOf(packages);
392         }
393 
394         @Override
395         public List<PackageEntry> packages() {
396             return List.copyOf(packages);
397         }
398     }
399 
400     public static final class UnboundModuleResolutionAttribute
401             extends UnboundAttribute<ModuleResolutionAttribute>
402             implements ModuleResolutionAttribute {
403         private final int resolutionFlags;
404 
405         public UnboundModuleResolutionAttribute(int flags) {
406             super(Attributes.MODULE_RESOLUTION);
407             resolutionFlags = flags;
408         }
409 
410         @Override
411         public int resolutionFlags() {
412             return resolutionFlags;
413         }
414     }
415 
416     public static final class UnboundPermittedSubclassesAttribute
417             extends UnboundAttribute<PermittedSubclassesAttribute>
418             implements PermittedSubclassesAttribute {
419         private final List<ClassEntry> permittedSubclasses;
420 
421         public UnboundPermittedSubclassesAttribute(List<ClassEntry> permittedSubclasses) {
422             super(Attributes.PERMITTED_SUBCLASSES);
423             this.permittedSubclasses = List.copyOf(permittedSubclasses);
424         }
425 
426         @Override
427         public List<ClassEntry> permittedSubclasses() {
428             return permittedSubclasses;
429         }
430     }
431 
432     public static final class UnboundNestMembersAttribute
433             extends UnboundAttribute<NestMembersAttribute>
434             implements NestMembersAttribute {
435         private final List<ClassEntry> memberEntries;
436 
437         public UnboundNestMembersAttribute(List<ClassEntry> memberEntries) {
438             super(Attributes.NEST_MEMBERS);
439             this.memberEntries = List.copyOf(memberEntries);
440         }
441 
442         @Override
443         public List<ClassEntry> nestMembers() {
444             return memberEntries;
445         }
446     }
447 
448     public static final class UnboundNestHostAttribute
449             extends UnboundAttribute<NestHostAttribute>
450             implements NestHostAttribute {
451         private final ClassEntry hostEntry;
452 
453         public UnboundNestHostAttribute(ClassEntry hostEntry) {
454             super(Attributes.NEST_HOST);
455             this.hostEntry = hostEntry;
456         }
457 
458         @Override
459         public ClassEntry nestHost() {
460             return hostEntry;
461         }
462     }
463 
464     public static final class UnboundCompilationIDAttribute
465             extends UnboundAttribute<CompilationIDAttribute>
466             implements CompilationIDAttribute {
467         private final Utf8Entry idEntry;
468 
469         public UnboundCompilationIDAttribute(Utf8Entry idEntry) {
470             super(Attributes.COMPILATION_ID);
471             this.idEntry = idEntry;
472         }
473 
474         @Override
475         public Utf8Entry compilationId() {
476             return idEntry;
477         }
478     }
479 
480     public static final class UnboundSourceIDAttribute
481             extends UnboundAttribute<SourceIDAttribute>
482             implements SourceIDAttribute {
483         private final Utf8Entry idEntry;
484 
485         public UnboundSourceIDAttribute(Utf8Entry idEntry) {
486             super(Attributes.SOURCE_ID);
487             this.idEntry = idEntry;
488         }
489 
490         @Override
491         public Utf8Entry sourceId() {
492             return idEntry;
493         }
494     }
495 
496     public static final class UnboundSourceDebugExtensionAttribute
497         extends UnboundAttribute<SourceDebugExtensionAttribute>
498             implements SourceDebugExtensionAttribute {
499         private final byte[] contents;
500 
501         public UnboundSourceDebugExtensionAttribute(byte[] contents) {
502             super(Attributes.SOURCE_DEBUG_EXTENSION);
503             this.contents = contents;
504         }
505 
506         @Override
507         public byte[] contents() {
508             return contents;
509         }
510     }
511 
512     public static final class UnboundCharacterRangeTableAttribute
513         extends UnboundAttribute<CharacterRangeTableAttribute>
514             implements CharacterRangeTableAttribute {
515         private final List<CharacterRangeInfo> ranges;
516 
517         public UnboundCharacterRangeTableAttribute(List<CharacterRangeInfo> ranges) {
518             super(Attributes.CHARACTER_RANGE_TABLE);
519             this.ranges = List.copyOf(ranges);
520         }
521 
522         @Override
523         public List<CharacterRangeInfo> characterRangeTable() {
524             return ranges;
525         }
526     }
527 
528     public static final class UnboundLineNumberTableAttribute
529         extends UnboundAttribute<LineNumberTableAttribute>
530             implements LineNumberTableAttribute {
531         private final List<LineNumberInfo> lines;
532 
533         public UnboundLineNumberTableAttribute(List<LineNumberInfo> lines) {
534             super(Attributes.LINE_NUMBER_TABLE);
535             this.lines = List.copyOf(lines);
536         }
537 
538         @Override
539         public List<LineNumberInfo> lineNumbers() {
540             return lines;
541         }
542     }
543 
544     public static final class UnboundLocalVariableTableAttribute
545         extends UnboundAttribute<LocalVariableTableAttribute>
546             implements LocalVariableTableAttribute {
547         private final List<LocalVariableInfo> locals;
548 
549         public UnboundLocalVariableTableAttribute(List<LocalVariableInfo> locals) {
550             super(Attributes.LOCAL_VARIABLE_TABLE);
551             this.locals = List.copyOf(locals);
552         }
553 
554         @Override
555         public List<LocalVariableInfo> localVariables() {
556             return locals;
557         }
558     }
559 
560     public static final class UnboundLocalVariableTypeTableAttribute
561         extends UnboundAttribute<LocalVariableTypeTableAttribute>
562             implements LocalVariableTypeTableAttribute {
563         private final List<LocalVariableTypeInfo> locals;
564 
565         public UnboundLocalVariableTypeTableAttribute(List<LocalVariableTypeInfo> locals) {
566             super(Attributes.LOCAL_VARIABLE_TYPE_TABLE);
567             this.locals = List.copyOf(locals);
568         }
569 
570         @Override
571         public List<LocalVariableTypeInfo> localVariableTypes() {
572             return locals;
573         }
574     }
575 
576     public static final class UnboundRuntimeVisibleAnnotationsAttribute
577             extends UnboundAttribute<RuntimeVisibleAnnotationsAttribute>
578             implements RuntimeVisibleAnnotationsAttribute {
579         private final List<Annotation> elements;
580 
581         public UnboundRuntimeVisibleAnnotationsAttribute(List<Annotation> elements) {
582             super(Attributes.RUNTIME_VISIBLE_ANNOTATIONS);
583             this.elements = List.copyOf(elements);
584         }
585 
586         @Override
587         public List<Annotation> annotations() {
588             return elements;
589         }
590     }
591 
592     public static final class UnboundRuntimeInvisibleAnnotationsAttribute
593             extends UnboundAttribute<RuntimeInvisibleAnnotationsAttribute>
594             implements RuntimeInvisibleAnnotationsAttribute {
595         private final List<Annotation> elements;
596 
597         public UnboundRuntimeInvisibleAnnotationsAttribute(List<Annotation> elements) {
598             super(Attributes.RUNTIME_INVISIBLE_ANNOTATIONS);
599             this.elements = List.copyOf(elements);
600         }
601 
602         @Override
603         public List<Annotation> annotations() {
604             return elements;
605         }
606     }
607 
608     public static final class UnboundRuntimeVisibleParameterAnnotationsAttribute
609             extends UnboundAttribute<RuntimeVisibleParameterAnnotationsAttribute>
610             implements RuntimeVisibleParameterAnnotationsAttribute {
611         private final List<List<Annotation>> elements;
612 
613         public UnboundRuntimeVisibleParameterAnnotationsAttribute(List<List<Annotation>> elements) {
614             super(Attributes.RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS);
615             this.elements = List.copyOf(elements);
616         }
617 
618         @Override
619         public List<List<Annotation>> parameterAnnotations() {
620             return elements;
621         }
622     }
623 
624     public static final class UnboundRuntimeInvisibleParameterAnnotationsAttribute
625             extends UnboundAttribute<RuntimeInvisibleParameterAnnotationsAttribute>
626             implements RuntimeInvisibleParameterAnnotationsAttribute {
627         private final List<List<Annotation>> elements;
628 
629         public UnboundRuntimeInvisibleParameterAnnotationsAttribute(List<List<Annotation>> elements) {
630             super(Attributes.RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS);
631             this.elements = List.copyOf(elements);
632         }
633 
634         @Override
635         public List<List<Annotation>> parameterAnnotations() {
636             return elements;
637         }
638     }
639 
640     public static final class UnboundRuntimeVisibleTypeAnnotationsAttribute
641             extends UnboundAttribute<RuntimeVisibleTypeAnnotationsAttribute>
642             implements RuntimeVisibleTypeAnnotationsAttribute {
643         private final List<TypeAnnotation> elements;
644 
645         public UnboundRuntimeVisibleTypeAnnotationsAttribute(List<TypeAnnotation> elements) {
646             super(Attributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS);
647             this.elements = List.copyOf(elements);
648         }
649 
650         @Override
651         public List<TypeAnnotation> annotations() {
652             return elements;
653         }
654     }
655 
656     public static final class UnboundRuntimeInvisibleTypeAnnotationsAttribute
657             extends UnboundAttribute<RuntimeInvisibleTypeAnnotationsAttribute>
658             implements RuntimeInvisibleTypeAnnotationsAttribute {
659         private final List<TypeAnnotation> elements;
660 
661         public UnboundRuntimeInvisibleTypeAnnotationsAttribute(List<TypeAnnotation> elements) {
662             super(Attributes.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS);
663             this.elements = List.copyOf(elements);
664         }
665 
666         @Override
667         public List<TypeAnnotation> annotations() {
668             return elements;
669         }
670     }
671 
672     public record UnboundCharacterRangeInfo(int startPc, int endPc,
673                                             int characterRangeStart,
674                                             int characterRangeEnd,
675                                             int flags)
676             implements CharacterRangeInfo { }
677 
678     public record UnboundInnerClassInfo(ClassEntry innerClass,
679                                         Optional<ClassEntry> outerClass,
680                                         Optional<Utf8Entry> innerName,
681                                         int flagsMask)
682             implements InnerClassInfo {}
683 
684     public record UnboundLineNumberInfo(int startPc, int lineNumber)
685             implements LineNumberInfo { }
686 
687     public record UnboundLocalVariableInfo(int startPc, int length,
688                                            Utf8Entry name,
689                                            Utf8Entry type,
690                                            int slot)
691             implements LocalVariableInfo { }
692 
693     public record UnboundLocalVariableTypeInfo(int startPc, int length,
694                                                Utf8Entry name,
695                                                Utf8Entry signature,
696                                                int slot)
697             implements LocalVariableTypeInfo { }
698 
699     public record UnboundMethodParameterInfo(Optional<Utf8Entry> name, int flagsMask)
700             implements MethodParameterInfo {}
701 
702     public record UnboundModuleExportInfo(PackageEntry exportedPackage,
703                                           int exportsFlagsMask,
704                                           List<ModuleEntry> exportsTo)
705             implements ModuleExportInfo {
706         public UnboundModuleExportInfo(PackageEntry exportedPackage, int exportsFlagsMask,
707                                        List<ModuleEntry> exportsTo) {
708             this.exportedPackage = exportedPackage;
709             this.exportsFlagsMask = exportsFlagsMask;
710             this.exportsTo = List.copyOf(exportsTo);
711         }
712     }
713 
714     public record UnboundModuleHashInfo(ModuleEntry moduleName,
715                                         byte[] hash) implements ModuleHashInfo { }
716 
717     public record UnboundModuleOpenInfo(PackageEntry openedPackage, int opensFlagsMask,
718                                         List<ModuleEntry> opensTo)
719             implements ModuleOpenInfo {
720         public UnboundModuleOpenInfo(PackageEntry openedPackage, int opensFlagsMask,
721                                      List<ModuleEntry> opensTo) {
722             this.openedPackage = openedPackage;
723             this.opensFlagsMask = opensFlagsMask;
724             this.opensTo = List.copyOf(opensTo);
725         }
726     }
727 
728     public record UnboundModuleProvideInfo(ClassEntry provides,
729                                            List<ClassEntry> providesWith)
730             implements ModuleProvideInfo {
731         public UnboundModuleProvideInfo(ClassEntry provides, List<ClassEntry> providesWith) {
732             this.provides = provides;
733             this.providesWith = List.copyOf(providesWith);
734         }
735     }
736 
737     public record UnboundModuleRequiresInfo(ModuleEntry requires, int requiresFlagsMask,
738                                             Optional<Utf8Entry> requiresVersion)
739             implements ModuleRequireInfo {}
740 
741     public record UnboundRecordComponentInfo(Utf8Entry name,
742                                              Utf8Entry descriptor,
743                                              List<Attribute<?>> attributes)
744             implements RecordComponentInfo {
745         public UnboundRecordComponentInfo(Utf8Entry name, Utf8Entry descriptor, List<Attribute<?>> attributes) {
746             this.name = name;
747             this.descriptor = descriptor;
748             this.attributes = List.copyOf(attributes);
749         }
750     }
751 
752     public record UnboundTypeAnnotation(TargetInfo targetInfo,
753                                         List<TypePathComponent> targetPath,
754                                         Utf8Entry className,
755                                         List<AnnotationElement> elements) implements TypeAnnotation {
756 
757         public UnboundTypeAnnotation(TargetInfo targetInfo, List<TypePathComponent> targetPath,
758                                      Utf8Entry className, List<AnnotationElement> elements) {
759             this.targetInfo = targetInfo;
760             this.targetPath = List.copyOf(targetPath);
761             this.className = className;
762             this.elements = List.copyOf(elements);
763         }
764 
765         private int labelToBci(LabelContext lr, Label label) {
766             //helper method to avoid NPE
767             if (lr == null) throw new IllegalArgumentException("Illegal targetType '%s' in TypeAnnotation outside of Code attribute".formatted(targetInfo.targetType()));
768             return lr.labelToBci(label);
769         }
770 
771         @Override
772         public void writeTo(BufWriter buf) {
773             LabelContext lr = ((BufWriterImpl) buf).labelContext();
774             // target_type
775             buf.writeU1(targetInfo.targetType().targetTypeValue());
776 
777             // target_info
778             switch (targetInfo) {
779                 case TypeParameterTarget tpt -> buf.writeU1(tpt.typeParameterIndex());
780                 case SupertypeTarget st -> buf.writeU2(st.supertypeIndex());
781                 case TypeParameterBoundTarget tpbt -> {
782                     buf.writeU1(tpbt.typeParameterIndex());
783                     buf.writeU1(tpbt.boundIndex());
784                 }
785                 case EmptyTarget et -> {
786                     // nothing to write
787                 }
788                 case FormalParameterTarget fpt -> buf.writeU1(fpt.formalParameterIndex());
789                 case ThrowsTarget tt -> buf.writeU2(tt.throwsTargetIndex());
790                 case LocalVarTarget lvt -> {
791                     buf.writeU2(lvt.table().size());
792                     for (var e : lvt.table()) {
793                         int startPc = labelToBci(lr, e.startLabel());
794                         buf.writeU2(startPc);
795                         buf.writeU2(labelToBci(lr, e.endLabel()) - startPc);
796                         buf.writeU2(e.index());
797                     }
798                 }
799                 case CatchTarget ct -> buf.writeU2(ct.exceptionTableIndex());
800                 case OffsetTarget ot -> buf.writeU2(labelToBci(lr, ot.target()));
801                 case TypeArgumentTarget tat -> {
802                     buf.writeU2(labelToBci(lr, tat.target()));
803                     buf.writeU1(tat.typeArgumentIndex());
804                 }
805             }
806 
807             // target_path
808             buf.writeU1(targetPath().size());
809             for (TypePathComponent component : targetPath()) {
810                 buf.writeU1(component.typePathKind().tag());
811                 buf.writeU1(component.typeArgumentIndex());
812             }
813 
814             // type_index
815             buf.writeIndex(className);
816 
817             // element_value_pairs
818             buf.writeU2(elements.size());
819             for (AnnotationElement pair : elements()) {
820                 buf.writeIndex(pair.name());
821                 pair.value().writeTo(buf);
822             }
823         }
824     }
825 
826     public record TypePathComponentImpl(TypeAnnotation.TypePathComponent.Kind typePathKind, int typeArgumentIndex)
827             implements TypeAnnotation.TypePathComponent {}
828 
829     public static final class UnboundModuleAttribute extends UnboundAttribute<ModuleAttribute> implements ModuleAttribute {
830         private final ModuleEntry moduleName;
831         private final int moduleFlags;
832         private final Utf8Entry moduleVersion;
833         private final List<ModuleRequireInfo> requires;
834         private final List<ModuleExportInfo> exports;
835         private final List<ModuleOpenInfo> opens;
836         private final List<ClassEntry> uses;
837         private final List<ModuleProvideInfo> provides;
838 
839         public UnboundModuleAttribute(ModuleEntry moduleName,
840                                       int moduleFlags,
841                                       Utf8Entry moduleVersion,
842                                       Collection<ModuleRequireInfo> requires,
843                                       Collection<ModuleExportInfo> exports,
844                                       Collection<ModuleOpenInfo> opens,
845                                       Collection<ClassEntry> uses,
846                                       Collection<ModuleProvideInfo> provides)
847         {
848             super(Attributes.MODULE);
849             this.moduleName = moduleName;
850             this.moduleFlags = moduleFlags;
851             this.moduleVersion = moduleVersion;
852             this.requires = List.copyOf(requires);
853             this.exports = List.copyOf(exports);
854             this.opens = List.copyOf(opens);
855             this.uses = List.copyOf(uses);
856             this.provides = List.copyOf(provides);
857         }
858 
859         @Override
860         public ModuleEntry moduleName() {
861             return moduleName;
862         }
863 
864         @Override
865         public int moduleFlagsMask() {
866             return moduleFlags;
867         }
868 
869         @Override
870         public Optional<Utf8Entry> moduleVersion() {
871             return Optional.ofNullable(moduleVersion);
872         }
873 
874         @Override
875         public List<ModuleRequireInfo> requires() {
876             return requires;
877         }
878 
879         @Override
880         public List<ModuleExportInfo> exports() {
881             return exports;
882         }
883 
884         @Override
885         public List<ModuleOpenInfo> opens() {
886             return opens;
887         }
888 
889         @Override
890         public List<ClassEntry> uses() {
891             return uses;
892         }
893 
894         @Override
895         public List<ModuleProvideInfo> provides() {
896             return provides;
897         }
898     }
899 
900     public static abstract non-sealed class AdHocAttribute<T extends Attribute<T>>
901             extends UnboundAttribute<T> {
902 
903         public AdHocAttribute(AttributeMapper<T> mapper) {
904             super(mapper);
905         }
906 
907         public abstract void writeBody(BufWriter b);
908 
909         @Override
910         public void writeTo(BufWriter b) {
911             b.writeIndex(b.constantPool().utf8Entry(mapper.name()));
912             b.writeInt(0);
913             int start = b.size();
914             writeBody(b);
915             int written = b.size() - start;
916             b.patchInt(start - 4, 4, written);
917         }
918     }
919 
920     public static final class EmptyBootstrapAttribute
921             extends UnboundAttribute<BootstrapMethodsAttribute>
922             implements BootstrapMethodsAttribute {
923         public EmptyBootstrapAttribute() {
924             super(Attributes.BOOTSTRAP_METHODS);
925         }
926 
927         @Override
928         public int bootstrapMethodsSize() {
929             return 0;
930         }
931 
932         @Override
933         public List<BootstrapMethodEntry> bootstrapMethods() {
934             return List.of();
935         }
936     }
937 }