View Javadoc

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 }