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.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23 package helpers;
24
25 import java.lang.constant.ClassDesc;
26 import java.util.HashMap;
27 import java.util.List;
28 import java.util.Random;
29 import java.lang.classfile.*;
30 import java.lang.classfile.attribute.*;
31 import java.lang.classfile.constantpool.*;
32 import java.lang.classfile.instruction.*;
33 import java.lang.constant.ModuleDesc;
34 import java.lang.constant.PackageDesc;
35 import jdk.internal.classfile.components.CodeStackTracker;
36
37 class RebuildingTransformation {
38
39 static private Random pathSwitch = new Random(1234);
40
41 static byte[] transform(ClassModel clm) {
42 return ClassFile.of(ClassFile.StackMapsOption.DROP_STACK_MAPS).build(clm.thisClass().asSymbol(), clb -> {
43 for (var cle : clm) {
44 switch (cle) {
45 case AccessFlags af -> clb.withFlags(af.flagsMask());
46 case Superclass sc -> clb.withSuperclass(sc.superclassEntry().asSymbol());
47 case Interfaces i -> clb.withInterfaceSymbols(i.interfaces().stream().map(ClassEntry::asSymbol).toArray(ClassDesc[]::new));
48 case ClassFileVersion v -> clb.withVersion(v.majorVersion(), v.minorVersion());
49 case FieldModel fm ->
50 clb.withField(fm.fieldName().stringValue(), fm.fieldTypeSymbol(), fb -> {
51 for (var fe : fm) {
52 switch (fe) {
53 case AccessFlags af -> fb.withFlags(af.flagsMask());
54 case ConstantValueAttribute a -> fb.with(ConstantValueAttribute.of(a.constant().constantValue()));
55 case DeprecatedAttribute a -> fb.with(DeprecatedAttribute.of());
56 case RuntimeInvisibleAnnotationsAttribute a -> fb.with(RuntimeInvisibleAnnotationsAttribute.of(transformAnnotations(a.annotations())));
57 case RuntimeInvisibleTypeAnnotationsAttribute a -> fb.with(RuntimeInvisibleTypeAnnotationsAttribute.of(transformTypeAnnotations(a.annotations(), null, null)));
58 case RuntimeVisibleAnnotationsAttribute a -> fb.with(RuntimeVisibleAnnotationsAttribute.of(transformAnnotations(a.annotations())));
59 case RuntimeVisibleTypeAnnotationsAttribute a -> fb.with(RuntimeVisibleTypeAnnotationsAttribute.of(transformTypeAnnotations(a.annotations(), null, null)));
60 case SignatureAttribute a -> fb.with(SignatureAttribute.of(Signature.parseFrom(a.asTypeSignature().signatureString())));
61 case SyntheticAttribute a -> fb.with(SyntheticAttribute.of());
62 case CustomAttribute<?> a -> throw new AssertionError("Unexpected custom attribute: " + a.attributeName().stringValue());
63 case UnknownAttribute a -> throw new AssertionError("Unexpected unknown attribute: " + a.attributeName().stringValue());
64 }
65 }
66 });
67 case MethodModel mm -> {
68 clb.withMethod(mm.methodName().stringValue(), mm.methodTypeSymbol(), mm.flags().flagsMask(), mb -> {
69 for (var me : mm) {
70 switch (me) {
71 case AccessFlags af -> mb.withFlags(af.flagsMask());
72 case CodeModel com -> mb.withCode(cob1 ->
73 cob1.transforming(CodeStackTracker.of(), cob2 ->
74 // second pass transforms unbound to unbound instructions
75 cob2.transforming(new CodeRebuildingTransform(), cob3 ->
76 // first pass transforms bound to unbound instructions
77 cob3.transforming(new CodeRebuildingTransform(), cob4 -> {
78 com.forEach(cob4::with);
79 com.findAttribute(Attributes.stackMapTable()).ifPresent(cob4::with);
80 }))));
81 case AnnotationDefaultAttribute a -> mb.with(AnnotationDefaultAttribute.of(transformAnnotationValue(a.defaultValue())));
82 case DeprecatedAttribute a -> mb.with(DeprecatedAttribute.of());
83 case ExceptionsAttribute a -> mb.with(ExceptionsAttribute.ofSymbols(a.exceptions().stream().map(ClassEntry::asSymbol).toArray(ClassDesc[]::new)));
84 case MethodParametersAttribute a -> mb.with(MethodParametersAttribute.of(a.parameters().stream().map(mp ->
85 MethodParameterInfo.ofParameter(mp.name().map(Utf8Entry::stringValue), mp.flagsMask())).toArray(MethodParameterInfo[]::new)));
86 case RuntimeInvisibleAnnotationsAttribute a -> mb.with(RuntimeInvisibleAnnotationsAttribute.of(transformAnnotations(a.annotations())));
87 case RuntimeInvisibleParameterAnnotationsAttribute a -> mb.with(RuntimeInvisibleParameterAnnotationsAttribute.of(a.parameterAnnotations().stream().map(pas -> List.of(transformAnnotations(pas))).toList()));
88 case RuntimeInvisibleTypeAnnotationsAttribute a -> mb.with(RuntimeInvisibleTypeAnnotationsAttribute.of(transformTypeAnnotations(a.annotations(), null, null)));
89 case RuntimeVisibleAnnotationsAttribute a -> mb.with(RuntimeVisibleAnnotationsAttribute.of(transformAnnotations(a.annotations())));
90 case RuntimeVisibleParameterAnnotationsAttribute a -> mb.with(RuntimeVisibleParameterAnnotationsAttribute.of(a.parameterAnnotations().stream().map(pas -> List.of(transformAnnotations(pas))).toList()));
91 case RuntimeVisibleTypeAnnotationsAttribute a -> mb.with(RuntimeVisibleTypeAnnotationsAttribute.of(transformTypeAnnotations(a.annotations(), null, null)));
92 case SignatureAttribute a -> mb.with(SignatureAttribute.of(MethodSignature.parseFrom(a.asMethodSignature().signatureString())));
93 case SyntheticAttribute a -> mb.with(SyntheticAttribute.of());
94 case CustomAttribute<?> a -> throw new AssertionError("Unexpected custom attribute: " + a.attributeName().stringValue());
95 case UnknownAttribute a -> throw new AssertionError("Unexpected unknown attribute: " + a.attributeName().stringValue());
96 }
97 }
98 });
99 }
100 case CompilationIDAttribute a -> clb.with(CompilationIDAttribute.of(a.compilationId().stringValue()));
101 case DeprecatedAttribute a -> clb.with(DeprecatedAttribute.of());
102 case EnclosingMethodAttribute a -> clb.with(EnclosingMethodAttribute.of(a.enclosingClass().asSymbol(), a.enclosingMethodName().map(Utf8Entry::stringValue), a.enclosingMethodTypeSymbol()));
103 case InnerClassesAttribute a -> clb.with(InnerClassesAttribute.of(a.classes().stream().map(ici -> InnerClassInfo.of(
104 ici.innerClass().asSymbol(),
105 ici.outerClass().map(ClassEntry::asSymbol),
106 ici.innerName().map(Utf8Entry::stringValue),
107 ici.flagsMask())).toArray(InnerClassInfo[]::new)));
108 case LoadableDescriptorsAttribute a -> clb.with(LoadableDescriptorsAttribute.of(a.loadableDescriptors()));
109 case ModuleAttribute a -> clb.with(ModuleAttribute.of(a.moduleName().asSymbol(), mob -> {
110 mob.moduleFlags(a.moduleFlagsMask());
111 a.moduleVersion().ifPresent(v -> mob.moduleVersion(v.stringValue()));
112 for (var req : a.requires()) mob.requires(req.requires().asSymbol(), req.requiresFlagsMask(), req.requiresVersion().map(Utf8Entry::stringValue).orElse(null));
113 for (var exp : a.exports()) mob.exports(exp.exportedPackage().asSymbol(), exp.exportsFlagsMask(), exp.exportsTo().stream().map(ModuleEntry::asSymbol).toArray(ModuleDesc[]::new));
114 for (var opn : a.opens()) mob.opens(opn.openedPackage().asSymbol(), opn.opensFlagsMask(), opn.opensTo().stream().map(ModuleEntry::asSymbol).toArray(ModuleDesc[]::new));
115 for (var use : a.uses()) mob.uses(use.asSymbol());
116 for (var prov : a.provides()) mob.provides(prov.provides().asSymbol(), prov.providesWith().stream().map(ClassEntry::asSymbol).toArray(ClassDesc[]::new));
117 }));
118 case ModuleHashesAttribute a -> clb.with(ModuleHashesAttribute.of(a.algorithm().stringValue(),
119 a.hashes().stream().map(mh -> ModuleHashInfo.of(mh.moduleName().asSymbol(), mh.hash())).toArray(ModuleHashInfo[]::new)));
120 case ModuleMainClassAttribute a -> clb.with(ModuleMainClassAttribute.of(a.mainClass().asSymbol()));
121 case ModulePackagesAttribute a -> clb.with(ModulePackagesAttribute.ofNames(a.packages().stream().map(PackageEntry::asSymbol).toArray(PackageDesc[]::new)));
122 case ModuleResolutionAttribute a -> clb.with(ModuleResolutionAttribute.of(a.resolutionFlags()));
123 case ModuleTargetAttribute a -> clb.with(ModuleTargetAttribute.of(a.targetPlatform().stringValue()));
124 case NestHostAttribute a -> clb.with(NestHostAttribute.of(a.nestHost().asSymbol()));
125 case NestMembersAttribute a -> clb.with(NestMembersAttribute.ofSymbols(a.nestMembers().stream().map(ClassEntry::asSymbol).toArray(ClassDesc[]::new)));
126 case PermittedSubclassesAttribute a -> clb.with(PermittedSubclassesAttribute.ofSymbols(a.permittedSubclasses().stream().map(ClassEntry::asSymbol).toArray(ClassDesc[]::new)));
127 case RecordAttribute a -> clb.with(RecordAttribute.of(a.components().stream().map(rci ->
128 RecordComponentInfo.of(rci.name().stringValue(), rci.descriptorSymbol(), rci.attributes().stream().mapMulti((rca, rcac) -> {
129 switch(rca) {
130 case RuntimeInvisibleAnnotationsAttribute riaa -> rcac.accept(RuntimeInvisibleAnnotationsAttribute.of(transformAnnotations(riaa.annotations())));
131 case RuntimeInvisibleTypeAnnotationsAttribute ritaa -> rcac.accept(RuntimeInvisibleTypeAnnotationsAttribute.of(transformTypeAnnotations(ritaa.annotations(), null, null)));
132 case RuntimeVisibleAnnotationsAttribute rvaa -> rcac.accept(RuntimeVisibleAnnotationsAttribute.of(transformAnnotations(rvaa.annotations())));
133 case RuntimeVisibleTypeAnnotationsAttribute rvtaa -> rcac.accept(RuntimeVisibleTypeAnnotationsAttribute.of(transformTypeAnnotations(rvtaa.annotations(), null, null)));
134 case SignatureAttribute sa -> rcac.accept(SignatureAttribute.of(Signature.parseFrom(sa.asTypeSignature().signatureString())));
135 default -> throw new AssertionError("Unexpected record component attribute: " + rca.attributeName().stringValue());
136 }}).toArray(Attribute[]::new))).toArray(RecordComponentInfo[]::new)));
137 case RuntimeInvisibleAnnotationsAttribute a -> clb.with(RuntimeInvisibleAnnotationsAttribute.of(transformAnnotations(a.annotations())));
138 case RuntimeInvisibleTypeAnnotationsAttribute a -> clb.with(RuntimeInvisibleTypeAnnotationsAttribute.of(transformTypeAnnotations(a.annotations(), null, null)));
139 case RuntimeVisibleAnnotationsAttribute a -> clb.with(RuntimeVisibleAnnotationsAttribute.of(transformAnnotations(a.annotations())));
140 case RuntimeVisibleTypeAnnotationsAttribute a -> clb.with(RuntimeVisibleTypeAnnotationsAttribute.of(transformTypeAnnotations(a.annotations(), null, null)));
141 case SignatureAttribute a -> clb.with(SignatureAttribute.of(ClassSignature.parseFrom(a.asClassSignature().signatureString())));
142 case SourceDebugExtensionAttribute a -> clb.with(SourceDebugExtensionAttribute.of(a.contents()));
143 case SourceFileAttribute a -> clb.with(SourceFileAttribute.of(a.sourceFile().stringValue()));
144 case SourceIDAttribute a -> clb.with(SourceIDAttribute.of(a.sourceId().stringValue()));
145 case SyntheticAttribute a -> clb.with(SyntheticAttribute.of());
146 case CustomAttribute<?> a -> throw new AssertionError("Unexpected custom attribute: " + a.attributeName().stringValue());
147 case UnknownAttribute a -> throw new AssertionError("Unexpected unknown attribute: " + a.attributeName().stringValue());
148 }
149 }
150 });
151 }
152
153 static Annotation[] transformAnnotations(List<Annotation> annotations) {
154 return annotations.stream().map(a -> transformAnnotation(a)).toArray(Annotation[]::new);
155 }
156
157 static Annotation transformAnnotation(Annotation a) {
158 return Annotation.of(a.classSymbol(), a.elements().stream().map(ae -> AnnotationElement.of(ae.name().stringValue(), transformAnnotationValue(ae.value()))).toArray(AnnotationElement[]::new));
159 }
160
161 static AnnotationValue transformAnnotationValue(AnnotationValue av) {
162 return switch (av) {
163 case AnnotationValue.OfAnnotation oa -> AnnotationValue.ofAnnotation(transformAnnotation(oa.annotation()));
164 case AnnotationValue.OfArray oa -> AnnotationValue.ofArray(oa.values().stream().map(v -> transformAnnotationValue(v)).toArray(AnnotationValue[]::new));
165 case AnnotationValue.OfString v -> AnnotationValue.of(v.stringValue());
166 case AnnotationValue.OfDouble v -> AnnotationValue.of(v.doubleValue());
167 case AnnotationValue.OfFloat v -> AnnotationValue.of(v.floatValue());
168 case AnnotationValue.OfLong v -> AnnotationValue.of(v.longValue());
169 case AnnotationValue.OfInt v -> AnnotationValue.of(v.intValue());
170 case AnnotationValue.OfShort v -> AnnotationValue.of(v.shortValue());
171 case AnnotationValue.OfChar v -> AnnotationValue.of(v.charValue());
172 case AnnotationValue.OfByte v -> AnnotationValue.of(v.byteValue());
173 case AnnotationValue.OfBoolean v -> AnnotationValue.of(v.booleanValue());
174 case AnnotationValue.OfClass oc -> AnnotationValue.of(oc.classSymbol());
175 case AnnotationValue.OfEnum oe -> AnnotationValue.ofEnum(oe.classSymbol(), oe.constantName().stringValue());
176 };
177 }
178
179 static TypeAnnotation[] transformTypeAnnotations(List<TypeAnnotation> annotations, CodeBuilder cob, HashMap<Label, Label> labels) {
180 return annotations.stream().map(ta -> TypeAnnotation.of(
181 transformTargetInfo(ta.targetInfo(), cob, labels),
182 ta.targetPath().stream().map(tpc -> TypeAnnotation.TypePathComponent.of(tpc.typePathKind(), tpc.typeArgumentIndex())).toList(),
183 transformAnnotation(ta.annotation()))).toArray(TypeAnnotation[]::new);
184 }
185
186 static TypeAnnotation.TargetInfo transformTargetInfo(TypeAnnotation.TargetInfo ti, CodeBuilder cob, HashMap<Label, Label> labels) {
187 return switch (ti) {
188 case TypeAnnotation.CatchTarget t -> TypeAnnotation.TargetInfo.ofExceptionParameter(t.exceptionTableIndex());
189 case TypeAnnotation.EmptyTarget t -> TypeAnnotation.TargetInfo.of(t.targetType());
190 case TypeAnnotation.FormalParameterTarget t -> TypeAnnotation.TargetInfo.ofMethodFormalParameter(t.formalParameterIndex());
191 case TypeAnnotation.SupertypeTarget t -> TypeAnnotation.TargetInfo.ofClassExtends(t.supertypeIndex());
192 case TypeAnnotation.ThrowsTarget t -> TypeAnnotation.TargetInfo.ofThrows(t.throwsTargetIndex());
193 case TypeAnnotation.TypeParameterBoundTarget t -> TypeAnnotation.TargetInfo.ofTypeParameterBound(t.targetType(), t.typeParameterIndex(), t.boundIndex());
194 case TypeAnnotation.TypeParameterTarget t -> TypeAnnotation.TargetInfo.ofTypeParameter(t.targetType(), t.typeParameterIndex());
195 case TypeAnnotation.LocalVarTarget t -> TypeAnnotation.TargetInfo.ofVariable(t.targetType(), t.table().stream().map(lvti ->
196 TypeAnnotation.LocalVarTargetInfo.of(labels.computeIfAbsent(lvti.startLabel(), l -> cob.newLabel()),
197 labels.computeIfAbsent(lvti.endLabel(), l -> cob.newLabel()), lvti.index())).toList());
198 case TypeAnnotation.OffsetTarget t -> TypeAnnotation.TargetInfo.ofOffset(t.targetType(), labels.computeIfAbsent(t.target(), l -> cob.newLabel()));
199 case TypeAnnotation.TypeArgumentTarget t -> TypeAnnotation.TargetInfo.ofTypeArgument(t.targetType(),
200 labels.computeIfAbsent(t.target(), l -> cob.newLabel()), t.typeArgumentIndex());
201 };
202 }
203
204 static List<StackMapFrameInfo.VerificationTypeInfo> transformFrameTypeInfos(List<StackMapFrameInfo.VerificationTypeInfo> infos, CodeBuilder cob, HashMap<Label, Label> labels) {
205 return infos.stream().map(ti -> {
206 return switch (ti) {
207 case StackMapFrameInfo.SimpleVerificationTypeInfo i -> i;
208 case StackMapFrameInfo.ObjectVerificationTypeInfo i -> StackMapFrameInfo.ObjectVerificationTypeInfo.of(i.classSymbol());
209 case StackMapFrameInfo.UninitializedVerificationTypeInfo i -> StackMapFrameInfo.UninitializedVerificationTypeInfo.of(labels.computeIfAbsent(i.newTarget(), l -> cob.newLabel()));
210 };
211 }).toList();
212 }
213
214 static class CodeRebuildingTransform implements CodeTransform {
215
216 final HashMap<Label, Label> labels = new HashMap<>();
217
218 @Override
219 public void accept(CodeBuilder cob, CodeElement coe) {
220 switch (coe) {
221 case ArrayLoadInstruction i -> {
222 switch (i.typeKind()) {
223 case BYTE -> cob.baload();
224 case SHORT -> cob.saload();
225 case INT -> cob.iaload();
226 case FLOAT -> cob.faload();
227 case LONG -> cob.laload();
228 case DOUBLE -> cob.daload();
229 case REFERENCE -> cob.aaload();
230 case CHAR -> cob.caload();
231 default -> throw new AssertionError("Should not reach here");
232 }
233 }
234 case ArrayStoreInstruction i -> {
235 switch (i.typeKind()) {
236 case BYTE -> cob.bastore();
237 case SHORT -> cob.sastore();
238 case INT -> cob.iastore();
239 case FLOAT -> cob.fastore();
240 case LONG -> cob.lastore();
241 case DOUBLE -> cob.dastore();
242 case REFERENCE -> cob.aastore();
243 case CHAR -> cob.castore();
244 default -> throw new AssertionError("Should not reach here");
245 }
246 }
247 case BranchInstruction i -> {
248 var target = labels.computeIfAbsent(i.target(), l -> cob.newLabel());
249 switch (i.opcode()) {
250 case GOTO -> cob.goto_(target);
251 case GOTO_W -> cob.goto_w(target);
252 case IF_ACMPEQ -> cob.if_acmpeq(target);
253 case IF_ACMPNE -> cob.if_acmpne(target);
254 case IF_ICMPEQ -> cob.if_icmpeq(target);
255 case IF_ICMPGE -> cob.if_icmpge(target);
256 case IF_ICMPGT -> cob.if_icmpgt(target);
257 case IF_ICMPLE -> cob.if_icmple(target);
258 case IF_ICMPLT -> cob.if_icmplt(target);
259 case IF_ICMPNE -> cob.if_icmpne(target);
260 case IFNONNULL -> cob.ifnonnull(target);
261 case IFNULL -> cob.ifnull(target);
262 case IFEQ -> cob.ifeq(target);
263 case IFGE -> cob.ifge(target);
264 case IFGT -> cob.ifgt(target);
265 case IFLE -> cob.ifle(target);
266 case IFLT -> cob.iflt(target);
267 case IFNE -> cob.ifne(target);
268 default -> throw new AssertionError("Should not reach here");
269 }
270 }
271 case ConstantInstruction i -> {
272 if (i.constantValue() == null)
273 if (pathSwitch.nextBoolean()) cob.aconst_null();
274 else cob.loadConstant(null);
275 else switch (i.constantValue()) {
276 case Integer iVal -> {
277 if (iVal == 1 && pathSwitch.nextBoolean()) cob.iconst_1();
278 else if (iVal == 2 && pathSwitch.nextBoolean()) cob.iconst_2();
279 else if (iVal == 3 && pathSwitch.nextBoolean()) cob.iconst_3();
280 else if (iVal == 4 && pathSwitch.nextBoolean()) cob.iconst_4();
281 else if (iVal == 5 && pathSwitch.nextBoolean()) cob.iconst_5();
282 else if (iVal == -1 && pathSwitch.nextBoolean()) cob.iconst_m1();
283 else if (iVal >= -128 && iVal <= 127 && pathSwitch.nextBoolean()) cob.bipush(iVal);
284 else if (iVal >= -32768 && iVal <= 32767 && pathSwitch.nextBoolean()) cob.sipush(iVal);
285 else cob.loadConstant(iVal);
286 }
287 case Long lVal -> {
288 if (lVal == 0 && pathSwitch.nextBoolean()) cob.lconst_0();
289 else if (lVal == 1 && pathSwitch.nextBoolean()) cob.lconst_1();
290 else cob.loadConstant(lVal);
291 }
292 case Float fVal -> {
293 if (fVal == 0.0 && pathSwitch.nextBoolean()) cob.fconst_0();
294 else if (fVal == 1.0 && pathSwitch.nextBoolean()) cob.fconst_1();
295 else if (fVal == 2.0 && pathSwitch.nextBoolean()) cob.fconst_2();
296 else cob.loadConstant(fVal);
297 }
298 case Double dVal -> {
299 if (dVal == 0.0d && pathSwitch.nextBoolean()) cob.dconst_0();
300 else if (dVal == 1.0d && pathSwitch.nextBoolean()) cob.dconst_1();
301 else cob.loadConstant(dVal);
302 }
303 default -> cob.loadConstant(i.constantValue());
304 }
305 }
306 case ConvertInstruction i -> {
307 switch (i.fromType()) {
308 case DOUBLE -> {
309 switch (i.toType()) {
310 case FLOAT -> cob.d2f();
311 case INT -> cob.d2i();
312 case LONG -> cob.d2l();
313 default -> throw new AssertionError("Should not reach here");
314 }
315 }
316 case FLOAT -> {
317 switch (i.toType()) {
318 case DOUBLE -> cob.f2d();
319 case INT -> cob.f2i();
320 case LONG -> cob.f2l();
321 default -> throw new AssertionError("Should not reach here");
322 }
323 }
324 case INT -> {
325 switch (i.toType()) {
326 case BYTE -> cob.i2b();
327 case CHAR -> cob.i2c();
328 case DOUBLE -> cob.i2d();
329 case FLOAT -> cob.i2f();
330 case LONG -> cob.i2l();
331 case SHORT -> cob.i2s();
332 default -> throw new AssertionError("Should not reach here");
333 }
334 }
335 case LONG -> {
336 switch (i.toType()) {
337 case DOUBLE -> cob.l2d();
338 case FLOAT -> cob.l2f();
339 case INT -> cob.l2i();
340 default -> throw new AssertionError("Should not reach here");
341 }
342 }
343 default -> throw new AssertionError("Should not reach here");
344 }
345 }
346 case DiscontinuedInstruction.JsrInstruction i ->
347 cob.with(DiscontinuedInstruction.JsrInstruction.of(i.opcode(), labels.computeIfAbsent(i.target(), l -> cob.newLabel())));
348 case DiscontinuedInstruction.RetInstruction i ->
349 cob.with(DiscontinuedInstruction.RetInstruction.of(i.opcode(), i.slot()));
350 case FieldInstruction i -> {
351 if (pathSwitch.nextBoolean()) {
352 switch (i.opcode()) {
353 case GETFIELD -> cob.getfield(i.owner().asSymbol(), i.name().stringValue(), i.typeSymbol());
354 case GETSTATIC -> cob.getstatic(i.owner().asSymbol(), i.name().stringValue(), i.typeSymbol());
355 case PUTFIELD -> cob.putfield(i.owner().asSymbol(), i.name().stringValue(), i.typeSymbol());
356 case PUTSTATIC -> cob.putstatic(i.owner().asSymbol(), i.name().stringValue(), i.typeSymbol());
357 default -> throw new AssertionError("Should not reach here");
358 }
359 } else {
360 switch (i.opcode()) {
361 case GETFIELD -> cob.getfield(i.field());
362 case GETSTATIC -> cob.getstatic(i.field());
363 case PUTFIELD -> cob.putfield(i.field());
364 case PUTSTATIC -> cob.putstatic(i.field());
365 default -> throw new AssertionError("Should not reach here");
366 }
367 }
368 }
369 case InvokeDynamicInstruction i -> {
370 if (pathSwitch.nextBoolean()) cob.invokedynamic(i.invokedynamic().asSymbol());
371 else cob.invokedynamic(i.invokedynamic());
372 }
373 case InvokeInstruction i -> {
374 if (pathSwitch.nextBoolean()) {
375 if (i.isInterface()) {
376 switch (i.opcode()) {
377 case INVOKEINTERFACE -> cob.invokeinterface(i.owner().asSymbol(), i.name().stringValue(), i.typeSymbol());
378 case INVOKESPECIAL -> cob.invokespecial(i.owner().asSymbol(), i.name().stringValue(), i.typeSymbol(), true);
379 case INVOKESTATIC -> cob.invokestatic(i.owner().asSymbol(), i.name().stringValue(), i.typeSymbol(), true);
380 default -> throw new AssertionError("Should not reach here");
381 }
382 } else {
383 switch (i.opcode()) {
384 case INVOKESPECIAL -> cob.invokespecial(i.owner().asSymbol(), i.name().stringValue(), i.typeSymbol());
385 case INVOKESTATIC -> cob.invokestatic(i.owner().asSymbol(), i.name().stringValue(), i.typeSymbol());
386 case INVOKEVIRTUAL -> cob.invokevirtual(i.owner().asSymbol(), i.name().stringValue(), i.typeSymbol());
387 default -> throw new AssertionError("Should not reach here");
388 }
389 }
390 } else {
391 switch (i.method()) {
392 case InterfaceMethodRefEntry en -> {
393 switch (i.opcode()) {
394 case INVOKEINTERFACE -> cob.invokeinterface(en);
395 case INVOKESPECIAL -> cob.invokespecial(en);
396 case INVOKESTATIC -> cob.invokestatic(en);
397 default -> throw new AssertionError("Should not reach here");
398 }
399 }
400 case MethodRefEntry en -> {
401 switch (i.opcode()) {
402 case INVOKESPECIAL -> cob.invokespecial(en);
403 case INVOKESTATIC -> cob.invokestatic(en);
404 case INVOKEVIRTUAL -> cob.invokevirtual(en);
405 default -> throw new AssertionError("Should not reach here");
406 }
407 }
408 default -> throw new AssertionError("Should not reach here");
409 }
410 }
411 }
412 case LoadInstruction i -> {
413 switch (i.typeKind()) {
414 case INT -> cob.iload(i.slot());
415 case FLOAT -> cob.fload(i.slot());
416 case LONG -> cob.lload(i.slot());
417 case DOUBLE -> cob.dload(i.slot());
418 case REFERENCE -> cob.aload(i.slot());
419 default -> throw new AssertionError("Should not reach here");
420 }
421 }
422 case StoreInstruction i -> {
423 switch (i.typeKind()) {
424 case INT -> cob.istore(i.slot());
425 case FLOAT -> cob.fstore(i.slot());
426 case LONG -> cob.lstore(i.slot());
427 case DOUBLE -> cob.dstore(i.slot());
428 case REFERENCE -> cob.astore(i.slot());
429 default -> throw new AssertionError("Should not reach here");
430 }
431 }
432 case IncrementInstruction i ->
433 cob.iinc(i.slot(), i.constant());
434 case LookupSwitchInstruction i ->
435 cob.lookupswitch(labels.computeIfAbsent(i.defaultTarget(), l -> cob.newLabel()),
436 i.cases().stream().map(sc ->
437 SwitchCase.of(sc.caseValue(), labels.computeIfAbsent(sc.target(), l -> cob.newLabel()))).toList());
438 case MonitorInstruction i -> {
439 switch (i.opcode()) {
440 case MONITORENTER -> cob.monitorenter();
441 case MONITOREXIT -> cob.monitorexit();
442 default -> throw new AssertionError("Should not reach here");
443 }
444 }
445 case NewMultiArrayInstruction i -> {
446 if (pathSwitch.nextBoolean()) {
447 cob.multianewarray(i.arrayType().asSymbol(), i.dimensions());
448 } else {
449 cob.multianewarray(i.arrayType(), i.dimensions());
450 }
451 }
452 case NewObjectInstruction i -> {
453 if (pathSwitch.nextBoolean()) {
454 cob.new_(i.className().asSymbol());
455 } else {
456 cob.new_(i.className());
457 }
458 }
459 case NewPrimitiveArrayInstruction i ->
460 cob.newarray(i.typeKind());
461 case NewReferenceArrayInstruction i -> {
462 if (pathSwitch.nextBoolean()) {
463 cob.anewarray(i.componentType().asSymbol());
464 } else {
465 cob.anewarray(i.componentType());
466 }
467 }
468 case NopInstruction i ->
469 cob.nop();
470 case OperatorInstruction i -> {
471 switch (i.opcode()) {
472 case IADD -> cob.iadd();
473 case LADD -> cob.ladd();
474 case FADD -> cob.fadd();
475 case DADD -> cob.dadd();
476 case ISUB -> cob.isub();
477 case LSUB -> cob.lsub();
478 case FSUB -> cob.fsub();
479 case DSUB -> cob.dsub();
480 case IMUL -> cob.imul();
481 case LMUL -> cob.lmul();
482 case FMUL -> cob.fmul();
483 case DMUL -> cob.dmul();
484 case IDIV -> cob.idiv();
485 case LDIV -> cob.ldiv();
486 case FDIV -> cob.fdiv();
487 case DDIV -> cob.ddiv();
488 case IREM -> cob.irem();
489 case LREM -> cob.lrem();
490 case FREM -> cob.frem();
491 case DREM -> cob.drem();
492 case INEG -> cob.ineg();
493 case LNEG -> cob.lneg();
494 case FNEG -> cob.fneg();
495 case DNEG -> cob.dneg();
496 case ISHL -> cob.ishl();
497 case LSHL -> cob.lshl();
498 case ISHR -> cob.ishr();
499 case LSHR -> cob.lshr();
500 case IUSHR -> cob.iushr();
501 case LUSHR -> cob.lushr();
502 case IAND -> cob.iand();
503 case LAND -> cob.land();
504 case IOR -> cob.ior();
505 case LOR -> cob.lor();
506 case IXOR -> cob.ixor();
507 case LXOR -> cob.lxor();
508 case LCMP -> cob.lcmp();
509 case FCMPL -> cob.fcmpl();
510 case FCMPG -> cob.fcmpg();
511 case DCMPL -> cob.dcmpl();
512 case DCMPG -> cob.dcmpg();
513 case ARRAYLENGTH -> cob.arraylength();
514 default -> throw new AssertionError("Should not reach here");
515 }
516 }
517 case ReturnInstruction i -> {
518 switch (i.typeKind()) {
519 case INT -> cob.ireturn();
520 case FLOAT -> cob.freturn();
521 case LONG -> cob.lreturn();
522 case DOUBLE -> cob.dreturn();
523 case REFERENCE -> cob.areturn();
524 case VOID -> cob.return_();
525 default -> throw new AssertionError("Should not reach here");
526 }
527 }
528 case StackInstruction i -> {
529 switch (i.opcode()) {
530 case POP -> cob.pop();
531 case POP2 -> cob.pop2();
532 case DUP -> cob.dup();
533 case DUP_X1 -> cob.dup_x1();
534 case DUP_X2 -> cob.dup_x2();
535 case DUP2 -> cob.dup2();
536 case DUP2_X1 -> cob.dup2_x1();
537 case DUP2_X2 -> cob.dup2_x2();
538 case SWAP -> cob.swap();
539 default -> throw new AssertionError("Should not reach here");
540 }
541 }
542 case TableSwitchInstruction i ->
543 cob.tableswitch(i.lowValue(), i.highValue(),
544 labels.computeIfAbsent(i.defaultTarget(), l -> cob.newLabel()),
545 i.cases().stream().map(sc ->
546 SwitchCase.of(sc.caseValue(), labels.computeIfAbsent(sc.target(), l -> cob.newLabel()))).toList());
547 case ThrowInstruction i -> cob.athrow();
548 case TypeCheckInstruction i -> {
549 if (pathSwitch.nextBoolean()) {
550 switch (i.opcode()) {
551 case CHECKCAST -> cob.checkcast(i.type().asSymbol());
552 case INSTANCEOF -> cob.instanceOf(i.type().asSymbol());
553 default -> throw new AssertionError("Should not reach here");
554 }
555 } else {
556 switch (i.opcode()) {
557 case CHECKCAST -> cob.checkcast(i.type());
558 case INSTANCEOF -> cob.instanceOf(i.type());
559 default -> throw new AssertionError("Should not reach here");
560 }
561 }
562 }
563 case CharacterRange pi ->
564 cob.characterRange(labels.computeIfAbsent(pi.startScope(), l -> cob.newLabel()),
565 labels.computeIfAbsent(pi.endScope(), l -> cob.newLabel()),
566 pi.characterRangeStart(), pi.characterRangeEnd(), pi.flags());
567 case ExceptionCatch pi ->
568 pi.catchType().ifPresentOrElse(
569 catchType -> cob.exceptionCatch(labels.computeIfAbsent(pi.tryStart(), l -> cob.newLabel()),
570 labels.computeIfAbsent(pi.tryEnd(), l -> cob.newLabel()),
571 labels.computeIfAbsent(pi.handler(), l -> cob.newLabel()),
572 catchType.asSymbol()),
573 () -> cob.exceptionCatchAll(labels.computeIfAbsent(pi.tryStart(), l -> cob.newLabel()),
574 labels.computeIfAbsent(pi.tryEnd(), l -> cob.newLabel()),
575 labels.computeIfAbsent(pi.handler(), l -> cob.newLabel())));
576 case LabelTarget pi ->
577 cob.labelBinding(labels.computeIfAbsent(pi.label(), l -> cob.newLabel()));
578 case LineNumber pi ->
579 cob.lineNumber(pi.line());
580 case LocalVariable pi ->
581 cob.localVariable(pi.slot(), pi.name().stringValue(), pi.typeSymbol(),
582 labels.computeIfAbsent(pi.startScope(), l -> cob.newLabel()),
583 labels.computeIfAbsent(pi.endScope(), l -> cob.newLabel()));
584 case LocalVariableType pi ->
585 cob.localVariableType(pi.slot(), pi.name().stringValue(),
586 Signature.parseFrom(pi.signatureSymbol().signatureString()),
587 labels.computeIfAbsent(pi.startScope(), l -> cob.newLabel()),
588 labels.computeIfAbsent(pi.endScope(), l -> cob.newLabel()));
589 case RuntimeInvisibleTypeAnnotationsAttribute a ->
590 cob.with(RuntimeInvisibleTypeAnnotationsAttribute.of(transformTypeAnnotations(a.annotations(), cob, labels)));
591 case RuntimeVisibleTypeAnnotationsAttribute a ->
592 cob.with(RuntimeVisibleTypeAnnotationsAttribute.of(transformTypeAnnotations(a.annotations(), cob, labels)));
593 case StackMapTableAttribute a ->
594 cob.with(StackMapTableAttribute.of(a.entries().stream().map(fr ->
595 StackMapFrameInfo.of(labels.computeIfAbsent(fr.target(), l -> cob.newLabel()),
596 transformFrameTypeInfos(fr.locals(), cob, labels),
597 transformFrameTypeInfos(fr.stack(), cob, labels))).toList()));
598 case CustomAttribute<?> a ->
599 throw new AssertionError("Unexpected custom attribute: " + a.attributeName().stringValue());
600 case UnknownAttribute a ->
601 throw new AssertionError("Unexpected unknown attribute: " + a.attributeName().stringValue());
602 }
603 }
604 }
605 }