1 /* 2 * Copyright (c) 2022, 2024, 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 java.lang.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()); 63 case UnknownAttribute a -> throw new AssertionError("Unexpected unknown attribute: " + a.attributeName()); 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()); 95 case UnknownAttribute a -> throw new AssertionError("Unexpected unknown attribute: " + a.attributeName()); 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()); 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()); 147 case UnknownAttribute a -> throw new AssertionError("Unexpected unknown attribute: " + a.attributeName()); 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()); 600 } 601 } 602 } 603 }