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