Last active
November 6, 2016 06:16
-
-
Save Deamon5550/d48f81ec8aad3360576b61071b958fb7 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
private static enum CompareOps { | |
AND, | |
OR, | |
MID, | |
MID_OR | |
} | |
private static class ConditionResult { | |
public Condition condition; | |
int end; | |
int block_end; | |
} | |
private ConditionResult makeCondition(int index) { | |
int condition_start = index; | |
int condition_end = index; | |
for (; condition_end < this.intermediates.size(); condition_end++) { | |
IntermediateOpcode onext = this.intermediates.get(condition_end); | |
if (onext instanceof IntermediateStatement) { | |
condition_end--; | |
break; | |
} | |
} | |
Set<LabelNode> seen_labels = Sets.newHashSet(); | |
List<IntermediateOpcode> group = Lists.newArrayList(); | |
int farthest = 0; | |
for (int i = condition_start; i < condition_end; i++) { | |
IntermediateOpcode cnext = this.intermediates.get(i); | |
if (cnext instanceof IntermediateLabel) { | |
if (i == condition_end - 1) { | |
break; | |
} | |
boolean sharing = false; | |
for (int o = i + 1; o < condition_end; o++) { | |
IntermediateOpcode onext = this.intermediates.get(o); | |
if (onext instanceof IntermediateJump) { | |
LabelNode label = ((IntermediateJump) onext).getNode().label; | |
if (seen_labels.contains(label)) { | |
sharing = true; | |
break; | |
} | |
if (this.label_indices.get(label.getLabel()) > farthest) { | |
sharing = true; | |
break; | |
} | |
} else if (onext instanceof IntermediateLabel) { | |
break; | |
} | |
} | |
if (!sharing) { | |
for (int c = condition_start; c < i; c++) { | |
group.add(this.intermediates.get(c)); | |
} | |
condition_end = i; | |
farthest = -1; | |
break; | |
} | |
} else if (cnext instanceof IntermediateJump) { | |
LabelNode label = ((IntermediateJump) cnext).getNode().label; | |
seen_labels.add(label); | |
int target = this.label_indices.get(label.getLabel()); | |
if (target > farthest) { | |
farthest = target; | |
} | |
} | |
} | |
if (farthest != -1) { | |
for (int c = condition_start; c < condition_end; c++) { | |
group.add(this.intermediates.get(c)); | |
} | |
} | |
Condition condition = makeCondition(group); | |
LabelNode break_node = ((IntermediateJump) group.get(group.size() - 1)).getNode().label; | |
int block_end = this.label_indices.get(break_node.getLabel()); | |
ConditionResult result = new ConditionResult(); | |
result.condition = condition; | |
result.end = condition_end; | |
result.block_end = block_end; | |
return result; | |
} | |
private Condition makeCondition(List<IntermediateOpcode> group) { | |
int start = this.intermediates.indexOf(group.get(0)); | |
IntermediateOpcode last = group.get(group.size() - 1); | |
int end = this.intermediates.indexOf(last); | |
LabelNode break_node = ((IntermediateJump) group.get(group.size() - 1)).getNode().label; | |
Deque<Condition> stack = Queues.newArrayDeque(); | |
Deque<CompareOps> ops_stack = Queues.newArrayDeque(); | |
for (int i = 0; i < group.size(); i++) { | |
IntermediateOpcode next = group.get(i); | |
if (next instanceof IntermediateJump) { | |
JumpInsnNode node = ((IntermediateJump) next).getNode(); | |
if (node.label == break_node) { | |
if (next instanceof IntermediateConditionalJump) { | |
if (node.getOpcode() == IFEQ) { | |
stack.push(new BooleanCondition(((IntermediateConditionalJump) next).getCondition(), false)); | |
} else if (node.getOpcode() == IFNE) { | |
stack.push(new BooleanCondition(((IntermediateConditionalJump) next).getCondition(), true)); | |
} else if (node.getOpcode() == IFNULL) { | |
stack.push(new CompareCondition(((IntermediateConditionalJump) next).getCondition(), new NullConstantArg(), | |
CompareOp.NOT_EQUAL)); | |
} else if (node.getOpcode() == IFNONNULL) { | |
stack.push(new CompareCondition(((IntermediateConditionalJump) next).getCondition(), new NullConstantArg(), | |
CompareOp.EQUAL)); | |
} else { | |
stack.push(new CompareCondition(((IntermediateConditionalJump) next).getCondition(), new IntConstantArg(0), | |
CompareCondition.fromOpcode(node.getOpcode()).inverse())); | |
} | |
} else { | |
IntermediateCompareJump cmp = (IntermediateCompareJump) next; | |
stack.push(new CompareCondition(cmp.getLeft(), cmp.getRight(), CompareCondition.fromOpcode(node.getOpcode()).inverse())); | |
} | |
if (!ops_stack.isEmpty()) { | |
CompareOps op = ops_stack.peek(); | |
if (op == CompareOps.AND) { | |
ops_stack.pop(); | |
Condition left = stack.pop(); | |
Condition right = stack.pop(); | |
AndCondition cond = new AndCondition(right, left); | |
stack.push(cond); | |
} | |
if (i < group.size() - 1) { | |
if (group.get(i + 1) instanceof IntermediateLabel) { | |
CompareOps nop = ops_stack.peek(); | |
if (nop == CompareOps.OR || nop == CompareOps.MID) { | |
ops_stack.pop(); | |
Condition left = stack.pop(); | |
Condition right = new InverseCondition(stack.pop()); | |
OrCondition cond = new OrCondition(right, left); | |
stack.push(cond); | |
ops_stack.push(CompareOps.AND); | |
} | |
} else { | |
ops_stack.push(CompareOps.AND); | |
} | |
} | |
} else if (i < group.size() - 1) { | |
ops_stack.push(CompareOps.AND); | |
} | |
} else { | |
int jump_target = this.label_indices.get(node.label.getLabel()); | |
if (jump_target <= end && jump_target >= start) { | |
if (next instanceof IntermediateConditionalJump) { | |
if (node.getOpcode() == IFEQ) { | |
stack.push(new BooleanCondition(((IntermediateConditionalJump) next).getCondition(), false)); | |
} else if (node.getOpcode() == IFNE) { | |
stack.push(new BooleanCondition(((IntermediateConditionalJump) next).getCondition(), true)); | |
} else if (node.getOpcode() == IFNULL) { | |
stack.push(new CompareCondition(((IntermediateConditionalJump) next).getCondition(), new NullConstantArg(), | |
CompareOp.NOT_EQUAL)); | |
} else if (node.getOpcode() == IFNONNULL) { | |
stack.push(new CompareCondition(((IntermediateConditionalJump) next).getCondition(), new NullConstantArg(), | |
CompareOp.EQUAL)); | |
} else { | |
stack.push(new CompareCondition(((IntermediateConditionalJump) next).getCondition(), new IntConstantArg(0), | |
CompareCondition.fromOpcode(node.getOpcode()).inverse())); | |
} | |
} else { | |
IntermediateCompareJump cmp = (IntermediateCompareJump) next; | |
stack.push(new CompareCondition(cmp.getLeft(), cmp.getRight(), CompareCondition.fromOpcode(node.getOpcode()).inverse())); | |
} | |
if (ops_stack.peek() == CompareOps.MID) { | |
ops_stack.pop(); | |
Condition left = stack.pop(); | |
Condition right = new InverseCondition(stack.pop()); | |
OrCondition cond = new OrCondition(right, left); | |
stack.push(cond); | |
} | |
ops_stack.push(CompareOps.MID); | |
} else { | |
if (next instanceof IntermediateConditionalJump) { | |
if (node.getOpcode() == IFEQ) { | |
stack.push(new BooleanCondition(((IntermediateConditionalJump) next).getCondition(), true)); | |
} else if (node.getOpcode() == IFNE) { | |
stack.push(new BooleanCondition(((IntermediateConditionalJump) next).getCondition(), false)); | |
} else if (node.getOpcode() == IFNULL) { | |
stack.push(new CompareCondition(((IntermediateConditionalJump) next).getCondition(), new NullConstantArg(), | |
CompareOp.NOT_EQUAL)); | |
} else if (node.getOpcode() == IFNONNULL) { | |
stack.push(new CompareCondition(((IntermediateConditionalJump) next).getCondition(), new NullConstantArg(), | |
CompareOp.EQUAL)); | |
} else { | |
stack.push(new CompareCondition(((IntermediateConditionalJump) next).getCondition(), new IntConstantArg(0), | |
CompareCondition.fromOpcode(node.getOpcode()).inverse())); | |
} | |
} else { | |
IntermediateCompareJump cmp = (IntermediateCompareJump) next; | |
stack.push(new CompareCondition(cmp.getLeft(), cmp.getRight(), CompareCondition.fromOpcode(node.getOpcode()).inverse())); | |
} | |
if (ops_stack.peek() == CompareOps.MID) { | |
if (i < group.size() - 1 && group.get(i + 1) instanceof IntermediateLabel) { | |
ops_stack.pop(); | |
Condition left = stack.pop(); | |
Condition right = stack.pop(); | |
AndCondition cond = new AndCondition(right, left); | |
stack.push(cond); | |
} else { | |
ops_stack.pop(); | |
ops_stack.push(CompareOps.MID_OR); | |
} | |
} else if (ops_stack.peek() == CompareOps.MID_OR) { | |
ops_stack.pop(); | |
Condition left = stack.pop(); | |
Condition right = stack.pop(); | |
OrCondition cond = new OrCondition(right, left); | |
Condition right2 = stack.pop(); | |
AndCondition cond2 = new AndCondition(right2, cond); | |
stack.push(cond2); | |
} else { | |
ops_stack.push(CompareOps.OR); | |
} | |
} | |
} | |
} | |
} | |
while (!ops_stack.isEmpty()) { | |
Condition left = stack.pop(); | |
Condition right = stack.pop(); | |
CompareOps op = ops_stack.pop(); | |
if (op == CompareOps.AND) { | |
AndCondition cond = new AndCondition(right, left); | |
stack.push(cond); | |
} else if (op == CompareOps.OR) { | |
OrCondition cond = new OrCondition(right, left); | |
stack.push(cond); | |
} | |
} | |
if (stack.size() == 2) { | |
Condition left = stack.pop(); | |
Condition right = stack.pop(); | |
OrCondition cond = new OrCondition(right, left); | |
stack.push(cond); | |
} | |
return stack.pop(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment