package com.sun.btrace.shared;
import com.sun.btrace.org.objectweb.asm.Type;
import com.sun.btrace.org.objectweb.asm.tree.*;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
public class MethodSerializer {
private static final class LabelRepository {
private final Map<LabelNode, Integer> labelMap = new HashMap<>();
private final AtomicInteger counter = new AtomicInteger();
public int getLabelIdx(LabelNode ln) {
Integer i = labelMap.get(ln);
if (i == null) {
i = counter.getAndIncrement();
labelMap.put(ln, i);
}
return i;
}
}
public static byte[] serialize(MethodNode mn) throws IOException {
LabelRepository lr = new LabelRepository();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos);
dos.writeUTF(mn.name);
dos.writeInt(mn.access);
dos.writeUTF(mn.desc);
writeParameters((List<ParameterNode>)mn.parameters, dos);
writeLocalVariables((List<LocalVariableNode>)mn.localVariables, lr, dos);
writeBody(mn.instructions, lr, dos);
return bos.toByteArray();
}
private static void writeParameters(List<ParameterNode> nodes, DataOutputStream dos) throws IOException {
if (nodes == null) {
dos.writeInt(0);
return;
}
dos.writeInt(nodes.size());
for (ParameterNode pm : nodes) {
dos.writeUTF(pm.name);
dos.writeInt(pm.access);
}
}
private static void writeLocalVariables(List<LocalVariableNode> nodes, LabelRepository lr, DataOutputStream dos) throws IOException {
if (nodes == null) {
dos.writeInt(0);
return;
}
dos.writeInt(nodes.size());
for (LocalVariableNode lvn : nodes) {
dos.writeUTF(lvn.name);
dos.writeUTF(lvn.desc);
dos.writeUTF(lvn.signature);
dos.writeInt(lvn.index);
writeLabel(lvn.start, lr, dos);
writeLabel(lvn.end, lr, dos);
}
}
private static void writeBody(InsnList il, LabelRepository lr, DataOutputStream dos) throws IOException {
for (AbstractInsnNode n = il.getFirst(); n != null; n = n.getNext()) {
dos.writeInt(n.getType());
dos.writeInt(n.getOpcode());
switch (n.getType()) {
case AbstractInsnNode.FIELD_INSN: {
writeField((FieldInsnNode)n, dos);
break;
}
case AbstractInsnNode.FRAME: {
writeFrame((FrameNode)n, lr, dos);
break;
}
case AbstractInsnNode.IINC_INSN: {
IincInsnNode iin = (IincInsnNode)n;
dos.writeInt(iin.var);
dos.writeInt(iin.incr);
break;
}
case AbstractInsnNode.INSN: {
// just opcode
break;
}
case AbstractInsnNode.INT_INSN: {
IntInsnNode iin = (IntInsnNode)n;
dos.writeInt(iin.operand);
break;
}
case AbstractInsnNode.INVOKE_DYNAMIC_INSN: {
// ignore for now
break;
}
case AbstractInsnNode.LABEL: {
writeLabel((LabelNode)n, lr, dos);
break;
}
case AbstractInsnNode.JUMP_INSN: {
JumpInsnNode jin = (JumpInsnNode)n;
writeLabel(jin.label, lr, dos);
break;
}
case AbstractInsnNode.LDC_INSN: {
writeLdc((LdcInsnNode)n, dos);
break;
}
case AbstractInsnNode.LOOKUPSWITCH_INSN: {
writeLookupSwitch((LookupSwitchInsnNode)n, lr, dos);
break;
}
case AbstractInsnNode.METHOD_INSN: {
writeMethodInv((MethodInsnNode)n, dos);
break;
}
case AbstractInsnNode.MULTIANEWARRAY_INSN: {
writeMultiANewArray((MultiANewArrayInsnNode)n, dos);
break;
}
case AbstractInsnNode.TABLESWITCH_INSN: {
writeTableSwitch((TableSwitchInsnNode)n, lr, dos);
break;
}
case AbstractInsnNode.TYPE_INSN: {
writeTypeInsn((TypeInsnNode)n, dos);
break;
}
case AbstractInsnNode.VAR_INSN: {
writeVar((VarInsnNode)n, dos);
break;
}
}
}
}
private static void writeLabel(LabelNode ln, LabelRepository lr, DataOutputStream dos) throws IOException {
dos.writeInt(lr.getLabelIdx(ln));
}
private static void writeFrame(FrameNode fn, LabelRepository lr, DataOutputStream dos) throws IOException {
for (Object o : fn.local) {
if (o instanceof LabelNode) {
dos.writeShort(1);
writeLabel((LabelNode)o, lr, dos);
} else {
if (o instanceof String) {
dos.writeShort(2);
dos.writeUTF((String)o);
} else if (o instanceof Integer) {
dos.writeShort(3);
dos.writeInt((Integer)o);
} else {
dos.writeShort(0);
}
}
}
for (Object o : fn.stack) {
if (o instanceof LabelNode) {
dos.writeShort(1);
writeLabel((LabelNode)o, lr, dos);
} else {
if (o instanceof String) {
dos.writeShort(2);
dos.writeUTF((String)o);
} else if (o instanceof Integer) {
dos.writeShort(3);
dos.writeInt((Integer)o);
} else {
dos.writeShort(0);
}
}
}
}
private static void writeField(FieldInsnNode fin, DataOutputStream dos) throws IOException {
dos.writeUTF(fin.name);
dos.writeUTF(fin.owner);
dos.writeUTF(fin.desc);
}
private static void writeLdc(LdcInsnNode lin, DataOutputStream dos) throws IOException {
Object o = lin.cst;
if (o instanceof Integer) {
dos.writeShort(1);
dos.writeInt((Integer)o);
} else if (o instanceof Float) {
dos.writeShort(2);
dos.writeFloat((Float)o);
} else if (o instanceof Long) {
dos.writeShort(3);
dos.writeLong((Long)o);
} else if (o instanceof Double) {
dos.writeShort(4);
dos.writeDouble((Double)o);
} else if (o instanceof String) {
dos.writeShort(5);
dos.writeUTF((String)o);
} else if (o instanceof Type) {
dos.writeShort(6);
dos.writeUTF(((Type)o).getDescriptor());
} else {
dos.writeShort(0);
}
}
private static void writeLookupSwitch(LookupSwitchInsnNode lsin, LabelRepository lr, DataOutputStream dos) throws IOException {
writeLabel(lsin.dflt, lr, dos);
dos.writeInt(lsin.keys.size());
for (Integer key : (List<Integer>)lsin.keys) {
dos.writeInt(key);
}
dos.writeInt(lsin.labels.size());
for (LabelNode ln : (List<LabelNode>)lsin.labels) {
writeLabel(ln, lr, dos);
}
}
private static void writeMethodInv(MethodInsnNode min, DataOutputStream dos) throws IOException {
dos.writeUTF(min.owner);
dos.writeUTF(min.name);
dos.writeUTF(min.desc);
dos.writeBoolean(min.itf);
}
private static void writeMultiANewArray(MultiANewArrayInsnNode n, DataOutputStream dos) throws IOException {
dos.writeInt(n.dims);
dos.writeUTF(n.desc);
}
private static void writeTableSwitch(TableSwitchInsnNode n, LabelRepository lr, DataOutputStream dos) throws IOException {
dos.writeInt(n.min);
dos.writeInt(n.max);
writeLabel(n.dflt, lr, dos);
dos.writeInt(n.labels.size());
for (LabelNode ln : (List<LabelNode>)n.labels) {
writeLabel(ln, lr, dos);
}
}
private static void writeTypeInsn(TypeInsnNode n, DataOutputStream dos) throws IOException {
dos.writeUTF(n.desc);
}
private static void writeVar(VarInsnNode n, DataOutputStream dos) throws IOException {
dos.writeInt(n.var);
}
}