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