View Javadoc

1   /*
2    *
3    */
4   package org.softevo.jdynpur.eval;
5   
6   import java.io.File;
7   import java.io.IOException;
8   import java.util.HashSet;
9   import java.util.Iterator;
10  import java.util.NoSuchElementException;
11  
12  import org.softevo.util.asm.MethodIdentifier;
13  import org.softevo.util.asm.MethodIdentifierMapGenerator;
14  
15  /**
16   * This is a utility class used to analyze execution of specific methods. It
17   * expects a classname and one or more trace files as input and displays
18   * recorded events only when the specified method is executed.
19   */
20  public class MethodExecutionDisplayer extends PurityTraceAnalyser {
21  
22  	/**
23  	 * The method identifier of the method to be displayed.
24  	 */
25  	protected MethodIdentifier identifier = null;
26  
27  	/**
28  	 * The integer identifying the sought method.
29  	 */
30  	protected int soughtMethodId = -1;
31  
32  	/**
33  	 * The number of times the method is currently active. This is needed for
34  	 * recursive calls.
35  	 */
36  	protected int numberOfRunningMethods = 0;
37  
38  	/**
39  	 * Creates a new method execution displayer.
40  	 * 
41  	 * @param fileName
42  	 *          the name of the trace file to replay
43  	 * @param identifierMap
44  	 *          the identifier map for this trace
45  	 * @param identifier
46  	 *          the identifier of the sought method
47  	 */
48  	public MethodExecutionDisplayer(String fileName, 
49  	                                MethodIdentifier identifier) {
50  		super(fileName, null, false, true);
51  		this.identifier = identifier;
52  		this.soughtMethodId = identifierMap.getIdentifier(identifier);
53  		System.out.println("ID of sought method: " + soughtMethodId);
54  	}
55  
56  	/**
57  	 * If the sought method is active, this method outputs an array creation
58  	 * message on <code>System.out</code>.
59  	 * 
60  	 * @param objectId
61  	 *          the identifier for the new array
62  	 * @param threadId
63  	 *          the thread id
64  	 */
65  	protected void handleArrayCreation(int objectId, int threadId) {
66  		if (isMethodRunning()) {
67  			System.out.println("Created array " + objectId);
68  		}
69  		super.handleArrayCreation(objectId, threadId);
70  	}
71  
72  	/**
73  	 * If the sought method is active, this method outputs an array modification
74  	 * message on <code>System.out</code>.
75  	 * 
76  	 * @param objectId
77  	 *          the identifier for the modified array
78  	 * @param threadId
79  	 *          the thread id
80  	 */
81  	protected void handleArrayModification(int objectId, int threadId) {
82  		if (isMethodRunning()) {
83  			System.out.println("Modified array " + objectId);
84  		}
85  		super.handleArrayModification(objectId, threadId);
86  	}
87  
88  	/**
89  	 * If the sought method is active, this method outputs a field modification
90  	 * message on <code>System.out</code>.
91  	 * 
92  	 * @param objectId
93  	 *          the identifier for the modified field
94  	 * @param threadId
95  	 *          the thread id
96  	 */
97  	protected void handleStaticFieldWrite(int threadId) {
98  		if (isMethodRunning()) {
99  			System.out.println("Wrote static field");
100 		}
101 		super.handleStaticFieldWrite(threadId);
102 	}
103 
104 	/**
105 	 * If the sought method is active, this method outputs a field modification
106 	 * message on <code>System.out</code>.
107 	 * 
108 	 * @param objectId
109 	 *          the identifier for the modified field
110 	 * @param threadId
111 	 *          the thread id
112 	 */
113 	protected void handleFieldWrite(int objectId, int threadId) {
114 		if (isMethodRunning()) {
115 			System.out.println("Wrote field of object " + objectId);
116 		}
117 		super.handleFieldWrite(objectId, threadId);
118 	}
119 
120 	/**
121 	 * If the sought method is active, this method outputs an object creation
122 	 * message on <code>System.out</code>.
123 	 * 
124 	 * @param objectId
125 	 *          the identifier for the new object
126 	 * @param threadId
127 	 *          the thread id
128 	 */
129 	protected void handleObjectCreation(int objectId, int threadId) {
130 		if (isMethodRunning()) {
131 			System.out.println("Created object " + objectId);
132 		}
133 		super.handleObjectCreation(objectId, threadId);
134 	}
135 
136 	/**
137 	 * If the sought method is active, this method outputs a method start message
138 	 * on <code>System.out</code> and increases the active method count.
139 	 * 
140 	 * @param methodId
141 	 *          the identifier for the method
142 	 * @param threadId
143 	 *          the thread id
144 	 */
145 	protected void handleMethodStart(int methodId, int threadId, String className) {
146 		if (isSoughtMethod(methodId)) {
147 			numberOfRunningMethods++;
148 			System.out.println("Starting execution of " + identifier + " (" + numberOfRunningMethods + ")");
149 		} else if (isMethodRunning()) {
150 			System.out.println("Intermediate method start " + identifierMap.getMethodIdentifier(methodId));
151 		}
152 		super.handleMethodStart(methodId, threadId, className);
153 	}
154 
155 	/**
156 	 * If a method has ended, this method checks if it's execution had
157 	 * side-effects and outputs a message on <code>System.out</code>.
158 	 * 
159 	 * @param methodId
160 	 *          the identifier for the method
161 	 * @param threadId
162 	 *          the thread id
163 	 */
164 	@SuppressWarnings("unchecked")
165 	protected void handleMethodEnd(int methodId, int threadId, String className) {
166 		HashSet<Integer> createdObjects;
167 		HashSet<Integer> modifiedObjects;
168 		HashSet<Integer> setDifference;
169 		Iterator<Integer> methodIdIterator;
170 
171 		if (isSoughtMethod(methodId)) {
172 			createdObjects = getCreatedObjectSetStack(threadId).pop();
173 			modifiedObjects = getModifiedObjectSetStack(threadId).peek();
174 			if (!createdObjects.containsAll(modifiedObjects)) {
175 				setDifference = (HashSet<Integer>) modifiedObjects.clone();
176 				setDifference.removeAll(createdObjects);
177 				System.out.println("Method " + identifierMap.getMethodIdentifier(methodId)
178 				                   + " impure because of modifications to the following objects:");
179 				methodIdIterator = setDifference.iterator();
180 				while (methodIdIterator.hasNext()) {
181 					System.out.println(methodIdIterator.next());
182 				}
183 			} else {
184 				System.out.println("Method " + identifierMap.getMethodIdentifier(methodId) + " is pure.");
185 			}
186 			getCreatedObjectSetStack(threadId).push(createdObjects);
187 			numberOfRunningMethods--;
188 			System.out.println("Finished execution of " + identifier + " (" + numberOfRunningMethods + ")");
189 		} else if (isMethodRunning()) {
190 			System.out.println("Intermediate method end " + identifierMap.getMethodIdentifier(methodId));
191 		}
192 		super.handleMethodEnd(methodId, threadId, className);
193 	}
194 
195 	/**
196 	 * Checks if the sought method is currently executed in the trace.
197 	 */
198 	protected boolean isMethodRunning() {
199 		return numberOfRunningMethods > 0;
200 	}
201 
202 	/**
203 	 * Checks if the identifier is for the sought method.
204 	 * 
205 	 * @param methodId
206 	 *          the id of the method
207 	 */
208 	protected boolean isSoughtMethod(int methodId) {
209 		if (methodId == soughtMethodId) {
210 			return true;
211 		} else {
212 			return false;
213 		}
214 	}
215 
216 	/**
217 	 * This method evaluates command line arguments and replays execution for
218 	 * every trace file.
219 	 * 
220 	 * @param args
221 	 *          command line arguments
222 	 */
223 	public static void main(String[] args) throws IOException {
224 		File[] files;
225 		String suffix;
226 		String[] fileNames;
227 		MethodExecutionDisplayer displayer;
228 		String methodIdentifier;
229 		MethodIdentifier identifier;
230 
231 		methodIdentifier = args[0];
232 		files = new File[args.length - 1];
233 		for (int counter = 0; counter < files.length; counter++) {
234 			files[counter] = new File(args[counter + 1]);
235 		}
236 		fileNames = new String[args.length - 1];
237 		for (int counter = 0; counter < fileNames.length; counter++) {
238 			fileNames[counter] = files[counter].getName();
239 		}
240 		for (int counter = 1; counter < args.length; counter++) {
241 			suffix = fileNames[counter - 1].substring(10, fileNames[counter - 1].length());
242 			identifier = MethodIdentifier.parseFromIdentifier(methodIdentifier);
243 			try {
244 				displayer = new MethodExecutionDisplayer(args[counter], identifier);
245 				System.out.println("Analysing trace " + args[counter]);
246 				displayer.analyse(false, false);
247 			} catch (NoSuchElementException methodNotExecutedException) {
248 				System.out.println("Method not executed in trace " + args[counter]);
249 			}
250 		}
251 	}
252 
253 }