将所有语句从一种方法移动到另一种方法

时间:2018-03-17 12:48:11

标签: java methods bytecode instrumentation soot

所以我有一个方法

public modifiers Foo foo(Bar bar){
    blah;
    blah;
    veryInterestingStmt;
    moreBlah();
    return XYZ;
}

我现在要将此方法拆分为s.t.其中的所有内容都被提取到一个单独的方法中(以编程方式)。

public modifiers Foo foo(Bar bar){
    return trulyFoo(bar);
}

public modifiers Foo trulyFoo(Bar bar){
    blah;
    blah;
    veryInterestingStmt;
    moreBlah();
    return XYZ;
}

但我怎么做呢?

天真的

private void fracture(SootMethod sm) {

        SootClass sc = sm.getDeclaringClass();

        String auxMethodName = sm.getName() + FRACTURE_SUFFIX;

        Type auxReturnType = sm.getReturnType();
        List<Type>auxParamTypes = new LinkedList<>(sm.getParameterTypes());
        int auxModifiers = sm.getModifiers();

        SootMethod auxMethod = sc.addMethod(new SootMethod(auxMethodName,auxParamTypes,auxReturnType,auxModifiers));

        Body body = sm.getActiveBody();
        Body auxBody = Jimple.v().newBody(auxMethod);
        auxMethod.setActiveBody(auxBody);

        for(Local l : body.getLocals()){
            auxBody.getLocals().add(l);
        }

        PatchingChain<Unit> units = body.getUnits();
        PatchingChain<Unit> auxUnits = auxBody.getUnits();

        Iterator<Unit> it = body.getUnits().snapshotIterator();
        boolean passedFirstNonidentity = false;
        while(it.hasNext()){
            Stmt stmt = (Stmt) it.next();
            if(!passedFirstNonidentity && !(stmt instanceof IdentityStmt)) {
                passedFirstNonidentity = true;
                //TODO: if added more parameters than original method had, add their identity stmts here
            }

            auxUnits.add(stmt);
//            if(passedFirstNonidentity) units.remove(stmt); //TODO: uncomment this and later add call to {@code auxMethod}
        }
    }
}

不起作用。如果我跑,请说

DirectedGraph dg = new ExceptionalUnitGraph(auxMethod.getActiveBody());

我得到了

java.lang.RuntimeException: Unit graph contains jump to non-existing target
    at soot.toolkits.graph.UnitGraph.buildUnexceptionalEdges(UnitGraph.java:128)
    at soot.toolkits.graph.ExceptionalUnitGraph.initialize(ExceptionalUnitGraph.java:258)
    at soot.toolkits.graph.ExceptionalUnitGraph.<init>(ExceptionalUnitGraph.java:159)
    at soot.toolkits.graph.ExceptionalUnitGraph.<init>(ExceptionalUnitGraph.java:192)

2 个答案:

答案 0 :(得分:0)

在不改变代码行为的情况下移动代码的技术称为Refactoring,并且在Martin Fowler的书中很好地介绍了。

在您的情况下,我会采取以下多步骤方法:

  1. 站起来&#34;什么都不做&#34;函数在你想要分割的函数中,就在你想要移动的代码行的上方。
  2. 从周围的函数中移动这些代码行中的一行或两行&#34;什么都不做&#34;函数,拆分函数,但拆分是嵌套调用。
  3. 将分割功能向上(或向下)移动到surronding函数中块的边缘。
  4. 将slh slpit函数移出块,在每次调用原始函数之前或每次调用原始函数之后对其进行新调用。请注意,您可能需要重新处理返回参数,具体取决于详细信息。
  5. 强烈建议您编写一组测试来首先验证此块的整体功能(如果不是大多数)。然后,在每次更改后运行您的测试以验证您没有改变行为。

    您现在看到的是通过以改变行为的方式修改代码文本而产生的行为变化。源代码的安全转换集可能比您之前认为的要小,或者您可能只是犯了一个简单的错误。但是,您正在尝试的工作需要的知识多于StackOverflow样式,问题/答案,格式。这就是我为什么参考这本书的原因。

    如果您可以缩小范围,您可能会在将来的重新提交中获得更好的响应。

答案 1 :(得分:0)

似乎移动stmts不起作用。相比之下,完全取代身体

        Body originalBody = sm.getActiveBody();
        originalBody.setMethod(auxMethod);
        auxMethod.setActiveBody(originalBody);
        Body newBody = Jimple.v().newBody(sm);
        sm.setActiveBody(newBody);

然后在newBody中重新生成本地人,身份stmts(以及您可能需要的其他stmts)看起来是一种明智的方式。