package Sequenic.T2ext.CoverageEngine; import java.io.*; import java.lang.reflect.Method; import java.util.List; import Sequenic.T2.Seq.*; import Sequenic.T2ext.Analyzer.Pair; import Sequenic.T2ext.Instrumenter.Sensor; import Sequenic.T2.*; import java.util.*; /** * Given a T2 test-trace, this class can provide various run-time information of * this trace. E.g. which steps does not actually make effect. */ public class T2TraceInspection { Trace trace; Class C; Pool pool; List classinvs; /** * Pointers to steps that do not change the state of the target object. The * pointers are given as an integer index pointing to the corresponding step * in the trace part of the trace field above. * *

Note that index 0 means the creation step; index i+1 means actually the * i-th element in the trace-field of trace. */ List stepsThatDoNotChangeTargetObj = new LinkedList(); /** * This table contains entries of the form (i,C), which means that the * i-th element of the pool contains an object of class C. The table * is sorted in the increasing order of i. */ List> REFtype_table = new LinkedList>() ; public T2TraceInspection(Trace trace_, Class C_, Pool pool_, List classinvs_) { trace = trace_ ; C = C_ ; pool = pool_ ; classinvs = classinvs_ ; inspect() ; } /** * Execute the trace to calculate various attributes; e.g. identifying which * steps do not change the target object, and to fill-in the REFtype table. */ private void inspect() { pool.reset(); TraceExecInfo info = new TraceExecInfo(trace); Object targetObj = null; int stepNr = 0; boolean ok = true; ok = exec_creation(info); stepNr++; // Creation step-done if (ok) { // Creation successful, continue with the steps: targetObj = pool.get(trace.indexOfTargetObj); Object oldTargetObject = null; for (TraceStep step : trace.trace) { oldTargetObject = cloneObj(targetObj); if (trace.diverging && step == trace.trace.getLast()) break; ok = exec_step(targetObj, step, info, stepNr); // Check if the step changes the state of target object: if (oldTargetObject != null && isEqual(targetObj, oldTargetObject) == 1) stepsThatDoNotChangeTargetObj.add(stepNr); stepNr++; if (!ok) break; } } // done with executing the trace... // Now build the REF-class table: List params = getParams(0,trace.trace.size()+1,false) ; Set indicesInPool = new HashSet() ; for (MkValStep param : params) { if (param instanceof REF) indicesInPool.add(((REF) param) . index) ; } List> table = new LinkedList>() ; for (Integer i : indicesInPool) { Object o = pool.get(i) ; if (o != null) table.add(new Pair(i,o.getClass())) ; } // Now sort the table, and move it to REFtype_table: while (! table.isEmpty()) { Pair min = null ; Integer i = null ; for (Pair x : table) { if (i==null || x.fst < i) { i = x.fst ; min = x ; } } REFtype_table.add(min) ; table.remove(min) ; } } /** * Short-cut to execute the creation step of the target trace. You need to * pass on a TraceExecInfo to hold the report (e.g. the kind of violation * found, if one is found). The method returns false if it detects a * violation, else true. */ private boolean exec_creation(TraceExecInfo info) { return info.update_with_step(trace.creation.MkTargetObject(C, pool, classinvs), 0); } /** * Short-cut to execute a (non-creational) test-step of the target trace. * You also need to pass on a TraceExecInfo to hold the report (e.g. the * kind of violation found, if one is found). The method returns false if it * detects a violation, else true. */ private boolean exec_step(Object targetObj, TraceStep step, TraceExecInfo info, int stepNr) { return info.update_with_step(step.exec(C, pool, targetObj, stepNr, classinvs), stepNr); } /** * Clone non-null t, if fails return null. */ private Object cloneObj(Object t) { Object clone = null; try { clone = Sequenic.T2.Obj.Cloner.clone(t); } catch (Exception e) { } return clone; } /** * Will check if two objects are structurally equal. This is done by * serializing them to byte arrays, and then comparing the bytes. This works * only if both objects are serializable. * * The method returns 1 if the objects are equal, 0 if they are unequal, and * -1 if it can't decide (e.g. if one of the object is unserializable). */ private int isEqual(Object s1, Object s2) { ByteArrayOutputStream as1 = new ByteArrayOutputStream(); ByteArrayOutputStream as2 = new ByteArrayOutputStream(); byte[] o1 = null; byte[] o2 = null; try { ObjectOutputStream oos1 = new ObjectOutputStream(as1); ObjectOutputStream oos2 = new ObjectOutputStream(as2); oos1.writeObject(s1); oos2.writeObject(s2); } catch (Exception e) { return -1; // can't compare; so undecided! } o1 = as1.toByteArray(); o2 = as2.toByteArray(); if (o1.length != o2.length) return 0; // not-equal int N = o1.length; for (int i = 0; i < N; i++) if (o1[i] != o2[i]) return 0; // not-equal // Else s1 and s2 are equal: return 1; } /** * Return the list of steps of this trace. The first one in the list * is the trace's creation step. */ public List getSteps() { LinkedList result = new LinkedList() ; result.add(trace.creation) ; for (TraceStep S : trace.trace) result.add(S) ; return result ; } /** * Will return the list of pointers pointing to the REF and CONST parameters * of the k1-th step in the target trace, up to (but excluded) the k2-th step. * The parameters are ordered from those of the k1-th to those of k2-th step. * *

Note: index-0 is supposed to refer to the creation step, and index * i+1 refers to the i-th element of the the trace-field of trace. * * @param skipSkippingSteps If set true, will skip the m-th step m, * with k1<=m getParams(int k1, int k2, boolean skipSkippingSteps) { List result = new LinkedList(); if (k1 >= k2) return result; List steps = getSteps() ; int N = steps.size() ; for (int i = Math.max(0, k1); i < Math.min(k2,N); i++) { if (skipSkippingSteps && stepsThatDoNotChangeTargetObj.contains(i) && i < Math.min(k2,N) -1 ) continue ; getParamsWorker(steps.get(i), result); } return result; } /** * Will return the list of pointers pointing to the REF and CONST * parameters of a given METARUN step. */ public static List getREFparams(METARUN metastep) { List result = new LinkedList(); getParamsWorker(metastep, result); return result; } static private void getParamsWorker(METARUN metastep, List result) { if (metastep instanceof REF) { result.add((REF) metastep) ; return ; } if (metastep instanceof CONST) { result.add((CONST) metastep) ; return; } if (metastep instanceof CALL_METHOD) { CALL_METHOD M = (CALL_METHOD) metastep; if (M.receiver != null) getParamsWorker(M.receiver, result); for (int i = 0; i < M.params.length; i++) getParamsWorker(M.params[i], result); return; } if (metastep instanceof UPDATE_FIELD) { getParamsWorker(((UPDATE_FIELD) metastep).val, result); return; } if (metastep instanceof CREATE_OBJECT) { CREATE_OBJECT M = (CREATE_OBJECT) metastep; for (int i = 0; i < M.params.length; i++) getParamsWorker(M.params[i], result); return; } if (metastep instanceof CREATE_COLLECTION_LIKE) { CREATE_COLLECTION_LIKE M = (CREATE_COLLECTION_LIKE) metastep; for (int i = 0; i < M.elements.length; i++) getParamsWorker(M.elements[i], result); return; } return; } }