
jasm.util.dfa.ForwardFlowAnalysis Maven / Gradle / Ivy
// Copyright (c) 2011, David J. Pearce ([email protected])
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL DAVID J. PEARCE BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package jasm.util.dfa;
import jasm.attributes.Code;
import jasm.lang.*;
import java.util.*;
/**
* Represents a generic forward dataflow analysis. This user must implement the
* transfer functions for the different kinds of bytecode, and the analysis will
* propagate until a fixed point is reached.
*
* @author David J. Pearce
*
*/
public abstract class ForwardFlowAnalysis {
/**
*
* @param method
*/
public T[] apply(ClassFile.Method method) {
Code attr = method.attribute(Code.class);
if (attr == null) {
// sanity check
throw new IllegalArgumentException(
"cannot apply forward flow analysis on method without code attribute");
}
List bytecodes = attr.bytecodes();
// Holds the indices of bytecodes still to be processed. When this set
// is emtpy, we're done.
HashSet worklist = new HashSet();
worklist.add(0);
// Determine the bytecode index of each declared label.
HashMap labels = new HashMap();
for(int i=0;i!=bytecodes.size();++i) {
Bytecode bytecode = bytecodes.get(i);
if(bytecode instanceof Bytecode.Label) {
Bytecode.Label label = (Bytecode.Label) bytecode;
labels.put(label.name, i);
}
}
// Stores the abstract store which holds immediately before each
// bytecode.
T[] stores = initialise(attr,method);
while(!worklist.isEmpty()) {
int index = select(worklist);
Bytecode bytecode = bytecodes.get(index);
T store = stores[index];
if(bytecode instanceof Bytecode.Label) {
// basically, a no-op
merge(index+1,store,worklist,stores);
} else if(bytecode instanceof Bytecode.Goto) {
Bytecode.Goto g = (Bytecode.Goto) bytecode;
int target = labels.get(g.label);
merge(target,store,worklist,stores);
} else if(bytecode instanceof Bytecode.If) {
Bytecode.If i = (Bytecode.If) bytecode;
T falseBranch = transfer(index,false,i,store);
T trueBranch = transfer(index,true,i,store);
merge(index+1,falseBranch,worklist,stores);
merge(labels.get(i.label),trueBranch,worklist,stores);
} else if(bytecode instanceof Bytecode.IfCmp) {
Bytecode.IfCmp i = (Bytecode.IfCmp) bytecode;
T falseBranch = transfer(index,false,i,store);
T trueBranch = transfer(index,true,i,store);
merge(index+1,falseBranch,worklist,stores);
merge(labels.get(i.label),trueBranch,worklist,stores);
} else if(bytecode instanceof Bytecode.Switch) {
// TODO
} else if(bytecode instanceof Bytecode.Return) {
transfer(index,(Bytecode.Return) bytecode,store);
} else if(bytecode instanceof Bytecode.Throw) {
transfer(index,(Bytecode.Throw) bytecode,store);
} else {
// all of these bytecodes are sequential and produce a single store.
if(bytecode instanceof Bytecode.Store) {
store = transfer(index, (Bytecode.Store)bytecode, store);
} else if(bytecode instanceof Bytecode.Load) {
store = transfer(index, (Bytecode.Load)bytecode, store);
} else if(bytecode instanceof Bytecode.LoadConst) {
store = transfer(index, (Bytecode.LoadConst)bytecode, store);
} else if(bytecode instanceof Bytecode.Iinc) {
store = transfer(index, (Bytecode.Iinc) bytecode, store);
} else if(bytecode instanceof Bytecode.ArrayLoad) {
store = transfer(index, (Bytecode.ArrayLoad) bytecode, store);
} else if(bytecode instanceof Bytecode.ArrayStore) {
store = transfer(index, (Bytecode.ArrayStore) bytecode, store);
} else if(bytecode instanceof Bytecode.ArrayLength) {
store = transfer(index, (Bytecode.ArrayLength) bytecode, store);
} else if(bytecode instanceof Bytecode.GetField) {
store = transfer(index, (Bytecode.GetField) bytecode, store);
} else if(bytecode instanceof Bytecode.PutField) {
store = transfer(index, (Bytecode.PutField) bytecode, store);
} else if(bytecode instanceof Bytecode.CheckCast) {
store = transfer(index, (Bytecode.CheckCast) bytecode, store);
} else if(bytecode instanceof Bytecode.InstanceOf) {
store = transfer(index, (Bytecode.InstanceOf) bytecode, store);
} else if(bytecode instanceof Bytecode.Invoke) {
store = transfer(index, (Bytecode.Invoke) bytecode, store);
} else if(bytecode instanceof Bytecode.Conversion) {
store = transfer(index, (Bytecode.Conversion) bytecode, store);
} else if(bytecode instanceof Bytecode.Cmp) {
store = transfer(index, (Bytecode.Cmp) bytecode, store);
} else if(bytecode instanceof Bytecode.Pop) {
store = transfer(index, (Bytecode.Pop) bytecode, store);
} else if(bytecode instanceof Bytecode.Dup) {
store = transfer(index, (Bytecode.Dup) bytecode, store);
} else if(bytecode instanceof Bytecode.DupX1) {
store = transfer(index, (Bytecode.DupX1) bytecode, store);
} else if(bytecode instanceof Bytecode.DupX2) {
store = transfer(index, (Bytecode.DupX2) bytecode, store);
} else if(bytecode instanceof Bytecode.Swap) {
store = transfer(index, (Bytecode.Swap) bytecode, store);
} else if(bytecode instanceof Bytecode.BinOp) {
store = transfer(index, (Bytecode.BinOp) bytecode, store);
} else if(bytecode instanceof Bytecode.Neg) {
store = transfer(index, (Bytecode.Neg) bytecode, store);
} else if(bytecode instanceof Bytecode.New) {
store = transfer(index, (Bytecode.New) bytecode, store);
} else if(bytecode instanceof Bytecode.MonitorEnter) {
store = transfer(index, (Bytecode.MonitorEnter) bytecode, store);
} else if(bytecode instanceof Bytecode.MonitorExit) {
store = transfer(index, (Bytecode.MonitorExit) bytecode, store);
} else if(bytecode instanceof Bytecode.Nop) {
store = transfer(index, (Bytecode.Nop) bytecode, store);
} else {
// unknown bytecode encountered should be dead code.
throw new RuntimeException(
"Unknown bytecode encountered in ForwardFlowAnalysis ("
+ bytecode + ")");
}
merge(index + 1, store, worklist, stores);
}
}
return stores;
}
protected int select(HashSet worklist) {
int next = worklist.iterator().next();
worklist.remove(next);
return next;
}
protected void merge(int index, T store, HashSet worklist, T[] stores) {
T old = stores[index];
if(old == null) {
stores[index] = store;
worklist.add(index);
} else {
if(merge(index,old,store)) {
worklist.add(index);
}
}
}
/**
* Generate an array of stores, one for each bytecode in the given method.
* The initial store (i.e. at index zero) is the initial store for the
* method.
*
* initial store for the given method.
*
* @param attribute
* code attribute being analysed.
* @param method
* enclosing method.
* @return
*/
public abstract T[] initialise(Code attribute, ClassFile.Method method);
/**
* Generate an updated a abstract store by apply the abstract effect(s) of a
* store bytecode to an incoming store.
*
* @param index
* index in bytecode array of bytecode being analysed.
* @param bytecode
* bytecode to be analysed.
* @param store
* incoming abstract store.
* @return
*/
public abstract T transfer(int index, Bytecode.Store bytecode, T store);
/**
* Generate an updated a abstract store by apply the abstract effect(s) of a
* load bytecode to an incoming store.
*
* @param index
* index in bytecode array of bytecode being analysed.
* @param bytecode
* bytecode to be analysed.
* @param store
* incoming abstract store.
* @return
*/
public abstract T transfer(int index, Bytecode.Load bytecode, T store);
/**
* Generate an updated a abstract store by apply the abstract effect(s) of a
* loadconst bytecode to an incoming store.
*
* @param index
* index in bytecode array of bytecode being analysed.
* @param bytecode
* bytecode to be analysed.
* @param store
* incoming abstract store.
* @return
*/
public abstract T transfer(int index, Bytecode.LoadConst bytecode, T store);
/**
* Generate an updated a abstract store by apply the abstract effect(s) of a
* arrayload bytecode to an incoming store.
*
* @param index
* index in bytecode array of bytecode being analysed.
* @param bytecode
* bytecode to be analysed.
* @param store
* incoming abstract store.
* @return
*/
public abstract T transfer(int index, Bytecode.ArrayLoad bytecode, T store);
/**
* Generate an updated a abstract store by apply the abstract effect(s) of a
* arraystore bytecode to an incoming store.
*
* @param index
* index in bytecode array of bytecode being analysed.
* @param bytecode
* bytecode to be analysed.
* @param store
* incoming abstract store.
* @return
*/
public abstract T transfer(int index, Bytecode.ArrayStore bytecode, T store);
/**
* Generate an updated a abstract store by apply the abstract effect(s) of a
* getfield bytecode to an incoming store.
*
* @param index
* index in bytecode array of bytecode being analysed.
* @param bytecode
* bytecode to be analysed.
* @param store
* incoming abstract store.
* @return
*/
public abstract T transfer(int index, Bytecode.GetField bytecode, T store);
/**
* Generate an updated a abstract store by apply the abstract effect(s) of a
* arraystore bytecode to an incoming store.
*
* @param index
* index in bytecode array of bytecode being analysed.
* @param bytecode
* bytecode to be analysed.
* @param store
* incoming abstract store.
* @return
*/
public abstract T transfer(int index, Bytecode.PutField bytecode, T store);
/**
* Generate an updated a abstract store by apply the abstract effect(s) of a
* arraystore bytecode to an incoming store.
*
* @param index
* index in bytecode array of bytecode being analysed.
* @param bytecode
* bytecode to be analysed.
* @param store
* incoming abstract store.
* @return
*/
public abstract T transfer(int index, Bytecode.ArrayLength bytecode, T store);
/**
* Generate an updated a abstract store by apply the abstract effect(s) of a
* invoke bytecode to an incoming store.
*
* @param index
* index in bytecode array of bytecode being analysed.
* @param bytecode
* bytecode to be analysed.
* @param store
* incoming abstract store.
* @return
*/
public abstract T transfer(int index, Bytecode.Invoke bytecode, T store);
/**
* Generate an updated a abstract store by apply the abstract effect(s) of a
* throw bytecode to an incoming store.
*
* @param index
* index in bytecode array of bytecode being analysed.
* @param bytecode
* bytecode to be analysed.
* @param store
* incoming abstract store.
*/
public abstract void transfer(int index, Bytecode.Throw bytecode, T store);
/**
* Generate an updated a abstract store by apply the abstract effect(s) of a
* return bytecode to an incoming store.
*
* @param index
* index in bytecode array of bytecode being analysed.
* @param bytecode
* bytecode to be analysed.
* @param store
* incoming abstract store.
*/
public abstract void transfer(int index, Bytecode.Return bytecode, T store);
/**
* Generate an updated a abstract store by apply the abstract effect(s) of
* an iinc bytecode to an incoming store.
*
* @param index
* index in bytecode array of bytecode being analysed.
* @param bytecode
* bytecode to be analysed.
* @param store
* incoming abstract store.
* @return
*/
public abstract T transfer(int index, Bytecode.Iinc bytecode, T store);
/**
* Generate an updated a abstract store by apply the abstract effect(s) of
* a binop bytecode to an incoming store.
*
* @param index
* index in bytecode array of bytecode being analysed.
* @param bytecode
* bytecode to be analysed.
* @param store
* incoming abstract store.
* @return
*/
public abstract T transfer(int index, Bytecode.BinOp bytecode, T store);
/**
* Generate an updated a abstract store by apply the abstract effect(s) of
* a neg bytecode to an incoming store.
*
* @param index
* index in bytecode array of bytecode being analysed.
* @param bytecode
* bytecode to be analysed.
* @param store
* incoming abstract store.
* @return
*/
public abstract T transfer(int index, Bytecode.Neg bytecode, T store);
/**
* Generate an updated a abstract store by apply the abstract effect(s) of
* a new bytecode to an incoming store.
*
* @param index
* index in bytecode array of bytecode being analysed.
* @param bytecode
* bytecode to be analysed.
* @param store
* incoming abstract store.
* @return
*/
public abstract T transfer(int index, Bytecode.New bytecode, T store);
/**
* Generate an updated a abstract store by apply the abstract effect(s) of
* a checkcast bytecode to an incoming store.
*
* @param index
* index in bytecode array of bytecode being analysed.
* @param bytecode
* bytecode to be analysed.
* @param store
* incoming abstract store.
* @return
*/
public abstract T transfer(int index, Bytecode.CheckCast bytecode, T store);
/**
* Generate an updated a abstract store by apply the abstract effect(s) of
* a convert bytecode to an incoming store.
*
* @param index
* index in bytecode array of bytecode being analysed.
* @param bytecode
* bytecode to be analysed.
* @param store
* incoming abstract store.
* @return
*/
public abstract T transfer(int index, Bytecode.Conversion bytecode, T store);
/**
* Generate an updated a abstract store by apply the abstract effect(s) of
* a instanceof bytecode to an incoming store.
*
* @param index
* index in bytecode array of bytecode being analysed.
* @param bytecode
* bytecode to be analysed.
* @param store
* incoming abstract store.
* @return
*/
public abstract T transfer(int index, Bytecode.InstanceOf bytecode, T store);
/**
* Generate an updated a abstract store by apply the abstract effect(s) of
* a pop bytecode to an incoming store.
*
* @param index
* index in bytecode array of bytecode being analysed.
* @param bytecode
* bytecode to be analysed.
* @param store
* incoming abstract store.
* @return
*/
public abstract T transfer(int index, Bytecode.Pop bytecode, T store);
/**
* Generate an updated a abstract store by apply the abstract effect(s) of
* a dup bytecode to an incoming store.
*
* @param index
* index in bytecode array of bytecode being analysed.
* @param bytecode
* bytecode to be analysed.
* @param store
* incoming abstract store.
* @return
*/
public abstract T transfer(int index, Bytecode.Dup bytecode, T store);
/**
* Generate an updated a abstract store by apply the abstract effect(s) of
* a dup_x1 bytecode to an incoming store.
*
* @param index
* index in bytecode array of bytecode being analysed.
* @param bytecode
* bytecode to be analysed.
* @param store
* incoming abstract store.
* @return
*/
public abstract T transfer(int index, Bytecode.DupX1 bytecode, T store);
/**
* Generate an updated a abstract store by apply the abstract effect(s) of
* a dup_x2 bytecode to an incoming store.
*
* @param index
* index in bytecode array of bytecode being analysed.
* @param bytecode
* bytecode to be analysed.
* @param store
* incoming abstract store.
* @return
*/
public abstract T transfer(int index, Bytecode.DupX2 bytecode, T store);
/**
* Generate an updated a abstract store by apply the abstract effect(s) of
* a swap bytecode to an incoming store.
*
* @param index
* index in bytecode array of bytecode being analysed.
* @param bytecode
* bytecode to be analysed.
* @param store
* incoming abstract store.
* @return
*/
public abstract T transfer(int index, Bytecode.Swap bytecode, T store);
/**
* Generate an updated a abstract store by apply the abstract effect(s) of
* a cmp bytecode to an incoming store.
*
* @param index
* index in bytecode array of bytecode being analysed.
* @param bytecode
* bytecode to be analysed.
* @param store
* incoming abstract store.
* @return
*/
public abstract T transfer(int index, Bytecode.Cmp bytecode, T store);
/**
* Generate an updated a abstract store by apply the abstract effect(s) of
* a nop bytecode to an incoming store.
*
* @param index
* index in bytecode array of bytecode being analysed.
* @param bytecode
* bytecode to be analysed.
* @param store
* incoming abstract store.
* @return
*/
public abstract T transfer(int index, Bytecode.Nop bytecode, T store);
/**
* Generate an updated a abstract store by apply the abstract effect(s) of
* a monitorenter bytecode to an incoming store.
*
* @param index
* index in bytecode array of bytecode being analysed.
* @param bytecode
* bytecode to be analysed.
* @param store
* incoming abstract store.
* @return
*/
public abstract T transfer(int index, Bytecode.MonitorEnter bytecode, T store);
/**
* Generate an updated a abstract store by apply the abstract effect(s) of
* a monitorexit bytecode to an incoming store.
*
* @param index
* index in bytecode array of bytecode being analysed.
* @param bytecode
* bytecode to be analysed.
* @param store
* incoming abstract store.
* @return
*/
public abstract T transfer(int index, Bytecode.MonitorExit bytecode, T store);
/**
* Generate an updated a abstract store by apply the abstract effect(s) of a
* given bytecode to an incoming store. In this case, the bytecode in
* question is branching, and we must consider which branch is being
* analysed (either the true branch, or the false branch).
*
* @param index
* index in bytecode array of bytecode being analysed.
* @param branch
* indicates the true or false branch is to be considered.
* @param bytecode
* to be analysed.
* @param store
* incoming abstract store.
* @return
*/
public abstract T transfer(int index, boolean branch, Bytecode.If bytecode, T store);
/**
* Generate an updated a abstract store by apply the abstract effect(s) of a
* given bytecode to an incoming store. In this case, the bytecode in
* question is branching, and we must consider which branch is being
* analysed (either the true branch, or the false branch).
*
* @param index
* index in bytecode array of bytecode being analysed.
* @param branch
* indicates the true or false branch is to be considered.
* @param bytecode
* to be analysed.
* @param store
* incoming abstract store.
* @return
*/
public abstract T transfer(int index, boolean branch, Bytecode.IfCmp bytecode, T store);
/**
* Merge one abstract store into another to form a store at a join point in
* the control-flow graph.
*
* @param index
* Index position of bytecode being analysed
* @param original
* Original store to join "into". In the case of no change, this
* should be returned.
* @param update
* New store to join "into" the original store.
* @return true if the store was changed.
*/
public abstract boolean merge(int index, T original, T update);
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy