private String[] box_types = new String[] { "java/lang/Integer", "java/lang/Long", "java/lang/Float", "java/lang/Double" };
private String[] box_descs = new String[] { "(I)V", "(J)V", "(F)V", "(D)V" };
private void emitFragmentInsn(MethodVisitor v, int iix, int begin, Label[] insnLabels, Map<Integer,Label> exitTrampolineLabels, Set<String> spilledUTypes) {
v.visitLabel(insnLabels[iix - begin]);
AbstractInsnNode ai = insnList[iix];
// some instructions require very special handling
int opc = ai.getOpcode();
if (opc == Opcodes.RETURN) {
v.visitInsn(Opcodes.ICONST_M1);
v.visitInsn(Opcodes.IRETURN);
return;
}
if (opc >= Opcodes.IRETURN && opc <= Opcodes.ARETURN) {
int t = opc - Opcodes.IRETURN;
v.visitVarInsn(Opcodes.ISTORE + t, nlocal+1);
v.visitVarInsn(Opcodes.ALOAD, nlocal);
v.visitInsn(Opcodes.ICONST_0);
if (opc != Opcodes.ARETURN) {
v.visitTypeInsn(Opcodes.NEW, box_types[t]);
v.visitInsn(Opcodes.DUP);
v.visitVarInsn(Opcodes.ILOAD + t, nlocal+1);
v.visitMethodInsn(Opcodes.INVOKESPECIAL, box_types[t], "<init>", box_descs[t]);
} else {
v.visitVarInsn(Opcodes.ILOAD + t, nlocal+1);
}
v.visitInsn(Opcodes.AASTORE);
v.visitInsn(Opcodes.ICONST_M1);
v.visitInsn(Opcodes.IRETURN);
return;
}
if (opc == Opcodes.NEW) {
Frame f = types[iix+1];
if (spilledUTypes.contains(f.stack[f.sp-1])) {
v.visitInsn(Opcodes.ACONST_NULL);
return;
}
}
if (opc == Opcodes.INVOKESPECIAL) {
MethodInsnNode mi = (MethodInsnNode)ai;
Frame f1 = types[iix];
Frame f2 = types[iix+1];
String uninit = f1.stack[f2.sp];
if (mi.name.equals("<init>") && spilledUTypes.contains(uninit)) {
if (!f2.stack[f2.sp-1].equals(uninit)) throw new RuntimeException("general case of INVOKESPECIAL spill not implemented");
for (int i = 0; i < f2.sp-1; i++) if (f2.stack[i].equals(uninit)) throw new RuntimeException("general case of INVOKESPECIAL spill not implemented");
int ltmp = nlocal+1;
int argc = Type.getArgumentTypes(mi.desc).length;
int[] spillarg = new int[argc];
for (int d = 0; d < argc; d++) {
char ty0 = f1.stack[f1.sp-d-1].charAt(0);
spillarg[d] = ltmp;
v.visitVarInsn(ty0 == 'D' ? Opcodes.DSTORE : ty0 == 'J' ? Opcodes.LSTORE : ty0 == 'I' ? Opcodes.ISTORE : ty0 == 'F' ? Opcodes.FSTORE : Opcodes.ASTORE, ltmp);
ltmp += (ty0 == 'D' || ty0 == 'J') ? 2 : 1;
}
v.visitInsn(Opcodes.POP2);
v.visitTypeInsn(Opcodes.NEW, mi.owner);
v.visitInsn(Opcodes.DUP);
for (int d = argc-1; d >= 0; d++) {
char ty0 = f1.stack[f1.sp-d-1].charAt(0);
v.visitVarInsn(ty0 == 'D' ? Opcodes.DLOAD : ty0 == 'J' ? Opcodes.LLOAD : ty0 == 'I' ? Opcodes.ILOAD : ty0 == 'F' ? Opcodes.FLOAD : Opcodes.ALOAD, spillarg[d]);
}
v.visitMethodInsn(Opcodes.INVOKESPECIAL, mi.owner, mi.name, mi.desc);
return;
}
}
// all other instructions can be processed normally, perhaps with some control-flow fudging
switch (ai.getType()) {
case AbstractInsnNode.JUMP_INSN:
{
JumpInsnNode ji = (JumpInsnNode)ai;
v.visitJumpInsn(opc, mapLabel(ji.label, begin, insnLabels, exitTrampolineLabels));
break;
}
case AbstractInsnNode.TABLESWITCH_INSN:
{
TableSwitchInsnNode si = (TableSwitchInsnNode)ai;
Label[] mapped = new Label[si.labels.size()];
for (int i = 0; i < mapped.length; i++)
mapped[i] = mapLabel((LabelNode)si.labels.get(i), begin, insnLabels, exitTrampolineLabels);
v.visitTableSwitchInsn(si.min, si.max, mapLabel(si.dflt, begin, insnLabels, exitTrampolineLabels), mapped);
break;
}
case AbstractInsnNode.LOOKUPSWITCH_INSN:
{
LookupSwitchInsnNode si = (LookupSwitchInsnNode)ai;
Label[] mapped = new Label[si.labels.size()];
for (int i = 0; i < mapped.length; i++)
mapped[i] = mapLabel((LabelNode)si.labels.get(i), begin, insnLabels, exitTrampolineLabels);
int[] keys = new int[si.keys.size()];
for (int i = 0; i < keys.length; i++)
keys[i] = (int)si.keys.get(i);
v.visitLookupSwitchInsn(mapLabel(si.dflt, begin, insnLabels, exitTrampolineLabels), keys, mapped);
break;
}
default:
ai.accept(v);
break;
}
}