All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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