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
26 package jdk.internal.classfile.impl;
27
28 import java.lang.classfile.*;
29 import java.lang.classfile.attribute.*;
30 import java.lang.classfile.constantpool.*;
31 import java.util.ArrayList;
32 import java.util.Collections;
33 import java.util.List;
34 import java.util.Objects;
35 import java.util.Optional;
36 import java.util.function.Function;
37
38 import jdk.internal.access.SharedSecrets;
39
40 import static java.lang.classfile.Attributes.*;
41
42 public abstract sealed class BoundAttribute<T extends Attribute<T>>
43 extends AbstractElement
44 implements Attribute<T>, Util.Writable {
45
46 static final int NAME_AND_LENGTH_PREFIX = 6;
47 private final AttributeMapper<T> mapper;
48 final ClassReaderImpl classReader;
49 final int payloadStart;
50 Utf8Entry name;
51
52 BoundAttribute(ClassReader classReader, AttributeMapper<T> mapper, int payloadStart) {
53 this.mapper = mapper;
54 this.classReader = (ClassReaderImpl)classReader;
55 this.payloadStart = payloadStart;
56 }
57
58 public int payloadLen() {
59 return classReader.readInt(payloadStart - 4);
60 }
61
62 @Override
63 public Utf8Entry attributeName() {
64 if (name == null) {
65 name = classReader.readEntry(payloadStart - 6, Utf8Entry.class);
66 }
67 return name;
68 }
69
70 @Override
71 public AttributeMapper<T> attributeMapper() {
72 return mapper;
73 }
74
75 public byte[] contents() {
76 return classReader.readBytes(payloadStart, payloadLen());
77 }
78
79 @Override
80 public void writeTo(DirectClassBuilder builder) {
81 builder.writeAttribute(this);
82 }
83
84 @Override
85 public void writeTo(DirectCodeBuilder builder) {
86 builder.writeAttribute(this);
87 }
88
89 @Override
90 public void writeTo(DirectMethodBuilder builder) {
91 builder.writeAttribute(this);
92 }
93
94 @Override
95 public void writeTo(DirectFieldBuilder builder) {
96 builder.writeAttribute(this);
97 }
98
99 @Override
100 @SuppressWarnings("unchecked")
101 public void writeTo(BufWriterImpl buf) {
102 if (!buf.canWriteDirect(classReader))
103 attributeMapper().writeAttribute(buf, (T) this);
104 else
105 classReader.copyBytesTo(buf, payloadStart - NAME_AND_LENGTH_PREFIX, payloadLen() + NAME_AND_LENGTH_PREFIX);
106 }
107
108 public ConstantPool constantPool() {
109 return classReader;
110 }
111
112 @Override
113 public String toString() {
114 return String.format("Attribute[name=%s]", mapper.name());
115 }
116
117 <E extends PoolEntry> List<E> readEntryList(int p, Class<E> type) {
118 int cnt = classReader.readU2(p);
119 p += 2;
120 var entries = new Object[cnt];
121 int end = p + (cnt * 2);
122 for (int i = 0; p < end; i++, p += 2) {
123 entries[i] = classReader.readEntry(p, type);
124 }
125 return SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(entries);
126 }
127
128 public static List<Attribute<?>> readAttributes(AttributedElement enclosing, ClassReader reader, int pos,
129 Function<Utf8Entry, AttributeMapper<?>> customAttributes) {
130 int size = reader.readU2(pos);
131 var filled = new ArrayList<Attribute<?>>(size);
132 int p = pos + 2;
133 int cfLen = reader.classfileLength();
134 for (int i = 0; i < size; ++i) {
135 Utf8Entry name = reader.readEntry(p, Utf8Entry.class);
136 int len = reader.readInt(p + 2);
137 p += 6;
138 if (len < 0 || len > cfLen - p) {
139 throw new IllegalArgumentException("attribute " + name.stringValue() + " too big to handle");
140 }
141
142 var mapper = standardAttribute(name);
143 if (mapper == null) {
144 mapper = customAttributes.apply(name);
145 }
146 if (mapper != null) {
147 filled.add(Objects.requireNonNull(mapper.readAttribute(enclosing, reader, p)));
148 } else {
149 AttributeMapper<UnknownAttribute> fakeMapper = new AttributeMapper<>() {
150 @Override
151 public String name() {
152 return name.stringValue();
153 }
154
155 @Override
156 public UnknownAttribute readAttribute(AttributedElement enclosing, ClassReader cf, int pos) {
157 // Will never get called
158 throw new UnsupportedOperationException();
159 }
160
161 @Override
162 public void writeAttribute(BufWriter buf, UnknownAttribute attr) {
163 buf.writeIndex(name);
164 var cont = attr.contents();
165 buf.writeInt(cont.length);
166 buf.writeBytes(cont);
167 }
168
169 @Override
170 public boolean allowMultiple() {
171 return true;
172 }
173
174 @Override
175 public AttributeMapper.AttributeStability stability() {
176 return AttributeStability.UNKNOWN;
177 }
178 };
179 filled.add(new BoundUnknownAttribute(reader, fakeMapper, p));
180 }
181 p += len;
182 }
183 return Collections.unmodifiableList(filled);
184 }
185
186 public static final class BoundUnknownAttribute extends BoundAttribute<UnknownAttribute>
187 implements UnknownAttribute {
188 public BoundUnknownAttribute(ClassReader cf, AttributeMapper<UnknownAttribute> mapper, int pos) {
189 super(cf, mapper, pos);
190 }
191 }
192
193 public static final class BoundStackMapTableAttribute
194 extends BoundAttribute<StackMapTableAttribute>
195 implements StackMapTableAttribute {
196 final MethodModel method;
197 final LabelContext ctx;
198 List<StackMapFrameInfo> entries = null;
199
200 public BoundStackMapTableAttribute(CodeImpl code, ClassReader cf, AttributeMapper<StackMapTableAttribute> mapper, int pos) {
201 super(cf, mapper, pos);
202 method = code.parent().orElseThrow();
203 ctx = code;
204 }
205
206 @Override
207 public List<StackMapFrameInfo> entries() {
208 if (entries == null) {
209 entries = new StackMapDecoder(classReader, payloadStart, ctx, StackMapDecoder.initFrameLocals(method),
210 StackMapDecoder.initFrameUnsets(method)).entries();
211 }
212 return entries;
213 }
214
215 @Override
216 public void writeTo(BufWriterImpl buf) {
217 if (buf.canWriteDirect(classReader) && buf.labelsMatch(ctx)) {
218 classReader.copyBytesTo(buf, payloadStart - NAME_AND_LENGTH_PREFIX, payloadLen() + NAME_AND_LENGTH_PREFIX);
219 } else {
220 attributeMapper().writeAttribute(buf, this);
221 }
222 }
223 }
224
225 public static final class BoundSyntheticAttribute extends BoundAttribute<SyntheticAttribute>
226 implements SyntheticAttribute {
227 public BoundSyntheticAttribute(ClassReader cf, AttributeMapper<SyntheticAttribute> mapper, int pos) {
228 super(cf, mapper, pos);
229 }
230 }
231
232 public static final class BoundLineNumberTableAttribute
233 extends BoundAttribute<LineNumberTableAttribute>
234 implements LineNumberTableAttribute {
235 private List<LineNumberInfo> lineNumbers = null;
236
237 public BoundLineNumberTableAttribute(ClassReader cf, AttributeMapper<LineNumberTableAttribute> mapper, int pos) {
238 super(cf, mapper, pos);
239 }
240
241 @Override
242 public List<LineNumberInfo> lineNumbers() {
243 if (lineNumbers == null) {
244 int nLn = classReader.readU2(payloadStart);
245 LineNumberInfo[] elements = new LineNumberInfo[nLn];
246 int p = payloadStart + 2;
247 int pEnd = p + (nLn * 4);
248 for (int i = 0; p < pEnd; p += 4, i++) {
249 int startPc = classReader.readU2(p);
250 int lineNumber = classReader.readU2(p + 2);
251 elements[i] = LineNumberInfo.of(startPc, lineNumber);
252 }
253 lineNumbers = List.of(elements);
254 }
255 return lineNumbers;
256 }
257 }
258
259 public static final class BoundCharacterRangeTableAttribute extends BoundAttribute<CharacterRangeTableAttribute> implements CharacterRangeTableAttribute {
260 private List<CharacterRangeInfo> characterRangeTable = null;
261
262 public BoundCharacterRangeTableAttribute(ClassReader cf, AttributeMapper<CharacterRangeTableAttribute> mapper, int pos) {
263 super(cf, mapper, pos);
264 }
265
266 @Override
267 public List<CharacterRangeInfo> characterRangeTable() {
268 if (characterRangeTable == null) {
269 int nLn = classReader.readU2(payloadStart);
270 CharacterRangeInfo[] elements = new CharacterRangeInfo[nLn];
271 int p = payloadStart + 2;
272 int pEnd = p + (nLn * 14);
273 for (int i = 0; p < pEnd; p += 14, i++) {
274 int startPc = classReader.readU2(p);
275 int endPc = classReader.readU2(p + 2);
276 int characterRangeStart = classReader.readInt(p + 4);
277 int characterRangeEnd = classReader.readInt(p + 8);
278 int flags = classReader.readU2(p + 12);
279 elements[i] = CharacterRangeInfo.of(startPc, endPc, characterRangeStart, characterRangeEnd, flags);
280 }
281 characterRangeTable = List.of(elements);
282 }
283 return characterRangeTable;
284 }
285 }
286
287 public static final class BoundLocalVariableTableAttribute
288 extends BoundAttribute<LocalVariableTableAttribute>
289 implements LocalVariableTableAttribute {
290 private final CodeImpl codeAttribute;
291 private List<LocalVariableInfo> localVars = null;
292
293 public BoundLocalVariableTableAttribute(AttributedElement enclosing, ClassReader cf, AttributeMapper<LocalVariableTableAttribute> mapper, int pos) {
294 super(cf, mapper, pos);
295 if (enclosing instanceof CodeImpl ci) {
296 this.codeAttribute = ci;
297 } else {
298 throw new IllegalArgumentException("Invalid LocalVariableTable attribute location");
299 }
300 }
301
302 @Override
303 public List<LocalVariableInfo> localVariables() {
304 if (localVars == null) {
305 int cnt = classReader.readU2(payloadStart);
306 BoundLocalVariable[] elements = new BoundLocalVariable[cnt];
307 int p = payloadStart + 2;
308 int pEnd = p + (cnt * 10);
309 for (int i = 0; p < pEnd; p += 10, i++) {
310 elements[i] = new BoundLocalVariable(codeAttribute, p);
311 }
312 localVars = List.of(elements);
313 }
314 return localVars;
315 }
316 }
317
318 public static final class BoundLocalVariableTypeTableAttribute
319 extends BoundAttribute<LocalVariableTypeTableAttribute>
320 implements LocalVariableTypeTableAttribute {
321 private final CodeImpl codeAttribute;
322 private List<LocalVariableTypeInfo> localVars = null;
323
324 public BoundLocalVariableTypeTableAttribute(AttributedElement enclosing, ClassReader cf, AttributeMapper<LocalVariableTypeTableAttribute> mapper, int pos) {
325 super(cf, mapper, pos);
326 if (enclosing instanceof CodeImpl ci) {
327 this.codeAttribute = ci;
328 } else {
329 throw new IllegalArgumentException("Invalid LocalVariableTypeTable attribute location");
330 }
331 }
332
333 @Override
334 public List<LocalVariableTypeInfo> localVariableTypes() {
335 if (localVars == null) {
336 final int cnt = classReader.readU2(payloadStart);
337 BoundLocalVariableType[] elements = new BoundLocalVariableType[cnt];
338 int p = payloadStart + 2;
339 int pEnd = p + (cnt * 10);
340 for (int i = 0; p < pEnd; p += 10, i++) {
341 elements[i] = new BoundLocalVariableType(codeAttribute, p);
342 }
343 localVars = List.of(elements);
344 }
345 return localVars;
346 }
347 }
348
349 public static final class BoundMethodParametersAttribute extends BoundAttribute<MethodParametersAttribute>
350 implements MethodParametersAttribute {
351 private List<MethodParameterInfo> parameters = null;
352
353 public BoundMethodParametersAttribute(ClassReader cf, AttributeMapper<MethodParametersAttribute> mapper, int pos) {
354 super(cf, mapper, pos);
355 }
356
357 @Override
358 public List<MethodParameterInfo> parameters() {
359 if (parameters == null) {
360 final int cnt = classReader.readU1(payloadStart);
361 MethodParameterInfo[] elements = new MethodParameterInfo[cnt];
362 int p = payloadStart + 1;
363 int pEnd = p + (cnt * 4);
364 for (int i = 0; p < pEnd; p += 4, i++) {
365 Utf8Entry name = classReader.readEntryOrNull(p, Utf8Entry.class);
366 int accessFlags = classReader.readU2(p + 2);
367 elements[i] = MethodParameterInfo.of(Optional.ofNullable(name), accessFlags);
368 }
369 parameters = List.of(elements);
370 }
371 return parameters;
372 }
373 }
374
375 public static final class BoundModuleHashesAttribute extends BoundAttribute<ModuleHashesAttribute>
376 implements ModuleHashesAttribute {
377 private List<ModuleHashInfo> hashes = null;
378
379 public BoundModuleHashesAttribute(ClassReader cf, AttributeMapper<ModuleHashesAttribute> mapper, int pos) {
380 super(cf, mapper, pos);
381 }
382
383 @Override
384 public Utf8Entry algorithm() {
385 return classReader.readEntry(payloadStart, Utf8Entry.class);
386 }
387
388 @Override
389 public List<ModuleHashInfo> hashes() {
390 if (hashes == null) {
391 final int cnt = classReader.readU2(payloadStart + 2);
392 ModuleHashInfo[] elements = new ModuleHashInfo[cnt];
393 int p = payloadStart + 4;
394 //System.err.printf("%5d: ModuleHashesAttr alg = %s, cnt = %d%n", pos, algorithm(), cnt);
395 for (int i = 0; i < cnt; ++i) {
396 ModuleEntry module = classReader.readEntry(p, ModuleEntry.class);
397 int hashLength = classReader.readU2(p + 2);
398 //System.err.printf("%5d: [%d] module = %s, hashLength = %d%n", p, i, module, hashLength);
399 p += 4;
400 elements[i] = ModuleHashInfo.of(module, classReader.readBytes(p, hashLength));
401 p += hashLength;
402 }
403 hashes = List.of(elements);
404 }
405 return hashes;
406 }
407 }
408
409 public static final class BoundRecordAttribute extends BoundAttribute<RecordAttribute>
410 implements RecordAttribute {
411 private List<RecordComponentInfo> components = null;
412
413 public BoundRecordAttribute(ClassReader cf, AttributeMapper<RecordAttribute> mapper, int pos) {
414 super(cf, mapper, pos);
415 }
416
417 @Override
418 public List<RecordComponentInfo> components() {
419 if (components == null) {
420 final int cnt = classReader.readU2(payloadStart);
421 RecordComponentInfo[] elements = new RecordComponentInfo[cnt];
422 int p = payloadStart + 2;
423 for (int i = 0; i < cnt; i++) {
424 elements[i] = new BoundRecordComponentInfo(classReader, p);
425 p = classReader.skipAttributeHolder(p + 4);
426 }
427 components = List.of(elements);
428 }
429 return components;
430 }
431 }
432
433 public static final class BoundDeprecatedAttribute extends BoundAttribute<DeprecatedAttribute>
434 implements DeprecatedAttribute {
435 public BoundDeprecatedAttribute(ClassReader cf, AttributeMapper<DeprecatedAttribute> mapper, int pos) {
436 super(cf, mapper, pos);
437 }
438 }
439
440 public static final class BoundSignatureAttribute extends BoundAttribute<SignatureAttribute>
441 implements SignatureAttribute {
442 public BoundSignatureAttribute(ClassReader cf, AttributeMapper<SignatureAttribute> mapper, int pos) {
443 super(cf, mapper, pos);
444 }
445
446 @Override
447 public Utf8Entry signature() {
448 return classReader.readEntry(payloadStart, Utf8Entry.class);
449 }
450 }
451
452 public static final class BoundSourceFileAttribute extends BoundAttribute<SourceFileAttribute>
453 implements SourceFileAttribute {
454 public BoundSourceFileAttribute(ClassReader cf, AttributeMapper<SourceFileAttribute> mapper, int pos) {
455 super(cf, mapper, pos);
456 }
457
458 @Override
459 public Utf8Entry sourceFile() {
460 return classReader.readEntry(payloadStart, Utf8Entry.class);
461 }
462
463 }
464
465 public static final class BoundModuleMainClassAttribute extends BoundAttribute<ModuleMainClassAttribute> implements ModuleMainClassAttribute {
466 public BoundModuleMainClassAttribute(ClassReader cf, AttributeMapper<ModuleMainClassAttribute> mapper, int pos) {
467 super(cf, mapper, pos);
468 }
469
470 @Override
471 public ClassEntry mainClass() {
472 return classReader.readEntry(payloadStart, ClassEntry.class);
473 }
474 }
475
476 public static final class BoundNestHostAttribute extends BoundAttribute<NestHostAttribute>
477 implements NestHostAttribute {
478 public BoundNestHostAttribute(ClassReader cf, AttributeMapper<NestHostAttribute> mapper, int pos) {
479 super(cf, mapper, pos);
480 }
481
482 @Override
483 public ClassEntry nestHost() {
484 return classReader.readEntry(payloadStart, ClassEntry.class);
485 }
486 }
487
488 public static final class BoundSourceDebugExtensionAttribute extends BoundAttribute<SourceDebugExtensionAttribute>
489 implements SourceDebugExtensionAttribute {
490 public BoundSourceDebugExtensionAttribute(ClassReader cf, AttributeMapper<SourceDebugExtensionAttribute> mapper, int pos) {
491 super(cf, mapper, pos);
492 }
493 }
494
495 public static final class BoundConstantValueAttribute extends BoundAttribute<ConstantValueAttribute>
496 implements ConstantValueAttribute {
497 public BoundConstantValueAttribute(ClassReader cf, AttributeMapper<ConstantValueAttribute> mapper, int pos) {
498 super(cf, mapper, pos);
499 }
500
501 @Override
502 public ConstantValueEntry constant() {
503 return classReader.readEntry(payloadStart, ConstantValueEntry.class);
504 }
505
506 }
507
508 public static final class BoundModuleTargetAttribute extends BoundAttribute<ModuleTargetAttribute>
509 implements ModuleTargetAttribute {
510 public BoundModuleTargetAttribute(ClassReader cf, AttributeMapper<ModuleTargetAttribute> mapper, int pos) {
511 super(cf, mapper, pos);
512 }
513
514 @Override
515 public Utf8Entry targetPlatform() {
516 return classReader.readEntry(payloadStart, Utf8Entry.class);
517 }
518 }
519
520 public static final class BoundCompilationIDAttribute extends BoundAttribute<CompilationIDAttribute>
521 implements CompilationIDAttribute {
522 public BoundCompilationIDAttribute(ClassReader cf, AttributeMapper<CompilationIDAttribute> mapper, int pos) {
523 super(cf, mapper, pos);
524 }
525
526 @Override
527 public Utf8Entry compilationId() {
528 return classReader.readEntry(payloadStart, Utf8Entry.class);
529 }
530 }
531
532 public static final class BoundSourceIDAttribute extends BoundAttribute<SourceIDAttribute>
533 implements SourceIDAttribute {
534 public BoundSourceIDAttribute(ClassReader cf, AttributeMapper<SourceIDAttribute> mapper, int pos) {
535 super(cf, mapper, pos);
536 }
537
538 @Override
539 public Utf8Entry sourceId() {
540 return classReader.readEntry(payloadStart, Utf8Entry.class);
541 }
542 }
543
544 public static final class BoundModuleResolutionAttribute extends BoundAttribute<ModuleResolutionAttribute>
545 implements ModuleResolutionAttribute {
546 public BoundModuleResolutionAttribute(ClassReader cf, AttributeMapper<ModuleResolutionAttribute> mapper, int pos) {
547 super(cf, mapper, pos);
548 }
549
550 @Override
551 public int resolutionFlags() {
552 return classReader.readU2(payloadStart);
553 }
554 }
555
556 public static final class BoundExceptionsAttribute extends BoundAttribute<ExceptionsAttribute>
557 implements ExceptionsAttribute {
558 private List<ClassEntry> exceptions = null;
559
560 public BoundExceptionsAttribute(ClassReader cf, AttributeMapper<ExceptionsAttribute> mapper, int pos) {
561 super(cf, mapper, pos);
562 }
563
564 @Override
565 public List<ClassEntry> exceptions() {
566 if (exceptions == null) {
567 exceptions = readEntryList(payloadStart, ClassEntry.class);
568 }
569 return exceptions;
570 }
571 }
572
573 public static final class BoundModuleAttribute extends BoundAttribute<ModuleAttribute>
574 implements ModuleAttribute {
575 private List<ModuleRequireInfo> requires = null;
576 private List<ModuleExportInfo> exports = null;
577 private List<ModuleOpenInfo> opens = null;
578 private List<ClassEntry> uses = null;
579 private List<ModuleProvideInfo> provides = null;
580
581 public BoundModuleAttribute(ClassReader cf, AttributeMapper<ModuleAttribute> mapper, int pos) {
582 super(cf, mapper, pos);
583 }
584
585 @Override
586 public ModuleEntry moduleName() {
587 return classReader.readEntry(payloadStart, ModuleEntry.class);
588 }
589
590 @Override
591 public int moduleFlagsMask() {
592 return classReader.readU2(payloadStart + 2);
593 }
594
595 @Override
596 public Optional<Utf8Entry> moduleVersion() {
597 return Optional.ofNullable(classReader.readEntryOrNull(payloadStart + 4, Utf8Entry.class));
598 }
599
600 @Override
601 public List<ModuleRequireInfo> requires() {
602 if (requires == null) {
603 structure();
604 }
605 return requires;
606 }
607
608 @Override
609 public List<ModuleExportInfo> exports() {
610 if (exports == null) {
611 structure();
612 }
613 return exports;
614 }
615
616 @Override
617 public List<ModuleOpenInfo> opens() {
618 if (opens == null) {
619 structure();
620 }
621 return opens;
622 }
623
624 @Override
625 public List<ClassEntry> uses() {
626 if (uses == null) {
627 structure();
628 }
629 return uses;
630 }
631
632 @Override
633 public List<ModuleProvideInfo> provides() {
634 if (provides == null) {
635 structure();
636 }
637 return provides;
638 }
639
640 private void structure() {
641 int p = payloadStart + 8;
642
643 {
644 int cnt = classReader.readU2(payloadStart + 6);
645 ModuleRequireInfo[] elements = new ModuleRequireInfo[cnt];
646 int end = p + (cnt * 6);
647 for (int i = 0; p < end; p += 6, i++) {
648 elements[i] = ModuleRequireInfo.of(classReader.readEntry(p, ModuleEntry.class),
649 classReader.readU2(p + 2),
650 classReader.readEntryOrNull(p + 4, Utf8Entry.class));
651 }
652 requires = List.of(elements);
653 }
654
655 {
656 int cnt = classReader.readU2(p);
657 p += 2;
658 ModuleExportInfo[] elements = new ModuleExportInfo[cnt];
659 for (int i = 0; i < cnt; i++) {
660 PackageEntry pe = classReader.readEntry(p, PackageEntry.class);
661 int exportFlags = classReader.readU2(p + 2);
662 p += 4;
663 List<ModuleEntry> exportsTo = readEntryList(p, ModuleEntry.class);
664 p += 2 + exportsTo.size() * 2;
665 elements[i] = ModuleExportInfo.of(pe, exportFlags, exportsTo);
666 }
667 exports = List.of(elements);
668 }
669
670 {
671 int cnt = classReader.readU2(p);
672 p += 2;
673 ModuleOpenInfo[] elements = new ModuleOpenInfo[cnt];
674 for (int i = 0; i < cnt; i++) {
675 PackageEntry po = classReader.readEntry(p, PackageEntry.class);
676 int opensFlags = classReader.readU2(p + 2);
677 p += 4;
678 List<ModuleEntry> opensTo = readEntryList(p, ModuleEntry.class);
679 p += 2 + opensTo.size() * 2;
680 elements[i] = ModuleOpenInfo.of(po, opensFlags, opensTo);
681 }
682 opens = List.of(elements);
683 }
684
685 {
686 uses = readEntryList(p, ClassEntry.class);
687 p += 2 + uses.size() * 2;
688 int cnt = classReader.readU2(p);
689 p += 2;
690 ModuleProvideInfo[] elements = new ModuleProvideInfo[cnt];
691 provides = new ArrayList<>(cnt);
692 for (int i = 0; i < cnt; i++) {
693 ClassEntry c = classReader.readEntry(p, ClassEntry.class);
694 p += 2;
695 List<ClassEntry> providesWith = readEntryList(p, ClassEntry.class);
696 p += 2 + providesWith.size() * 2;
697 elements[i] = ModuleProvideInfo.of(c, providesWith);
698 }
699 provides = List.of(elements);
700 }
701 }
702 }
703
704 public static final class BoundModulePackagesAttribute extends BoundAttribute<ModulePackagesAttribute>
705 implements ModulePackagesAttribute {
706 private List<PackageEntry> packages = null;
707
708 public BoundModulePackagesAttribute(ClassReader cf, AttributeMapper<ModulePackagesAttribute> mapper, int pos) {
709 super(cf, mapper, pos);
710 }
711
712 @Override
713 public List<PackageEntry> packages() {
714 if (packages == null) {
715 packages = readEntryList(payloadStart, PackageEntry.class);
716 }
717 return packages;
718 }
719 }
720
721 public static final class BoundNestMembersAttribute extends BoundAttribute<NestMembersAttribute>
722 implements NestMembersAttribute {
723
724 private List<ClassEntry> members = null;
725
726 public BoundNestMembersAttribute(ClassReader cf, AttributeMapper<NestMembersAttribute> mapper, int pos) {
727 super(cf, mapper, pos);
728 }
729
730 @Override
731 public List<ClassEntry> nestMembers() {
732 if (members == null) {
733 members = readEntryList(payloadStart, ClassEntry.class);
734 }
735 return members;
736 }
737 }
738
739 public static final class BoundBootstrapMethodsAttribute extends BoundAttribute<BootstrapMethodsAttribute>
740 implements BootstrapMethodsAttribute {
741
742 private List<BootstrapMethodEntry> bootstraps = null;
743 private final int size;
744
745 public BoundBootstrapMethodsAttribute(ClassReader reader, AttributeMapper<BootstrapMethodsAttribute> mapper, int pos) {
746 super(reader, mapper, pos);
747 size = classReader.readU2(pos);
748 }
749
750 @Override
751 public int bootstrapMethodsSize() {
752 return size;
753 }
754
755 @Override
756 public List<BootstrapMethodEntry> bootstrapMethods() {
757 if (bootstraps == null) {
758 BootstrapMethodEntry[] bs = new BootstrapMethodEntry[size];
759 int p = payloadStart + 2;
760 for (int i = 0; i < size; ++i) {
761 final var handle = classReader.readEntry(p, AbstractPoolEntry.MethodHandleEntryImpl.class);
762 final List<LoadableConstantEntry> args = readEntryList(p + 2, LoadableConstantEntry.class);
763 p += 4 + args.size() * 2;
764 int hash = BootstrapMethodEntryImpl.computeHashCode(handle, args);
765 bs[i] = new BootstrapMethodEntryImpl(classReader, i, hash, handle, args);
766 }
767 bootstraps = List.of(bs);
768 }
769 return bootstraps;
770 }
771 }
772
773 public static final class BoundInnerClassesAttribute extends BoundAttribute<InnerClassesAttribute>
774 implements InnerClassesAttribute {
775 private List<InnerClassInfo> classes;
776
777 public BoundInnerClassesAttribute(ClassReader cf, AttributeMapper<InnerClassesAttribute> mapper, int pos) {
778 super(cf, mapper, pos);
779 }
780
781 @Override
782 public List<InnerClassInfo> classes() {
783 if (classes == null) {
784 final int cnt = classReader.readU2(payloadStart);
785 int p = payloadStart + 2;
786 InnerClassInfo[] elements = new InnerClassInfo[cnt];
787 for (int i = 0; i < cnt; i++) {
788 ClassEntry innerClass = classReader.readEntry(p, ClassEntry.class);
789 var outerClass = classReader.readEntryOrNull(p + 2, ClassEntry.class);
790 var innerName = classReader.readEntryOrNull(p + 4, Utf8Entry.class);
791 int flags = classReader.readU2(p + 6);
792 p += 8;
793 elements[i] = InnerClassInfo.of(innerClass, Optional.ofNullable(outerClass), Optional.ofNullable(innerName), flags);
794 }
795 classes = List.of(elements);
796 }
797 return classes;
798 }
799 }
800
801 public static final class BoundEnclosingMethodAttribute extends BoundAttribute<EnclosingMethodAttribute>
802 implements EnclosingMethodAttribute {
803 public BoundEnclosingMethodAttribute(ClassReader cf, AttributeMapper<EnclosingMethodAttribute> mapper, int pos) {
804 super(cf, mapper, pos);
805 }
806
807 @Override
808 public ClassEntry enclosingClass() {
809 return classReader.readEntry(payloadStart, ClassEntry.class);
810 }
811
812 @Override
813 public Optional<NameAndTypeEntry> enclosingMethod() {
814 return Optional.ofNullable(classReader.readEntryOrNull(payloadStart + 2, NameAndTypeEntry.class));
815 }
816 }
817
818 public static final class BoundAnnotationDefaultAttr
819 extends BoundAttribute<AnnotationDefaultAttribute>
820 implements AnnotationDefaultAttribute {
821 private AnnotationValue annotationValue;
822
823 public BoundAnnotationDefaultAttr(ClassReader cf, AttributeMapper<AnnotationDefaultAttribute> mapper, int pos) {
824 super(cf, mapper, pos);
825 }
826
827 @Override
828 public AnnotationValue defaultValue() {
829 if (annotationValue == null)
830 annotationValue = AnnotationReader.readElementValue(classReader, payloadStart);
831 return annotationValue;
832 }
833 }
834
835 public static final class BoundRuntimeVisibleTypeAnnotationsAttribute extends BoundAttribute<RuntimeVisibleTypeAnnotationsAttribute>
836 implements RuntimeVisibleTypeAnnotationsAttribute {
837
838 private final LabelContext labelContext;
839
840 public BoundRuntimeVisibleTypeAnnotationsAttribute(AttributedElement enclosing, ClassReader cf, AttributeMapper<RuntimeVisibleTypeAnnotationsAttribute> mapper, int pos) {
841 super(cf, mapper, pos);
842 this.labelContext = (enclosing instanceof LabelContext lc) ? lc : null;
843 }
844
845 @Override
846 public List<TypeAnnotation> annotations() {
847 return AnnotationReader.readTypeAnnotations(classReader, payloadStart, labelContext);
848 }
849 }
850
851 public static final class BoundRuntimeInvisibleTypeAnnotationsAttribute
852 extends BoundAttribute<RuntimeInvisibleTypeAnnotationsAttribute>
853 implements RuntimeInvisibleTypeAnnotationsAttribute {
854 public BoundRuntimeInvisibleTypeAnnotationsAttribute(AttributedElement enclosing, ClassReader cf, AttributeMapper<RuntimeInvisibleTypeAnnotationsAttribute> mapper, int pos) {
855 super(cf, mapper, pos);
856 this.labelContext = (enclosing instanceof LabelContext lc) ? lc : null;
857 }
858
859 private final LabelContext labelContext;
860
861 @Override
862 public List<TypeAnnotation> annotations() {
863 return AnnotationReader.readTypeAnnotations(classReader, payloadStart, labelContext);
864 }
865 }
866
867 public static final class BoundRuntimeVisibleParameterAnnotationsAttribute
868 extends BoundAttribute<RuntimeVisibleParameterAnnotationsAttribute>
869 implements RuntimeVisibleParameterAnnotationsAttribute {
870
871 public BoundRuntimeVisibleParameterAnnotationsAttribute(ClassReader cf, AttributeMapper<RuntimeVisibleParameterAnnotationsAttribute> mapper, int pos) {
872 super(cf, mapper, pos);
873 }
874
875 @Override
876 public List<List<Annotation>> parameterAnnotations() {
877 return AnnotationReader.readParameterAnnotations(classReader, payloadStart);
878 }
879 }
880
881 public static final class BoundRuntimeInvisibleParameterAnnotationsAttribute
882 extends BoundAttribute<RuntimeInvisibleParameterAnnotationsAttribute>
883 implements RuntimeInvisibleParameterAnnotationsAttribute {
884
885 public BoundRuntimeInvisibleParameterAnnotationsAttribute(ClassReader cf, AttributeMapper<RuntimeInvisibleParameterAnnotationsAttribute> mapper, int pos) {
886 super(cf, mapper, pos);
887 }
888
889 @Override
890 public List<List<Annotation>> parameterAnnotations() {
891 return AnnotationReader.readParameterAnnotations(classReader, payloadStart);
892 }
893 }
894
895 public static final class BoundRuntimeInvisibleAnnotationsAttribute
896 extends BoundAttribute<RuntimeInvisibleAnnotationsAttribute>
897 implements RuntimeInvisibleAnnotationsAttribute {
898 private List<Annotation> inflated;
899
900 public BoundRuntimeInvisibleAnnotationsAttribute(ClassReader cf,
901 int payloadStart) {
902 super(cf, Attributes.runtimeInvisibleAnnotations(), payloadStart);
903 }
904
905 @Override
906 public List<Annotation> annotations() {
907 if (inflated == null)
908 inflated = AnnotationReader.readAnnotations(classReader, payloadStart);
909 return inflated;
910 }
911 }
912
913 public static final class BoundRuntimeVisibleAnnotationsAttribute
914 extends BoundAttribute<RuntimeVisibleAnnotationsAttribute>
915 implements RuntimeVisibleAnnotationsAttribute {
916 private List<Annotation> inflated;
917
918 public BoundRuntimeVisibleAnnotationsAttribute(ClassReader cf,
919 int payloadStart) {
920 super(cf, Attributes.runtimeVisibleAnnotations(), payloadStart);
921 }
922
923 @Override
924 public List<Annotation> annotations() {
925 if (inflated == null)
926 inflated = AnnotationReader.readAnnotations(classReader, payloadStart);
927 return inflated;
928 }
929 }
930
931 public static final class BoundPermittedSubclassesAttribute extends BoundAttribute<PermittedSubclassesAttribute>
932 implements PermittedSubclassesAttribute {
933 private List<ClassEntry> permittedSubclasses = null;
934
935 public BoundPermittedSubclassesAttribute(ClassReader cf, AttributeMapper<PermittedSubclassesAttribute> mapper, int pos) {
936 super(cf, mapper, pos);
937 }
938
939 @Override
940 public List<ClassEntry> permittedSubclasses() {
941 if (permittedSubclasses == null) {
942 permittedSubclasses = readEntryList(payloadStart, ClassEntry.class);
943 }
944 return permittedSubclasses;
945 }
946 }
947
948 public static final class BoundLoadableDescriptorsAttribute extends BoundAttribute<LoadableDescriptorsAttribute>
949 implements LoadableDescriptorsAttribute {
950 private List<Utf8Entry> loadableDescriptors = null;
951
952 public BoundLoadableDescriptorsAttribute(ClassReader cf, AttributeMapper<LoadableDescriptorsAttribute> mapper, int pos) {
953 super(cf, mapper, pos);
954 }
955
956 @Override
957 public List<Utf8Entry> loadableDescriptors() {
958 if (loadableDescriptors == null) {
959 loadableDescriptors = readEntryList(payloadStart, Utf8Entry.class);
960 }
961 return loadableDescriptors;
962 }
963 }
964
965 public abstract static sealed class BoundCodeAttribute
966 extends BoundAttribute<CodeAttribute>
967 implements CodeAttribute
968 permits CodeImpl {
969 protected final int codeStart;
970 protected final int codeLength;
971 protected final int codeEnd;
972 protected final int attributePos;
973 protected final int exceptionHandlerPos;
974 protected final int exceptionHandlerCnt;
975 protected final MethodModel enclosingMethod;
976
977 public BoundCodeAttribute(AttributedElement enclosing,
978 ClassReader reader,
979 AttributeMapper<CodeAttribute> mapper,
980 int payloadStart) {
981 super(reader, mapper, payloadStart);
982 this.codeLength = classReader.readInt(payloadStart + 4);
983 this.enclosingMethod = (MethodModel) enclosing;
984 this.codeStart = payloadStart + 8;
985 this.codeEnd = codeStart + codeLength;
986 this.exceptionHandlerPos = codeEnd;
987 this.exceptionHandlerCnt = classReader.readU2(exceptionHandlerPos);
988 this.attributePos = exceptionHandlerPos + 2 + exceptionHandlerCnt * 8;
989 }
990
991 // CodeAttribute
992
993 @Override
994 public int maxStack() {
995 return classReader.readU2(payloadStart);
996 }
997
998 @Override
999 public int maxLocals() {
1000 return classReader.readU2(payloadStart + 2);
1001 }
1002
1003 @Override
1004 public int codeLength() {
1005 return codeLength;
1006 }
1007
1008 @Override
1009 public byte[] codeArray() {
1010 return classReader.readBytes(payloadStart + 8, codeLength());
1011 }
1012 }
1013
1014 /**
1015 * {@return the attribute mapper for a standard attribute}
1016 *
1017 * @param name the name of the attribute to find
1018 */
1019 public static AttributeMapper<?> standardAttribute(Utf8Entry name) {
1020 // critical bootstrap path, so no lambdas nor method handles here
1021 return switch (name.hashCode()) {
1022 case 0x46699ff2 ->
1023 name.equalsString(NAME_ANNOTATION_DEFAULT) ? annotationDefault() : null;
1024 case 0x5208e184 ->
1025 name.equalsString(NAME_BOOTSTRAP_METHODS) ? bootstrapMethods() : null;
1026 case 0xcb60907a ->
1027 name.equalsString(NAME_CHARACTER_RANGE_TABLE) ? characterRangeTable() : null;
1028 case 0x4020220d ->
1029 name.equalsString(NAME_CODE) ? code() : null;
1030 case 0xc20dd1fe ->
1031 name.equalsString(NAME_COMPILATION_ID) ? compilationId() : null;
1032 case 0xcab1940d ->
1033 name.equalsString(NAME_CONSTANT_VALUE) ? constantValue() : null;
1034 case 0x558641d3 ->
1035 name.equalsString(NAME_DEPRECATED) ? deprecated() : null;
1036 case 0x51d443cd ->
1037 name.equalsString(NAME_ENCLOSING_METHOD) ? enclosingMethod() : null;
1038 case 0x687c1624 ->
1039 name.equalsString(NAME_EXCEPTIONS) ? exceptions() : null;
1040 case 0x7adb2910 ->
1041 name.equalsString(NAME_INNER_CLASSES) ? innerClasses() : null;
1042 case 0x653f0551 ->
1043 name.equalsString(NAME_LINE_NUMBER_TABLE) ? lineNumberTable() : null;
1044 case 0x5f348b64 ->
1045 name.equalsString(NAME_LOADABLE_DESCRIPTORS) ? loadableDescriptors() : null;
1046 case 0x64c75927 ->
1047 name.equalsString(NAME_LOCAL_VARIABLE_TABLE) ? localVariableTable() : null;
1048 case 0x6697f98d ->
1049 name.equalsString(NAME_LOCAL_VARIABLE_TYPE_TABLE) ? localVariableTypeTable() : null;
1050 case 0xdbb0cdcb ->
1051 name.equalsString(NAME_METHOD_PARAMETERS) ? methodParameters() : null;
1052 case 0xc9b0928c ->
1053 name.equalsString(NAME_MODULE) ? module() : null;
1054 case 0x41cd27e8 ->
1055 name.equalsString(NAME_MODULE_HASHES) ? moduleHashes() : null;
1056 case 0x7deb0a13 ->
1057 name.equalsString(NAME_MODULE_MAIN_CLASS) ? moduleMainClass() : null;
1058 case 0x6706ff99 ->
1059 name.equalsString(NAME_MODULE_PACKAGES) ? modulePackages() : null;
1060 case 0x60272858 ->
1061 name.equalsString(NAME_MODULE_RESOLUTION) ? moduleResolution() : null;
1062 case 0x5646d73d ->
1063 name.equalsString(NAME_MODULE_TARGET) ? moduleTarget() : null;
1064 case 0x50336c40 ->
1065 name.equalsString(NAME_NEST_HOST) ? nestHost() : null;
1066 case 0x4735ab81 ->
1067 name.equalsString(NAME_NEST_MEMBERS) ? nestMembers() : null;
1068 case 0x7100d9fe ->
1069 name.equalsString(NAME_PERMITTED_SUBCLASSES) ? permittedSubclasses() : null;
1070 case 0xd1ab5871 ->
1071 name.equalsString(NAME_RECORD) ? record() : null;
1072 case 0x7588550f ->
1073 name.equalsString(NAME_RUNTIME_INVISIBLE_ANNOTATIONS) ? runtimeInvisibleAnnotations() : null;
1074 case 0xcc74da30 ->
1075 name.equalsString(NAME_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS) ? runtimeInvisibleParameterAnnotations() : null;
1076 case 0xf67697f5 ->
1077 name.equalsString(NAME_RUNTIME_INVISIBLE_TYPE_ANNOTATIONS) ? runtimeInvisibleTypeAnnotations() : null;
1078 case 0xe0837d2a ->
1079 name.equalsString(NAME_RUNTIME_VISIBLE_ANNOTATIONS) ? runtimeVisibleAnnotations() : null;
1080 case 0xc945a075 ->
1081 name.equalsString(NAME_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS) ? runtimeVisibleParameterAnnotations() : null;
1082 case 0x611a3a90 ->
1083 name.equalsString(NAME_RUNTIME_VISIBLE_TYPE_ANNOTATIONS) ? runtimeVisibleTypeAnnotations() : null;
1084 case 0xf76fb898 ->
1085 name.equalsString(NAME_SIGNATURE) ? signature() : null;
1086 case 0x6b41b047 ->
1087 name.equalsString(NAME_SOURCE_DEBUG_EXTENSION) ? sourceDebugExtension() : null;
1088 case 0x748c2857 ->
1089 name.equalsString(NAME_SOURCE_FILE) ? sourceFile() : null;
1090 case 0x6bf13a96 ->
1091 name.equalsString(NAME_SOURCE_ID) ? sourceId() : null;
1092 case 0xfa85ee5a ->
1093 name.equalsString(NAME_STACK_MAP_TABLE) ? stackMapTable() : null;
1094 case 0xf2670725 ->
1095 name.equalsString(NAME_SYNTHETIC) ? synthetic() : null;
1096 default -> null;
1097 };
1098 }
1099 }