allow control flow in induced cfgs, and various related fixes
This commit is contained in:
parent
d6ffcdc3bb
commit
dd3124479e
|
@ -664,7 +664,9 @@ public class RhinoToAstTranslator {
|
|||
}
|
||||
}
|
||||
|
||||
return Ast.makeNode(CAstNode.OBJECT_LITERAL, eltNodes.toArray(new CAstNode[eltNodes.size()]));
|
||||
CAstNode lit = Ast.makeNode(CAstNode.OBJECT_LITERAL, eltNodes.toArray(new CAstNode[eltNodes.size()]));
|
||||
arg.cfg().map(node, lit);
|
||||
return lit;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -787,9 +789,12 @@ public class RhinoToAstTranslator {
|
|||
result = get = Ast.makeNode(CAstNode.OBJECT_REF, obj, elt);
|
||||
}
|
||||
|
||||
if (get != null && context.getCatchTarget() != null) {
|
||||
if (get != null) {
|
||||
context.cfg().map(get, get);
|
||||
context.cfg().add(get, context.getCatchTarget(), JavaScriptTypes.TypeError);
|
||||
context.cfg().add(
|
||||
get,
|
||||
context.getCatchTarget() != null? context.getCatchTarget(): CAstControlFlowMap.EXCEPTION_TO_EXIT,
|
||||
JavaScriptTypes.TypeError);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -1178,7 +1183,10 @@ public class RhinoToAstTranslator {
|
|||
visit(label, context);
|
||||
args[i++] = visit(prop, context);
|
||||
}
|
||||
return Ast.makeNode(CAstNode.OBJECT_LITERAL, args);
|
||||
|
||||
CAstNode lit = Ast.makeNode(CAstNode.OBJECT_LITERAL, args);
|
||||
context.cfg().map(n, lit);
|
||||
return lit;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,4 +1,10 @@
|
|||
function f() {
|
||||
lbl:
|
||||
break lbl;
|
||||
function dead_code() {
|
||||
|
||||
}
|
||||
|
||||
function f() {
|
||||
lbl: {
|
||||
break lbl;
|
||||
dead_code();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -81,6 +81,15 @@ public abstract class TestSimpleCallGraphShape extends TestJSCallGraphShape {
|
|||
verifyGraphAssertions(CG, assertionsForObjects);
|
||||
}
|
||||
|
||||
private static final Object[][] cfgAssertionsForInherit = new Object[][] {
|
||||
new Object[]{"ctor:tests/inherit.js/objectMasquerading/Rectangle",
|
||||
new int[][]{{1,7},{2},{3,7},{4,7},{5,6},{7},{7}}
|
||||
},
|
||||
new Object[]{"ctor:tests/inherit.js/sharedClassObject/Rectangle",
|
||||
new int[][]{{1,7},{2},{3,7},{4,7},{5,6},{7},{7}}
|
||||
}
|
||||
};
|
||||
|
||||
private static final Object[][] assertionsForInherit = new Object[][] {
|
||||
new Object[] { ROOT, new String[] { "tests/inherit.js" } },
|
||||
new Object[] {
|
||||
|
@ -88,18 +97,26 @@ public abstract class TestSimpleCallGraphShape extends TestJSCallGraphShape {
|
|||
new String[] { "tests/inherit.js/objectMasquerading", "tests/inherit.js/objectMasquerading/Rectangle/area",
|
||||
"tests/inherit.js/Polygon/shape", "tests/inherit.js/sharedClassObject",
|
||||
"tests/inherit.js/sharedClassObject/Rectangle/area" } },
|
||||
/*
|
||||
* new Object[]{"tests/inherit.js/objectMasquerading", new
|
||||
* String[]{"ctor:tests/inherit.js/objectMasquerading/Rectangle"}}, new
|
||||
* Object[]{"tests/inherit.js/sharedClassObject", new
|
||||
* String[]{"ctor:tests/inherit.js/sharedClassObject/Rectangle"}},
|
||||
*/
|
||||
new Object[]{
|
||||
"tests/inherit.js/objectMasquerading",
|
||||
new String[]{"ctor:tests/inherit.js/objectMasquerading/Rectangle"}},
|
||||
new Object[]{
|
||||
"ctor:tests/inherit.js/objectMasquerading/Rectangle" ,
|
||||
new String[]{"tests/inherit.js/objectMasquerading/Rectangle"}},
|
||||
new Object[]{"tests/inherit.js/objectMasquerading/Rectangle",
|
||||
new String[]{"tests/inherit.js/Polygon"}},
|
||||
new Object[]{
|
||||
"tests/inherit.js/sharedClassObject",
|
||||
new String[]{"ctor:tests/inherit.js/sharedClassObject/Rectangle"}},
|
||||
new Object[]{"ctor:tests/inherit.js/sharedClassObject/Rectangle",
|
||||
new String[]{"tests/inherit.js/sharedClassObject/Rectangle"}}
|
||||
};
|
||||
|
||||
@Test
|
||||
public void testInherit() throws IOException, IllegalArgumentException, CancelException, WalaException {
|
||||
CallGraph CG = JSCallGraphBuilderUtil.makeScriptCG("tests", "inherit.js");
|
||||
verifyGraphAssertions(CG, assertionsForInherit);
|
||||
verifyCFGAssertions(CG, cfgAssertionsForInherit);
|
||||
}
|
||||
|
||||
private static final Object[][] assertionsForNewfn = new Object[][] {
|
||||
|
|
|
@ -69,13 +69,15 @@ public class WebPageLoaderFactory extends JavaScriptLoaderFactory {
|
|||
translateConditionOpcode(CAstOperator.OP_NE),
|
||||
null,
|
||||
isDefined,
|
||||
context.currentScope().getConstantValue(new Integer(0))));
|
||||
context.currentScope().getConstantValue(new Integer(0)),
|
||||
-1));
|
||||
PreBasicBlock srcB = context.cfg().getCurrentBlock();
|
||||
|
||||
// field lookup of value
|
||||
context.cfg().newBlock(true);
|
||||
context.cfg().addInstruction(((JSInstructionFactory) insts).GetInstruction(result, windowVal, name));
|
||||
context.cfg().addInstruction(insts.GotoInstruction());
|
||||
context.cfg().newBlock(true);
|
||||
context.cfg().addInstruction(insts.GotoInstruction(-1));
|
||||
PreBasicBlock trueB = context.cfg().getCurrentBlock();
|
||||
|
||||
// read global
|
||||
|
|
|
@ -295,16 +295,16 @@ public class ClosureExtractor extends CAstRewriterExt {
|
|||
epos.addGotoTarget(root.getChildCount() > 0 ? (String)root.getChild(0).getValue(): null, target);
|
||||
int label = labeller.addNode(target);
|
||||
// return { type: 'goto', target: <label> }
|
||||
CAstNode newNode =
|
||||
Ast.makeNode(RETURN,
|
||||
Ast.makeNode(OBJECT_LITERAL,
|
||||
addExnFlow(Ast.makeNode(CALL,
|
||||
addExnFlow(makeVarRef("Object"), JavaScriptTypes.ReferenceError, getCurrentEntity(), context),
|
||||
Ast.makeConstant("ctor")), null, getCurrentEntity(), context),
|
||||
Ast.makeConstant("type"),
|
||||
Ast.makeConstant("goto"),
|
||||
Ast.makeConstant("target"),
|
||||
Ast.makeConstant(((double)label)+"")));
|
||||
CAstNode returnLit = Ast.makeNode(OBJECT_LITERAL,
|
||||
addExnFlow(Ast.makeNode(CALL,
|
||||
addExnFlow(makeVarRef("Object"), JavaScriptTypes.ReferenceError, getCurrentEntity(), context),
|
||||
Ast.makeConstant("ctor")), null, getCurrentEntity(), context),
|
||||
Ast.makeConstant("type"),
|
||||
Ast.makeConstant("goto"),
|
||||
Ast.makeConstant("target"),
|
||||
Ast.makeConstant(((double)label)+""));
|
||||
addNode(returnLit, getCurrentEntity().getControlFlow());
|
||||
CAstNode newNode = Ast.makeNode(RETURN, returnLit);
|
||||
// remove outgoing cfg edges of the old node
|
||||
deleteFlow(root, getCurrentEntity());
|
||||
nodeMap.put(Pair.make(root, context.key()), newNode);
|
||||
|
|
|
@ -19,6 +19,8 @@ import com.ibm.wala.classLoader.IMethod;
|
|||
import com.ibm.wala.classLoader.NewSiteReference;
|
||||
import com.ibm.wala.ipa.cha.IClassHierarchy;
|
||||
import com.ibm.wala.ipa.summaries.MethodSummary;
|
||||
import com.ibm.wala.shrikeBT.IConditionalBranchInstruction.IOperator;
|
||||
import com.ibm.wala.shrikeBT.IConditionalBranchInstruction.Operator;
|
||||
import com.ibm.wala.ssa.ConstantValue;
|
||||
import com.ibm.wala.ssa.IR;
|
||||
import com.ibm.wala.ssa.SSAAbstractInvokeInstruction;
|
||||
|
@ -459,8 +461,6 @@ public class JavaScriptConstructorFunctions {
|
|||
Object key = Pair.make(cls, new Integer(nargs));
|
||||
if (constructors.containsKey(key))
|
||||
return constructors.get(key);
|
||||
|
||||
System.err.println(cls);
|
||||
|
||||
MethodReference ref = JavaScriptMethods.makeCtorReference(cls.getReference());
|
||||
JavaScriptSummary S = new JavaScriptSummary(ref, nargs + 1);
|
||||
|
@ -473,7 +473,6 @@ public class JavaScriptConstructorFunctions {
|
|||
JavaScriptTypes.Object)));
|
||||
|
||||
S.addStatement(insts.SetPrototype(nargs + 5, nargs + 4));
|
||||
//S.addStatement(insts.PutInstruction(nargs + 5, nargs + 4, "__proto__"));
|
||||
S.getNextProgramCounter();
|
||||
|
||||
CallSiteReference cs = new JSCallSiteReference(S.getNextProgramCounter());
|
||||
|
@ -482,15 +481,18 @@ public class JavaScriptConstructorFunctions {
|
|||
for (int i = 0; i < nargs; i++)
|
||||
args[i + 1] = i + 2;
|
||||
S.addStatement(insts.Invoke(1, nargs + 7, args, nargs + 8, cs));
|
||||
int pc = S.getNextProgramCounter();
|
||||
|
||||
S.addConstant(nargs + 9, null);
|
||||
S.addStatement(insts.ConditionalBranchInstruction(Operator.EQ, JavaScriptTypes.Root, nargs + 7, nargs + 9, pc+2));
|
||||
S.getNextProgramCounter();
|
||||
|
||||
S.addStatement(insts.ReturnInstruction(nargs + 7, false));
|
||||
S.getNextProgramCounter();
|
||||
|
||||
S.addStatement(insts.ReturnInstruction(nargs + 5, false));
|
||||
S.getNextProgramCounter();
|
||||
|
||||
//S.addConstant(nargs + 9, new ConstantValue("__proto__"));
|
||||
|
||||
return record(key, new JavaScriptConstructor(ref, S, cls, cls));
|
||||
}
|
||||
|
||||
|
|
|
@ -421,8 +421,8 @@ public class JavaScriptLoader extends CAstAbstractModuleLoader {
|
|||
|
||||
@Override
|
||||
public SSAConditionalBranchInstruction ConditionalBranchInstruction(
|
||||
com.ibm.wala.shrikeBT.IConditionalBranchInstruction.IOperator operator, TypeReference type, int val1, int val2) {
|
||||
return new SSAConditionalBranchInstruction(operator, type, val1, val2);
|
||||
com.ibm.wala.shrikeBT.IConditionalBranchInstruction.IOperator operator, TypeReference type, int val1, int val2, int target) {
|
||||
return new SSAConditionalBranchInstruction(operator, type, val1, val2, target);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -462,8 +462,8 @@ public class JavaScriptLoader extends CAstAbstractModuleLoader {
|
|||
}
|
||||
|
||||
@Override
|
||||
public SSAGotoInstruction GotoInstruction() {
|
||||
return new SSAGotoInstruction();
|
||||
public SSAGotoInstruction GotoInstruction(int target) {
|
||||
return new SSAGotoInstruction(target);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -258,17 +258,15 @@ public class JSAstTranslator extends AstTranslator {
|
|||
context.cfg().addInstruction(((JSInstructionFactory) insts).PropertyRead(result, x, context.getValue(elt)));
|
||||
}
|
||||
|
||||
// generate code to handle read of non-existent property
|
||||
if (context.getControlFlow().getMappedNodes().contains(readNode)) {
|
||||
context.cfg().addPreNode(readNode, context.getUnwindState());
|
||||
// generate code to handle read of property from null or undefined
|
||||
context.cfg().addPreNode(readNode, context.getUnwindState());
|
||||
|
||||
context.cfg().newBlock(true);
|
||||
context.cfg().newBlock(true);
|
||||
|
||||
if (context.getControlFlow().getTarget(readNode, JavaScriptTypes.TypeError) != null)
|
||||
context.cfg().addPreEdge(readNode, context.getControlFlow().getTarget(readNode, JavaScriptTypes.TypeError), true);
|
||||
else
|
||||
context.cfg().addPreEdgeToExit(readNode, true);
|
||||
}
|
||||
if (context.getControlFlow().getTarget(readNode, JavaScriptTypes.TypeError) != null)
|
||||
context.cfg().addPreEdge(readNode, context.getControlFlow().getTarget(readNode, JavaScriptTypes.TypeError), true);
|
||||
else
|
||||
context.cfg().addPreEdgeToExit(readNode, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -293,9 +291,18 @@ public class JSAstTranslator extends AstTranslator {
|
|||
context.cfg().addInstruction(put);
|
||||
}
|
||||
} else {
|
||||
*/
|
||||
*/
|
||||
context.cfg().addInstruction(((JSInstructionFactory) insts).PropertyWrite(receiver, context.getValue(elt), rval));
|
||||
// }
|
||||
context.cfg().addPreNode(parent, context.getUnwindState());
|
||||
|
||||
// generate code to handle read of property from null or undefined
|
||||
context.cfg().newBlock(true);
|
||||
|
||||
if (context.getControlFlow().getTarget(parent, JavaScriptTypes.TypeError) != null)
|
||||
context.cfg().addPreEdge(parent, context.getControlFlow().getTarget(parent, JavaScriptTypes.TypeError), true);
|
||||
else
|
||||
context.cfg().addPreEdgeToExit(parent, true);
|
||||
// }
|
||||
}
|
||||
|
||||
private void doPrimitiveNew(WalkContext context, int resultVal, String typeName) {
|
||||
|
|
|
@ -22,11 +22,29 @@ import com.ibm.wala.core.tests.util.WalaTestCase;
|
|||
import com.ibm.wala.ipa.callgraph.CGNode;
|
||||
import com.ibm.wala.ipa.callgraph.CallGraph;
|
||||
import com.ibm.wala.ssa.IR;
|
||||
import com.ibm.wala.ssa.SSACFG;
|
||||
import com.ibm.wala.ssa.SSAInstruction;
|
||||
import com.ibm.wala.util.collections.NonNullSingletonIterator;
|
||||
|
||||
public abstract class TestCallGraphShape extends WalaTestCase {
|
||||
|
||||
protected void verifyCFGAssertions(CallGraph CG, Object[][] assertionData) {
|
||||
for(Object[] dat : assertionData) {
|
||||
String function = (String) dat[0];
|
||||
for(CGNode N : getNodes(CG, function)) {
|
||||
int[][] edges = (int[][]) dat[1];
|
||||
SSACFG cfg = N.getIR().getControlFlowGraph();
|
||||
for (int i = 0; i < edges.length; i++) {
|
||||
SSACFG.BasicBlock bb = cfg.getNode(i);
|
||||
Assert.assertEquals("basic block " + i, edges[i].length, cfg.getSuccNodeCount(bb));
|
||||
for (int j = 0; j < edges[i].length; j++) {
|
||||
Assert.assertTrue(cfg.hasEdge(bb, cfg.getNode(edges[i][j])));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void verifySourceAssertions(CallGraph CG, Object[][] assertionData) {
|
||||
for(Object[] dat : assertionData) {
|
||||
String function = (String) dat[0];
|
||||
|
|
|
@ -22,6 +22,7 @@ import com.ibm.wala.cast.ir.ssa.analysis.LiveAnalysis;
|
|||
import com.ibm.wala.cast.loader.AstMethod;
|
||||
import com.ibm.wala.cast.loader.AstMethod.DebuggingInformation;
|
||||
import com.ibm.wala.cast.loader.AstMethod.LexicalInformation;
|
||||
import com.ibm.wala.cast.tree.CAstType.Array;
|
||||
import com.ibm.wala.ssa.IR.SSA2LocalMap;
|
||||
import com.ibm.wala.ssa.SSACFG;
|
||||
import com.ibm.wala.ssa.SSAInstruction;
|
||||
|
@ -34,6 +35,7 @@ import com.ibm.wala.util.collections.Pair;
|
|||
import com.ibm.wala.util.intset.BitVector;
|
||||
import com.ibm.wala.util.intset.BitVectorIntSet;
|
||||
import com.ibm.wala.util.intset.IntSet;
|
||||
import com.ibm.wala.util.intset.IntSetUtil;
|
||||
import com.ibm.wala.util.intset.MutableIntSet;
|
||||
|
||||
/**
|
||||
|
@ -264,22 +266,30 @@ public class SSAConversion extends AbstractSSAConversion {
|
|||
// SSA2LocalMap implementation for SSAConversion
|
||||
//
|
||||
private class SSAInformation implements com.ibm.wala.ssa.IR.SSA2LocalMap {
|
||||
|
||||
private final String[][] computedNames = new String[valueMap.length][];
|
||||
|
||||
@Override
|
||||
public String[] getLocalNames(int pc, int vn) {
|
||||
|
||||
if (computedNames[vn] != null) {
|
||||
return computedNames[vn];
|
||||
}
|
||||
|
||||
int v = skip(vn) || vn >= valueMap.length ? vn : valueMap[vn];
|
||||
String[][] namesData = debugInfo.getSourceNamesForValues();
|
||||
String[] vNames = namesData[v];
|
||||
Set<String> x = HashSetFactory.make();
|
||||
x.addAll(Arrays.asList(vNames));
|
||||
|
||||
while (assignments.containsKey(v)) {
|
||||
MutableIntSet vals = IntSetUtil.make();
|
||||
while (assignments.containsKey(v) && !vals.contains(v)) {
|
||||
vals.add(v);
|
||||
v = assignments.get(v);
|
||||
vNames = namesData[v];
|
||||
x.addAll(Arrays.asList(vNames));
|
||||
}
|
||||
|
||||
return x.toArray(new String[x.size()]);
|
||||
return computedNames[vn] = x.toArray(new String[x.size()]);
|
||||
}
|
||||
|
||||
private void undoCopyPropagation(int instructionIndex, int useNumber) {
|
||||
|
|
|
@ -68,6 +68,7 @@ import com.ibm.wala.shrikeBT.IConditionalBranchInstruction;
|
|||
import com.ibm.wala.shrikeBT.IUnaryOpInstruction;
|
||||
import com.ibm.wala.shrikeBT.ShiftInstruction;
|
||||
import com.ibm.wala.ssa.SSAAbstractInvokeInstruction;
|
||||
import com.ibm.wala.ssa.SSAConditionalBranchInstruction;
|
||||
import com.ibm.wala.ssa.SSAGetCaughtExceptionInstruction;
|
||||
import com.ibm.wala.ssa.SSAGotoInstruction;
|
||||
import com.ibm.wala.ssa.SSAInstruction;
|
||||
|
@ -698,6 +699,7 @@ public abstract class AstTranslator extends CAstVisitor<AstTranslator.WalkContex
|
|||
* holds the control-flow graph as it is being constructed. When construction
|
||||
* is complete, information is stored in an {@link AstCFG}
|
||||
*/
|
||||
@SuppressWarnings("javadoc")
|
||||
public final class IncipientCFG extends SparseNumberedGraph<PreBasicBlock> {
|
||||
|
||||
protected class Unwind {
|
||||
|
@ -751,7 +753,7 @@ public abstract class AstTranslator extends CAstVisitor<AstTranslator.WalkContex
|
|||
int e = -1;
|
||||
PreBasicBlock currentBlock = getCurrentBlock();
|
||||
if (!isDeadBlock(currentBlock)) {
|
||||
addInstruction(insts.GotoInstruction());
|
||||
addInstruction(insts.GotoInstruction(-1));
|
||||
newBlock(false);
|
||||
}
|
||||
PreBasicBlock startBlock = getCurrentBlock();
|
||||
|
@ -795,7 +797,7 @@ public abstract class AstTranslator extends CAstVisitor<AstTranslator.WalkContex
|
|||
addPreNode(dummy);
|
||||
doThrow(astContext, e);
|
||||
} else {
|
||||
addInstruction(insts.GotoInstruction());
|
||||
addInstruction(insts.GotoInstruction(-1));
|
||||
}
|
||||
newBlock(false);
|
||||
|
||||
|
@ -1277,7 +1279,35 @@ public abstract class AstTranslator extends CAstVisitor<AstTranslator.WalkContex
|
|||
if (ci.getBasicBlockNumber() != blocks.get(i).getNumber()) {
|
||||
inst = insts.GetCaughtExceptionInstruction(blocks.get(i).getNumber(), ci.getException());
|
||||
}
|
||||
} else if (inst instanceof SSAGotoInstruction) {
|
||||
Iterator<PreBasicBlock> succs = this.getNormalSuccessors(blocks.get(i)).iterator();
|
||||
if (succs.hasNext()) {
|
||||
PreBasicBlock target = succs.next();
|
||||
assert !succs.hasNext() : "unexpected successors for block " + blocks.get(i) + ": " + target + " and " + succs.next();
|
||||
inst = insts.GotoInstruction(target.firstIndex);
|
||||
} else {
|
||||
// goto to the end of the method, so the instruction is unnecessary
|
||||
inst = null;
|
||||
}
|
||||
} else if (inst instanceof SSAConditionalBranchInstruction) {
|
||||
Iterator<PreBasicBlock> succs = this.getNormalSuccessors(blocks.get(i)).iterator();
|
||||
assert succs.hasNext();
|
||||
int target;
|
||||
int t1 = succs.next().firstIndex;
|
||||
if (succs.hasNext()) {
|
||||
int t2 = succs.next().firstIndex;
|
||||
if (t1 == x+1) {
|
||||
target = t2;
|
||||
} else {
|
||||
target = t1;
|
||||
}
|
||||
} else {
|
||||
target = t1;
|
||||
}
|
||||
SSAConditionalBranchInstruction branch = (SSAConditionalBranchInstruction) inst;
|
||||
inst = insts.ConditionalBranchInstruction(branch.getOperator(), branch.getType(), branch.getUse(0), branch.getUse(1), target);
|
||||
}
|
||||
|
||||
instructions[x++] = inst;
|
||||
}
|
||||
}
|
||||
|
@ -3451,14 +3481,14 @@ public abstract class AstTranslator extends CAstVisitor<AstTranslator.WalkContex
|
|||
+ " of loop " + CAstPrinter.print(n, context.top().getSourceMap());
|
||||
context.cfg().addInstruction(
|
||||
insts.ConditionalBranchInstruction(translateConditionOpcode(CAstOperator.OP_EQ), null, c.getValue(n.getChild(0)), context
|
||||
.currentScope().getConstantValue(new Integer(0))));
|
||||
.currentScope().getConstantValue(new Integer(0)), -1));
|
||||
PreBasicBlock branchB = context.cfg().getCurrentBlock();
|
||||
|
||||
// loop body
|
||||
context.cfg().newBlock(true);
|
||||
visitor.visit(n.getChild(1), context, visitor);
|
||||
if (!context.cfg().isDeadBlock(context.cfg().getCurrentBlock())) {
|
||||
context.cfg().addInstruction(insts.GotoInstruction());
|
||||
context.cfg().addInstruction(insts.GotoInstruction(-1));
|
||||
PreBasicBlock bodyB = context.cfg().getCurrentBlock();
|
||||
context.cfg().addEdge(bodyB, headerB);
|
||||
|
||||
|
@ -3727,11 +3757,11 @@ public abstract class AstTranslator extends CAstVisitor<AstTranslator.WalkContex
|
|||
if (n.getChildCount() == 1) {
|
||||
context.cfg().addInstruction(
|
||||
insts.ConditionalBranchInstruction(translateConditionOpcode(CAstOperator.OP_NE), null, c.getValue(n.getChild(0)), context
|
||||
.currentScope().getConstantValue(new Integer(0))));
|
||||
.currentScope().getConstantValue(new Integer(0)), -1));
|
||||
} else if (n.getChildCount() == 3) {
|
||||
context.cfg().addInstruction(
|
||||
insts.ConditionalBranchInstruction(translateConditionOpcode(n.getChild(0)), null, c.getValue(n.getChild(1)),
|
||||
c.getValue(n.getChild(2))));
|
||||
c.getValue(n.getChild(2)), -1));
|
||||
} else {
|
||||
Assertions.UNREACHABLE();
|
||||
}
|
||||
|
@ -3752,7 +3782,7 @@ public abstract class AstTranslator extends CAstVisitor<AstTranslator.WalkContex
|
|||
if (!context.cfg().isDeadBlock(context.cfg().getCurrentBlock())) {
|
||||
context.cfg().addPreNode(n, context.getUnwindState());
|
||||
context.cfg().addPreEdge(n, context.getControlFlow().getTarget(n, null), false);
|
||||
context.cfg().addInstruction(insts.GotoInstruction());
|
||||
context.cfg().addInstruction(insts.GotoInstruction(-1));
|
||||
if (context.getControlFlow().getTarget(n, null) == null) {
|
||||
assert context.getControlFlow().getTarget(n, null) != null : context.getControlFlow() + " does not map " + n + " ("
|
||||
+ context.getSourceMap().getPosition(n) + ")";
|
||||
|
@ -3783,7 +3813,7 @@ public abstract class AstTranslator extends CAstVisitor<AstTranslator.WalkContex
|
|||
visitor.visit(l, context, visitor);
|
||||
context.cfg().addInstruction(
|
||||
insts.ConditionalBranchInstruction(translateConditionOpcode(CAstOperator.OP_EQ), null, c.getValue(l), context.currentScope()
|
||||
.getConstantValue(new Integer(0))));
|
||||
.getConstantValue(new Integer(0)), -1));
|
||||
PreBasicBlock srcB = context.cfg().getCurrentBlock();
|
||||
// true clause
|
||||
context.cfg().newBlock(true);
|
||||
|
@ -3793,7 +3823,7 @@ public abstract class AstTranslator extends CAstVisitor<AstTranslator.WalkContex
|
|||
context.cfg().addInstruction(new AssignInstruction(c.getValue(n), c.getValue(r)));
|
||||
if (n.getChildCount() == 3) {
|
||||
if (!context.cfg().isDeadBlock(context.cfg().getCurrentBlock())) {
|
||||
context.cfg().addInstruction(insts.GotoInstruction());
|
||||
context.cfg().addInstruction(insts.GotoInstruction(-1));
|
||||
trueB = context.cfg().getCurrentBlock();
|
||||
|
||||
// false clause
|
||||
|
@ -4184,7 +4214,7 @@ public abstract class AstTranslator extends CAstVisitor<AstTranslator.WalkContex
|
|||
// PreBasicBlock switchB = context.cfg().getCurrentBlock();
|
||||
context.cfg().newBlock(true);
|
||||
|
||||
context.cfg().addInstruction(insts.GotoInstruction());
|
||||
context.cfg().addInstruction(insts.GotoInstruction(-1));
|
||||
defaultHackBlock = context.cfg().getCurrentBlock();
|
||||
context.cfg().newBlock(false);
|
||||
|
||||
|
@ -4228,14 +4258,14 @@ public abstract class AstTranslator extends CAstVisitor<AstTranslator.WalkContex
|
|||
if (x != CAstControlFlowMap.SWITCH_DEFAULT) {
|
||||
visitor.visit((CAstNode) x, context, visitor);
|
||||
context.cfg().addInstruction(
|
||||
insts.ConditionalBranchInstruction(translateConditionOpcode(CAstOperator.OP_EQ), null, v, context.getValue((CAstNode) x)));
|
||||
insts.ConditionalBranchInstruction(translateConditionOpcode(CAstOperator.OP_EQ), null, v, context.getValue((CAstNode) x), -1));
|
||||
labelToBlock.put(x, context.cfg().getCurrentBlock());
|
||||
context.cfg().newBlock(true);
|
||||
}
|
||||
}
|
||||
|
||||
PreBasicBlock defaultGotoBlock = context.cfg().getCurrentBlock();
|
||||
context.cfg().addInstruction(insts.GotoInstruction());
|
||||
context.cfg().addInstruction(insts.GotoInstruction(-1));
|
||||
context.cfg().newBlock(false);
|
||||
|
||||
CAstNode switchBody = n.getChild(1);
|
||||
|
@ -4381,7 +4411,7 @@ public abstract class AstTranslator extends CAstVisitor<AstTranslator.WalkContex
|
|||
|
||||
if (!context.cfg().isDeadBlock(context.cfg().getCurrentBlock())) {
|
||||
addSkipCatchGoto = true;
|
||||
context.cfg().addInstruction(insts.GotoInstruction());
|
||||
context.cfg().addInstruction(insts.GotoInstruction(-1));
|
||||
context.cfg().newBlock(false);
|
||||
}
|
||||
|
||||
|
|
|
@ -78,7 +78,7 @@ public class CAstImpl implements CAst {
|
|||
@Override
|
||||
public int hashCode() {
|
||||
int code = getKind() * (getChildCount() + 13);
|
||||
for (int i = 0; i < getChildCount(); i++) {
|
||||
for (int i = 0; i < getChildCount() && i < 15; i++) {
|
||||
code *= getChild(i).getKind();
|
||||
}
|
||||
|
||||
|
|
|
@ -234,24 +234,21 @@ public class InducedCFG extends AbstractCFG<SSAInstruction, InducedCFG.BasicBloc
|
|||
|
||||
@Override
|
||||
public void visitGoto(SSAGotoInstruction instruction) {
|
||||
Assertions.UNREACHABLE("haven't implemented logic for goto yet.");
|
||||
breakBasicBlock(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitConditionalBranch(SSAConditionalBranchInstruction instruction) {
|
||||
Assertions.UNREACHABLE("haven't implemented logic for cbranch yet.");
|
||||
breakBasicBlock(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitSwitch(SSASwitchInstruction instruction) {
|
||||
Assertions.UNREACHABLE("haven't implemented logic for switch yet.");
|
||||
// breakBasicBlock();
|
||||
// int[] targets = instruction.getTargets();
|
||||
// for (int i = 0; i < targets.length; i++) {
|
||||
// r[targets[i]] = true;
|
||||
// }
|
||||
breakBasicBlock(index);
|
||||
int[] targets = instruction.getCasesAndLabels();
|
||||
for (int i = 1; i < targets.length; i+=2) {
|
||||
r[targets[i]] = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -448,20 +445,30 @@ public class InducedCFG extends AbstractCFG<SSAInstruction, InducedCFG.BasicBloc
|
|||
|
||||
SSAInstruction last = getInstructions()[getLastInstructionIndex()];
|
||||
addExceptionalEdges(last);
|
||||
// this CFG is odd in that we assume fallthru might always
|
||||
// happen .. this is because I'm too lazy to code control
|
||||
// flow in all method summaries yet.
|
||||
|
||||
int normalSuccNodeNumber = getGraphNodeId() + 1;
|
||||
if (true) {
|
||||
// if (last.isFallThrough()) {
|
||||
if (last.isFallThrough()) {
|
||||
if (DEBUG) {
|
||||
System.err.println(("Add fallthru to " + getNode(getGraphNodeId() + 1)));
|
||||
}
|
||||
addNormalEdgeTo(getNode(normalSuccNodeNumber));
|
||||
}
|
||||
|
||||
if (last instanceof SSAGotoInstruction) {
|
||||
addNormalEdgeTo(getBlockForInstruction(((SSAGotoInstruction)last).getTarget()));
|
||||
} else if (last instanceof SSAConditionalBranchInstruction) {
|
||||
addNormalEdgeTo(getBlockForInstruction(((SSAConditionalBranchInstruction)last).getTarget()));
|
||||
} else if (last instanceof SSASwitchInstruction) {
|
||||
int[] targets = ((SSASwitchInstruction) last).getCasesAndLabels();
|
||||
for (int i = 1; i < targets.length; i+=2) {
|
||||
addNormalEdgeTo(getBlockForInstruction(targets[i]));
|
||||
}
|
||||
}
|
||||
|
||||
if (pis != null) {
|
||||
updatePiInstrs(normalSuccNodeNumber);
|
||||
}
|
||||
|
||||
if (last instanceof SSAReturnInstruction) {
|
||||
// link each return instrution to the exit block.
|
||||
BasicBlock exit = exit();
|
||||
|
|
|
@ -168,8 +168,8 @@ public class JavaLanguage extends LanguageImpl implements BytecodeLanguage, Cons
|
|||
|
||||
@Override
|
||||
public SSAConditionalBranchInstruction ConditionalBranchInstruction(IConditionalBranchInstruction.IOperator operator,
|
||||
TypeReference type, int val1, int val2) {
|
||||
return new SSAConditionalBranchInstruction(operator, type, val1, val2);
|
||||
TypeReference type, int val1, int val2, int target) {
|
||||
return new SSAConditionalBranchInstruction(operator, type, val1, val2, target);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -210,8 +210,8 @@ public class JavaLanguage extends LanguageImpl implements BytecodeLanguage, Cons
|
|||
}
|
||||
|
||||
@Override
|
||||
public SSAGotoInstruction GotoInstruction() {
|
||||
return new SSAGotoInstruction();
|
||||
public SSAGotoInstruction GotoInstruction(int target) {
|
||||
return new SSAGotoInstruction(target);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -480,7 +480,7 @@ public class SSABuilder extends AbstractIntStackMachine {
|
|||
int val1 = workingState.pop();
|
||||
|
||||
TypeReference t = ShrikeUtil.makeTypeReference(loader, instruction.getType());
|
||||
emitInstruction(insts.ConditionalBranchInstruction(instruction.getOperator(), t, val1, val2));
|
||||
emitInstruction(insts.ConditionalBranchInstruction(instruction.getOperator(), t, val1, val2, instruction.getTarget()));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -560,7 +560,7 @@ public class SSABuilder extends AbstractIntStackMachine {
|
|||
*/
|
||||
@Override
|
||||
public void visitGoto(com.ibm.wala.shrikeBT.GotoInstruction instruction) {
|
||||
emitInstruction(insts.GotoInstruction());
|
||||
emitInstruction(insts.GotoInstruction(instruction.getLabel()));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -26,9 +26,12 @@ public class SSAConditionalBranchInstruction extends SSAInstruction {
|
|||
|
||||
private final TypeReference type;
|
||||
|
||||
public SSAConditionalBranchInstruction(IConditionalBranchInstruction.IOperator operator, TypeReference type, int val1, int val2)
|
||||
final private int target;
|
||||
|
||||
public SSAConditionalBranchInstruction(IConditionalBranchInstruction.IOperator operator, TypeReference type, int val1, int val2, int target)
|
||||
throws IllegalArgumentException {
|
||||
super();
|
||||
this.target = target;
|
||||
this.operator = operator;
|
||||
this.val1 = val1;
|
||||
this.val2 = val2;
|
||||
|
@ -41,12 +44,16 @@ public class SSAConditionalBranchInstruction extends SSAInstruction {
|
|||
}
|
||||
}
|
||||
|
||||
public int getTarget() {
|
||||
return target;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SSAInstruction copyForSSA(SSAInstructionFactory insts, int[] defs, int[] uses) throws IllegalArgumentException {
|
||||
if (uses != null && uses.length < 2) {
|
||||
throw new IllegalArgumentException("(uses != null) and (uses.length < 2)");
|
||||
}
|
||||
return insts.ConditionalBranchInstruction(operator, type, uses == null ? val1 : uses[0], uses == null ? val2 : uses[1]);
|
||||
return insts.ConditionalBranchInstruction(operator, type, uses == null ? val1 : uses[0], uses == null ? val2 : uses[1], target);
|
||||
}
|
||||
|
||||
public IConditionalBranchInstruction.IOperator getOperator() {
|
||||
|
|
|
@ -14,14 +14,18 @@ package com.ibm.wala.ssa;
|
|||
* Unconditional branch instruction for SSA form.
|
||||
*/
|
||||
public class SSAGotoInstruction extends SSAInstruction {
|
||||
private final int target;
|
||||
public SSAGotoInstruction(int target) {
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
public SSAGotoInstruction() {
|
||||
super();
|
||||
public int getTarget() {
|
||||
return target;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SSAInstruction copyForSSA(SSAInstructionFactory insts, int[] defs, int[] uses) {
|
||||
return insts.GotoInstruction();
|
||||
return insts.GotoInstruction(target);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -51,7 +51,7 @@ public interface SSAInstructionFactory {
|
|||
SSAComparisonInstruction ComparisonInstruction(IComparisonInstruction.Operator operator, int result, int val1, int val2);
|
||||
|
||||
SSAConditionalBranchInstruction ConditionalBranchInstruction(IConditionalBranchInstruction.IOperator operator,
|
||||
TypeReference type, int val1, int val2);
|
||||
TypeReference type, int val1, int val2, int target);
|
||||
|
||||
SSAConversionInstruction ConversionInstruction(int result, int val, TypeReference fromType, TypeReference toType, boolean overflow);
|
||||
|
||||
|
@ -61,7 +61,7 @@ public interface SSAInstructionFactory {
|
|||
|
||||
SSAGetInstruction GetInstruction(int result, int ref, FieldReference field);
|
||||
|
||||
SSAGotoInstruction GotoInstruction();
|
||||
SSAGotoInstruction GotoInstruction(int target);
|
||||
|
||||
SSAInstanceofInstruction InstanceofInstruction(int result, int ref, TypeReference checkedType);
|
||||
|
||||
|
|
Loading…
Reference in New Issue