1
2
3
4 package org.softevo.jdynpur.eval;
5
6 import java.io.ByteArrayOutputStream;
7 import java.io.File;
8 import java.io.IOException;
9 import java.util.Arrays;
10 import java.util.HashMap;
11 import java.util.HashSet;
12 import java.util.Iterator;
13
14 import javax.xml.parsers.ParserConfigurationException;
15 import javax.xml.transform.TransformerException;
16
17 import org.softevo.jdynpur.eval.PurityTraceAnalyser.ParameterMutabilityInformation;
18 import org.softevo.util.asm.MethodIdentifier;
19 import org.xml.sax.SAXException;
20
21 /**
22 * This class analyzes several execution traces for the same program and merges
23 * the results. If a method was impure in at least one trace, then it is
24 * considered to be impure.
25 *
26 * @author dallmeier
27 */
28 public class MultiplePurityTraceAnalyser {
29
30 /**
31 * The name of the trace file to be analyzed.
32 */
33 private String fileName = null;
34
35 /**
36 * The set of pure method identifiers.
37 */
38 private HashMap<MethodIdentifier, HashSet<String>> pureMethodIdentifiers;
39
40 /**
41 * The set of impure method identifiers.
42 */
43 private HashMap<MethodIdentifier, HashSet<String>> impureMethodIdentifiers;
44
45 /**
46 * The set of executed method identifiers.
47 */
48 private HashMap<MethodIdentifier, HashSet<String>> executedMethodIdentifiers;
49
50 private HashMap<MethodIdentifier, HashSet<String>> methodsModifyingThis;
51
52 private String resultFileName;
53
54 private boolean analyseParameterMutability;
55
56 private HashMap<MethodIdentifier, ParameterMutabilityInformation> parameterMutabilityInformation;
57
58 /**
59 * Creates a new analyzer for all traces in the given directory.
60 *
61 * @param fileName
62 * the name of the directory
63 */
64 public MultiplePurityTraceAnalyser(String fileName, String resultFileName, boolean analyseParameterMutability) {
65 this.fileName = fileName;
66 this.resultFileName = resultFileName;
67 this.analyseParameterMutability = analyseParameterMutability;
68 }
69
70 private HashSet<String> getTypeSet(HashMap<MethodIdentifier, HashSet<String>> map, MethodIdentifier identifier) {
71 HashSet<String> result;
72
73 result = map.get(identifier);
74 if (result == null) {
75 result = new HashSet<String>();
76 map.put(identifier, result);
77 }
78 return result;
79 }
80
81 /**
82 * Analyzes all trace files in the directory. After this method has finished,
83 * the results are stored in the classes' <code>HashSet</code> fields. This
84 * method also outputs some information on <code>System.out</code>
85 *
86 * @throws IOException
87 * if an exception occurs reading a trace.
88 * @throws TransformerException
89 * @throws ParserConfigurationException
90 * @throws SAXException
91 */
92 public void analyse() throws IOException, ParserConfigurationException, TransformerException, SAXException {
93 File traceDirectory;
94 File[] children;
95 String suffix;
96 String[] fileNames;
97 PurityTraceAnalyser purityAnalyser;
98 Iterator<MethodIdentifier> newImpureMethodsIterator, newPureMethodsIterator;
99 MethodIdentifier identifier;
100 boolean isFirstTrace = true;
101 HashSet<String> pureTypes, impureTypes;
102
103 impureMethodIdentifiers = new HashMap<MethodIdentifier, HashSet<String>>();
104 pureMethodIdentifiers = new HashMap<MethodIdentifier, HashSet<String>>();
105 executedMethodIdentifiers = new HashMap<MethodIdentifier, HashSet<String>>();
106 methodsModifyingThis = new HashMap<MethodIdentifier, HashSet<String>>();
107 parameterMutabilityInformation = new HashMap<MethodIdentifier, ParameterMutabilityInformation>();
108 traceDirectory = new File(fileName);
109 if (traceDirectory.isDirectory()) {
110 children = traceDirectory.listFiles();
111 System.out.println("Found " + children.length + " trace files");
112 fileNames = new String[children.length];
113 for (int counter = 0; counter < children.length; counter++) {
114 fileNames[counter] = children[counter].getName();
115 }
116 Arrays.sort(fileNames);
117 } else {
118 fileNames = new String[] {fileName};
119 children = new File[] {new File(fileName)};
120 }
121 for (int counter = 0; counter < fileNames.length; counter++) {
122 suffix = fileNames[counter].substring(10, fileNames[counter].length());
123 System.out.println("Processing file " + fileNames[counter]);
124 purityAnalyser = new PurityTraceAnalyser(children[counter].getAbsolutePath(), null, false, analyseParameterMutability);
125 System.out.println("Analysing purity trace " + suffix + ".");
126 try {
127 purityAnalyser.analyse(false, false);
128 } catch (Throwable analysisError) {
129 System.out.println("An error occured processing file " + fileNames[counter]);
130 System.out.println(analysisError);
131 analysisError.printStackTrace();
132 System.out.println("Results of this file will be ignored.");
133 continue;
134 }
135 System.out.println("Comparing trace results.");
136 PurityResults results = new PurityResults(purityAnalyser.getPureMethodIdentifiers(),
137 purityAnalyser.getImpureMethodIdentifiers(),
138 purityAnalyser.getThisModifyingMethodIdentifiers(),
139 purityAnalyser.getExecutedMethodIdentifiers(),
140 purityAnalyser.getParameterMutabilityInformation());
141 ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream();
142 results.saveXML(byteBuffer);
143 executedMethodIdentifiers.putAll(purityAnalyser.getExecutedMethodIdentifiers());
144 methodsModifyingThis.putAll(purityAnalyser.getThisModifyingMethodIdentifiers());
145 if (isFirstTrace) {
146 isFirstTrace = false;
147 pureMethodIdentifiers.putAll(purityAnalyser.getPureMethodIdentifiers());
148 impureMethodIdentifiers.putAll(purityAnalyser.getImpureMethodIdentifiers());
149 parameterMutabilityInformation.putAll(purityAnalyser.getParameterMutabilityInformation());
150 } else {
151 newImpureMethodsIterator = purityAnalyser.getImpureMethodIdentifiers().keySet().iterator();
152 while (newImpureMethodsIterator.hasNext()) {
153 identifier = newImpureMethodsIterator.next();
154 pureMethodIdentifiers.remove(identifier);
155 impureTypes = getTypeSet(impureMethodIdentifiers, identifier);
156 impureTypes.addAll(purityAnalyser.getImpureMethodIdentifiers().get(identifier));
157 }
158 newPureMethodsIterator = purityAnalyser.getPureMethodIdentifiers().keySet().iterator();
159 while (newPureMethodsIterator.hasNext()) {
160 identifier = newPureMethodsIterator.next();
161 if (!impureMethodIdentifiers.containsKey(identifier)) {
162 pureTypes = getTypeSet(pureMethodIdentifiers, identifier);
163 pureTypes.addAll(purityAnalyser.getPureMethodIdentifiers().get(identifier));
164 }
165 }
166 HashMap<MethodIdentifier, ParameterMutabilityInformation> newParameterInformation = purityAnalyser.getParameterMutabilityInformation();
167 for (MethodIdentifier methodIdentifier: newParameterInformation.keySet()) {
168 if (parameterMutabilityInformation.containsKey(methodIdentifier)) {
169 ParameterMutabilityInformation oldMutabilityInformation = parameterMutabilityInformation.get(methodIdentifier);
170 int oldNumberOfImmutableParameters = oldMutabilityInformation.getUnmodifiedParameters().size();
171 ParameterMutabilityInformation newMutabilityInformation = newParameterInformation.get(methodIdentifier);
172 HashMap<String, HashSet<Integer>> classToUnmodifiedParametersMap = newMutabilityInformation.getRuntimeClassNameToUnmodifiedParametersMap();
173 for (String className : classToUnmodifiedParametersMap.keySet()) {
174 oldMutabilityInformation.updateUnmodifiedParameters(className, classToUnmodifiedParametersMap.get(className));
175 }
176 int newNumberOfImmutableParameters = oldMutabilityInformation.getUnmodifiedParameters().size();
177 assert (newNumberOfImmutableParameters <= oldNumberOfImmutableParameters) : "Incorrect increase of immutable parameters.";
178 } else {
179 parameterMutabilityInformation.put(methodIdentifier, newParameterInformation.get(methodIdentifier));
180 }
181 }
182
183 }
184 byteBuffer = new ByteArrayOutputStream();
185 results.saveXML(byteBuffer);
186 writeResults();
187 }
188 System.out.println("Done.");
189 }
190
191 /**
192 * This method serializes the results to the file system. Pure methods are
193 * stored in <code>puremethods.ser</code>, impure methods are stored in
194 * <code>impuremethods.ser</code>, executed methods are stored in
195 * <code>executedmethods.ser</code>.
196 * @throws TransformerException
197 * @throws ParserConfigurationException
198 * @throws IOException
199 */
200 private void writeResults() throws IOException, ParserConfigurationException, TransformerException {
201 PurityResults results = new PurityResults(pureMethodIdentifiers, impureMethodIdentifiers,
202 methodsModifyingThis, executedMethodIdentifiers,
203 parameterMutabilityInformation);
204 results.saveXML(resultFileName);
205 }
206
207 /**
208 * Launches analysis of a directory of trace files. It expects the name of the
209 * trace directory as its only argument.
210 *
211 * @param args
212 * the command line arguments
213 * @throws TransformerException
214 * @throws ParserConfigurationException
215 * @throws SAXException
216 */
217 public static void main(String[] args) throws IOException, ParserConfigurationException, TransformerException, SAXException {
218 MultiplePurityTraceAnalyser traceAnalyser;
219
220 if (args.length < 3) {
221 System.out.println("Usage: java org.softevo.jdynpur.MultiplePurityTraceAnalyser <traceDirectory> <resultfilename> <analyseParameterMutability>");
222 } else {
223 traceAnalyser = new MultiplePurityTraceAnalyser(args[0], args[1], new Boolean(args[2]));
224 traceAnalyser.analyse();
225 }
226 }
227
228 }