Commit 2534c634 authored by Yudi Zheng's avatar Yudi Zheng

Move splitter to a new project.

parent caed92ea
package ch.usi.dag.disl.weaver.splitter;
import org.objectweb.asm.tree.analysis.Value;
public class FlagValue implements Value {
public class FlagReference {
boolean rFlag;
public FlagReference(boolean rFlag) {
this.rFlag = rFlag;
}
}
private int size;
private boolean flag;
private FlagReference ref;
public FlagValue(int size) {
this.size = size;
this.flag = true;
this.ref = new FlagReference(true);
}
public FlagValue(int size, boolean flag) {
this.size = size;
this.flag = flag;
this.ref = null;
}
@Override
public int getSize() {
return size;
}
public boolean getFlag() {
if (ref == null) {
return flag;
} else {
return ref.rFlag;
}
}
public void setFlag(boolean flag) {
if (ref == null) {
this.flag = flag;
} else {
ref.rFlag = flag;
}
}
public FlagValue clone() {
FlagValue clone = new FlagValue(size, flag);
clone.ref = ref;
return clone;
}
}
package ch.usi.dag.disl.weaver.splitter;
import java.util.HashSet;
import java.util.Set;
public class LocalVar {
public int index;
public Set<SuperBlock> defines;
public Set<SuperBlock> uses;
public LocalVar(int index) {
this.index = index;
this.defines = new HashSet<SuperBlock>();
this.uses = new HashSet<SuperBlock>();
}
public void addDefine(SuperBlock sb) {
defines.add(sb);
}
public void addUse(SuperBlock sb) {
uses.add(sb);
}
}
package ch.usi.dag.disl.weaver.splitter;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Stack;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.IincInsnNode;
import org.objectweb.asm.tree.InsnList;
import org.objectweb.asm.tree.InsnNode;
import org.objectweb.asm.tree.LabelNode;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.MethodNode;
import org.objectweb.asm.tree.VarInsnNode;
import org.objectweb.asm.tree.analysis.BasicValue;
import org.objectweb.asm.tree.analysis.Frame;
import ch.usi.dag.disl.exception.DiSLFatalException;
import ch.usi.dag.disl.util.AsmHelper;
import ch.usi.dag.disl.util.FrameHelper;
import ch.usi.dag.disl.util.cfg.CtrlFlowGraph;
import ch.usi.dag.disl.weaver.pe.MaxCalculator;
public class Splitter {
public int idx = 0;
private ClassNode clazz;
private MethodNode method;
private CtrlFlowGraph cfg;
private LocalVar[] locals;
private List<SuperBlock> superblocks;
private Map<AbstractInsnNode, Frame<BasicValue>> frames_mapping;
public Splitter(ClassNode clazz, MethodNode method) {
this.clazz = clazz;
this.method = method;
this.cfg = CtrlFlowGraph.build(method);
locals = new LocalVar[method.maxLocals];
for (int i = 0; i < method.maxLocals; i++) {
locals[i] = new LocalVar(i);
}
frames_mapping = FrameHelper.createBasicMapping(clazz.name, method);
superblocks = SuperBlock.build(method, cfg, locals, frames_mapping);
Collections.sort(superblocks);
}
public AbstractInsnNode fork(MethodNode newMethod, SuperBlock sb) {
InsnList src = method.instructions;
InsnList dst = newMethod.instructions;
AbstractInsnNode[] src_array = src.toArray();
AbstractInsnNode[] dst_array = dst.toArray();
boolean flag = false;
LabelNode label = new LabelNode();
InsnList iList = new InsnList();
for (int i = 0; i < src_array.length; i++) {
AbstractInsnNode instr_src = src_array[i];
AbstractInsnNode instr_dst = dst_array[i];
if (instr_src.equals(sb.start)) {
src.insertBefore(instr_src, label);
flag = true;
}
if (flag) {
if (instr_src.getOpcode() != -1) {
src.remove(instr_src);
iList.add(instr_src);
}
} else {
if (instr_dst.getOpcode() != -1) {
dst.remove(instr_dst);
}
}
if (instr_src.equals(sb.end)) {
flag = false;
}
}
return label;
}
public void complete(MethodNode newMethod, SuperBlock sb,
AbstractInsnNode label) {
boolean fReturn = SplitterHelper.addReturn(newMethod.instructions);
boolean fStatic = (method.access & Opcodes.ACC_STATIC) != 0;
InsnList parent = method.instructions;
InsnList child = newMethod.instructions;
AbstractInsnNode parameter = new LabelNode();
parent.insertBefore(label, parameter);
AbstractInsnNode aftercall = new LabelNode();
parent.insert(label, aftercall);
AbstractInsnNode iReturn = SplitterHelper.getReturn(child);
Frame<BasicValue> frame_start = frames_mapping.get(sb.start);
Frame<BasicValue> frame_end = frames_mapping.get(sb.end);
Map<Integer, Integer> mapping = new HashMap<Integer, Integer>();
Stack<Type> types = new Stack<Type>();
Type returnType = Type.VOID_TYPE;
int down = 0, top = 0;
for (LocalVar var : sb.usedVar) {
Type t = frame_start.getLocal(var.index).getType();
if (t == null || !sb.isParameter(var)) {
t = frame_end.getLocal(var.index).getType();
mapping.put(var.index, top);
top += t.getSize();
continue;
}
types.push(t);
down -= t.getSize();
mapping.put(var.index, down);
parent.insert(parameter, new VarInsnNode(
t.getOpcode(Opcodes.ILOAD), var.index));
if (!sb.needReturn(var)) {
continue;
}
if (!returnType.equals(Type.VOID_TYPE)) {
throw new DiSLFatalException("Method cannot return two values.");
}
returnType = t;
child.insertBefore(iReturn,
new VarInsnNode(t.getOpcode(Opcodes.ILOAD), var.index));
child.insertBefore(iReturn,
new InsnNode(t.getOpcode(Opcodes.IRETURN)));
child.remove(iReturn);
parent.insert(label, new VarInsnNode(t.getOpcode(Opcodes.ISTORE),
var.index));
}
if (!fStatic) {
down--;
mapping.put(0, down);
parent.insert(parameter, new VarInsnNode(Opcodes.ALOAD, 0));
}
for (Integer key : mapping.keySet()) {
mapping.put(key, mapping.get(key) - down);
}
for (AbstractInsnNode instr : newMethod.instructions.toArray()) {
if (instr instanceof VarInsnNode) {
VarInsnNode vin = (VarInsnNode) instr;
vin.var = mapping.get(vin.var);
} else if (instr instanceof IincInsnNode) {
IincInsnNode iin = (IincInsnNode) instr;
iin.var = mapping.get(iin.var);
}
}
newMethod.name = method.name + "$" + idx++;
if (!fReturn) {
returnType = Type.getReturnType(method.desc);
parent.insert(aftercall,
new InsnNode(returnType.getOpcode(Opcodes.IRETURN)));
}
newMethod.desc = Type.getMethodDescriptor(returnType,
types.toArray(new Type[types.size()]));
if (fStatic) {
parent.insertBefore(label, new MethodInsnNode(Opcodes.INVOKESTATIC,
clazz.name, newMethod.name, newMethod.desc));
} else {
parent.insertBefore(label, new MethodInsnNode(
Opcodes.INVOKEVIRTUAL, clazz.name, newMethod.name,
newMethod.desc));
}
newMethod.maxLocals = MaxCalculator.getMaxLocal(newMethod);
newMethod.maxStack = MaxCalculator.getMaxStack(newMethod);
}
public void split() {
if (superblocks.size() == 0) {
return;
}
for (SuperBlock sb : superblocks) {
if ((sb.getWeight() < 100) && sb.splitable()) {
MethodNode newMethod = new MethodNode();
newMethod.instructions = AsmHelper
.cloneInsnList(method.instructions);
newMethod.tryCatchBlocks = new LinkedList<>();
newMethod.access = method.access;
newMethod.exceptions = new LinkedList<>();
AbstractInsnNode label = fork(newMethod, sb);
complete(newMethod, sb, label);
clazz.methods.add(newMethod);
}
}
}
}
package ch.usi.dag.disl.weaver.splitter;
import java.util.LinkedList;
import java.util.List;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.InsnList;
import org.objectweb.asm.tree.InsnNode;
import org.objectweb.asm.tree.JumpInsnNode;
import org.objectweb.asm.tree.LabelNode;
public class SplitterHelper {
public static boolean addReturn(InsnList iList) {
for (AbstractInsnNode instr : iList.toArray()) {
int opcode = instr.getOpcode();
if (opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN) {
return false;
}
}
AbstractInsnNode end = iList.getLast();
iList.insert(end, new InsnNode(Opcodes.RETURN));
return true;
}
public static AbstractInsnNode getReturn(InsnList iList) {
List<AbstractInsnNode> returns = new LinkedList<>();
for (AbstractInsnNode instr : iList.toArray()) {
int opcode = instr.getOpcode();
if (opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN) {
returns.add(instr);
}
}
if (returns.size() == 1) {
return returns.get(0);
} else {
LabelNode label = new LabelNode();
AbstractInsnNode newReturn = new InsnNode(returns.get(0)
.getOpcode());
iList.add(label);
iList.add(newReturn);
for (AbstractInsnNode instr : returns) {
if (instr.getNext() != label) {
iList.insert(instr, new JumpInsnNode(Opcodes.GOTO, label));
}
iList.remove(instr);
}
return newReturn;
}
}
// http://en.wikipedia.org/wiki/Java_bytecode_instruction_listings
public static int getSize(AbstractInsnNode instr) {
switch (instr.getOpcode()) {
case Opcodes.ALOAD:
case Opcodes.ASTORE:
case Opcodes.BIPUSH:
case Opcodes.DLOAD:
case Opcodes.DSTORE:
case Opcodes.FLOAD:
case Opcodes.FSTORE:
case Opcodes.ILOAD:
case Opcodes.ISTORE:
case Opcodes.LDC: // LDC_W & LDC2_W takes 3 byte.
case Opcodes.LLOAD:
case Opcodes.LSTORE:
case Opcodes.NEWARRAY:
case Opcodes.RET:
return 2;
case Opcodes.ANEWARRAY:
case Opcodes.CHECKCAST:
case Opcodes.GETFIELD:
case Opcodes.GETSTATIC:
case Opcodes.GOTO: // GOTO_W takes 5 byte.
case Opcodes.IF_ACMPEQ:
case Opcodes.IF_ACMPNE:
case Opcodes.IF_ICMPEQ:
case Opcodes.IF_ICMPGE:
case Opcodes.IF_ICMPGT:
case Opcodes.IF_ICMPLE:
case Opcodes.IF_ICMPLT:
case Opcodes.IF_ICMPNE:
case Opcodes.IFEQ:
case Opcodes.IFGE:
case Opcodes.IFGT:
case Opcodes.IFLE:
case Opcodes.IFLT:
case Opcodes.IFNE:
case Opcodes.IFNONNULL:
case Opcodes.IFNULL:
case Opcodes.IINC:
case Opcodes.INSTANCEOF:
case Opcodes.INVOKESPECIAL:
case Opcodes.INVOKESTATIC:
case Opcodes.INVOKEVIRTUAL:
case Opcodes.JSR: // JSR_W takes 5 byte.
case Opcodes.NEW:
case Opcodes.PUTFIELD:
case Opcodes.PUTSTATIC:
case Opcodes.SIPUSH:
return 3;
case Opcodes.MULTIANEWARRAY:
return 4;
case Opcodes.INVOKEDYNAMIC:
case Opcodes.INVOKEINTERFACE:
return 5;
case Opcodes.LOOKUPSWITCH:
case Opcodes.TABLESWITCH:
return 5; // 4+
default:
return 1;
}
}
public static int getSize(SuperBlock sb) {
int total = 0;
for (AbstractInsnNode iter : sb) {
total += getSize(iter);
}
return total;
}
}
package ch.usi.dag.disl.weaver.splitter;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.MethodNode;
import org.objectweb.asm.tree.analysis.AnalyzerException;
import org.objectweb.asm.tree.analysis.BasicValue;
import org.objectweb.asm.tree.analysis.Frame;
import ch.usi.dag.disl.util.cfg.BasicBlock;
public class StatusAnalyzer {
private static StatusInterpreter interpreter = new StatusInterpreter();
public Map<AbstractInsnNode, Frame<FlagValue>> frames;
public Set<BasicBlock> visited;
public StatusAnalyzer() {
frames = new HashMap<AbstractInsnNode, Frame<FlagValue>>();
visited = new HashSet<BasicBlock>();
}
public boolean merge(AbstractInsnNode instr, Frame<FlagValue> frame)
throws AnalyzerException {
Frame<FlagValue> origin = frames.get(instr);
if (origin == null) {
frames.put(instr, frame);
return true;
}
return origin.merge(frame, interpreter);
}
public void analyze(Frame<FlagValue> frame, BasicBlock current,
BasicBlock exit) throws AnalyzerException {
if (current.getIndex() == exit.getIndex() + 1) {
return;
}
visited.add(current);
boolean changed = false;
for (AbstractInsnNode instr : current) {
frame = new Frame<FlagValue>(frame);
frame.execute(instr, interpreter);
changed = merge(instr, frame);
}
for (BasicBlock succ : current.getSuccessors()) {
if (!visited.contains(succ) || changed) {
analyze(frame, succ, exit);
}
}
}
public void analyze(MethodNode method, BasicBlock entrance,
BasicBlock exit, Map<AbstractInsnNode, Frame<BasicValue>> mapping)
throws AnalyzerException {
Frame<FlagValue> frame = createFrame(
mapping.get(entrance.getEntrance()), method);
analyze(frame, entrance, exit);
}
public static Frame<FlagValue> createFrame(Frame<BasicValue> basic,
MethodNode method) {
Frame<FlagValue> frame = new Frame<FlagValue>(method.maxLocals,
method.maxStack);
for (int i = 0; i < frame.getLocals(); i++) {
BasicValue value = basic.getLocal(i);
if (value != null) {
Type type = value.getType();
if (type != null) {
frame.setLocal(i, new FlagValue(type.getSize(), false));
}
}
}
return frame;
}
}
package ch.usi.dag.disl.weaver.splitter;
import java.util.List;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.FieldInsnNode;
import org.objectweb.asm.tree.InvokeDynamicInsnNode;
import org.objectweb.asm.tree.LdcInsnNode;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.analysis.Interpreter;
public class StatusInterpreter extends Interpreter<FlagValue> {
protected StatusInterpreter() {
super(Opcodes.ASM4);
}
@Override
public FlagValue newValue(final Type type) {
if (type == Type.VOID_TYPE) {
return null;
}
return new FlagValue(type == null ? 1 : type.getSize(), false);
}
@Override
public FlagValue newOperation(final AbstractInsnNode insn) {
switch (insn.getOpcode()) {
case Opcodes.ACONST_NULL:
case Opcodes.ICONST_M1:
case Opcodes.ICONST_0:
case Opcodes.ICONST_1:
case Opcodes.ICONST_2:
case Opcodes.ICONST_3:
case Opcodes.ICONST_4:
case Opcodes.ICONST_5:
case Opcodes.FCONST_0:
case Opcodes.FCONST_1:
case Opcodes.FCONST_2:
case Opcodes.BIPUSH:
case Opcodes.SIPUSH:
return new FlagValue(1, true);
case Opcodes.LCONST_0:
case Opcodes.LCONST_1:
case Opcodes.DCONST_0:
case Opcodes.DCONST_1:
return new FlagValue(2, true);
case Opcodes.LDC:
Object cst = ((LdcInsnNode) insn).cst;
return new FlagValue(
cst instanceof Long || cst instanceof Double ? 2 : 1, true);
case Opcodes.GETSTATIC:
return new FlagValue(Type.getType(((FieldInsnNode) insn).desc)
.getSize(), false);
case Opcodes.NEW:
return new FlagValue(1);
default:
return new FlagValue(1, false);
}
}
@Override
public FlagValue copyOperation(final AbstractInsnNode insn,
final FlagValue value) {
return value.clone();
}
@Override
public FlagValue unaryOperation(final AbstractInsnNode insn,
final FlagValue value) {
if (!value.getFlag()) {
switch (insn.getOpcode()) {
case Opcodes.LNEG:
case Opcodes.DNEG:
case Opcodes.I2L:
case Opcodes.I2D:
case Opcodes.L2D:
case Opcodes.F2L:
case Opcodes.F2D:
case Opcodes.D2L:
return new FlagValue(2, false);
case Opcodes.GETFIELD:
return new FlagValue(Type.getType(((FieldInsnNode) insn).desc)
.getSize(), false);
default:
return new FlagValue(1, false);
}
}
switch (insn.getOpcode()) {
case Opcodes.INEG:
case Opcodes.FNEG:
case Opcodes.IINC:
case Opcodes.I2F:
case Opcodes.L2I:
case Opcodes.L2F:
case Opcodes.F2I:
case Opcodes.D2I:
case Opcodes.D2F:
case Opcodes.I2B:
case Opcodes.I2C:
case Opcodes.I2S:
case Opcodes.IFEQ:
case Opcodes.IFNE: