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 }