1 package edu.uci.eecs.codeGenerator;
3 import java.io.BufferedReader;
5 import java.io.FileNotFoundException;
6 import java.io.FileReader;
7 import java.io.IOException;
8 import java.io.LineNumberReader;
9 import java.util.ArrayList;
10 import java.util.Collections;
11 import java.util.HashMap;
13 import edu.uci.eecs.codeGenerator.CodeAdditions.CodeAddition;
14 import edu.uci.eecs.specExtraction.Code;
15 import edu.uci.eecs.specExtraction.Construct;
16 import edu.uci.eecs.specExtraction.DefineConstruct;
17 import edu.uci.eecs.specExtraction.EntryConstruct;
18 import edu.uci.eecs.specExtraction.InterfaceConstruct;
19 import edu.uci.eecs.specExtraction.OPConstruct;
20 import edu.uci.eecs.specExtraction.SpecExtractor;
21 import edu.uci.eecs.specExtraction.SpecNaming;
22 import edu.uci.eecs.specExtraction.WrongAnnotationException;
23 import edu.uci.eecs.utilParser.ParseException;
27 * This class represents the engine to generate instrumented code. To construct
28 * an object of this file, users need provide a string that represents the
29 * sub-directory under the benchmarks directory, then the engine will explore
30 * all the C/C++ files that ends with ".cc/.cpp/.c/.h" and extract specification
31 * annotations and generate instrumented code in the generated directory.
37 public class CodeGenerator {
38 // Files that we need to process
39 private ArrayList<File> files;
41 // Code addition list --- per file
42 private ArrayList<CodeAdditions> allAdditions;
43 // Line change map list --- per file; Each map represents the
44 // line->InterfaceConstruct mapping that will rename the interface
46 private ArrayList<HashMap<Integer, InterfaceConstruct>> renamedLinesMapList;
48 // The string that users provide as a sub-directory in the benchmarks
49 // directory: e.g. ms-queue
50 public final String dirName;
52 // The original directory --- the benchmarks directory: e.g.
53 // ~/model-checker/benchmarks/
54 public final String originalDir;
55 // The directory for generated files: e.g. ~/model-checker/test-cdsspec/
56 public final String generatedDir;
58 // The specification annotation extractor
59 private SpecExtractor extractor;
61 public CodeGenerator(String dirName) {
62 this.dirName = dirName;
63 originalDir = Environment.BenchmarksDir + dirName + "/";
64 generatedDir = Environment.GeneratedFilesDir + dirName + "/";
66 files = this.getSrcFiles(originalDir);
67 } catch (FileNotFoundException e) {
70 extractor = new SpecExtractor();
72 extractor.extract(files);
73 } catch (WrongAnnotationException e) {
75 } catch (ParseException e) {
82 * This function initializes the list of code additions and line changes for
83 * all the files. For the code additions of a file, we sort them in an
84 * increasing order by the inserting line number.
88 private void getAllCodeChanges() {
89 allAdditions = new ArrayList<CodeAdditions>();
90 renamedLinesMapList = new ArrayList<HashMap<Integer, InterfaceConstruct>>();
91 for (int i = 0; i < files.size(); i++) {
92 File file = files.get(i);
93 // One CodeAdditions per file
94 CodeAdditions additions = new CodeAdditions(file);
95 // Add the additions for this file to the list
96 allAdditions.add(additions);
98 // One CodeChange per file
99 HashMap<Integer, InterfaceConstruct> renamedLinesMap = new HashMap<Integer, InterfaceConstruct>();
100 // Add it the the list
101 renamedLinesMapList.add(renamedLinesMap);
103 // Extract all the additions
104 ArrayList<OPConstruct> OPList = extractor.OPListMap.get(file);
105 EntryConstruct entry = extractor.entryMap.get(file);
106 ArrayList<DefineConstruct> defineList = extractor.defineListMap
108 ArrayList<InterfaceConstruct> interfaceList = extractor.interfaceListMap
111 CodeAddition addition = null;
112 // For ordering point constructs
113 if (OPList != null) {
114 for (OPConstruct con : OPList) {
115 code = CodeGeneratorUtils.Generate4OPConstruct(con);
116 addition = new CodeAddition(con.beginLineNum, code);
117 additions.addCodeAddition(addition);
120 // For entry constructs
122 code = CodeGeneratorUtils.Generate4Entry(entry);
123 addition = new CodeAddition(entry.beginLineNum, code);
124 additions.addCodeAddition(addition);
126 // For define constructs
127 if (defineList != null) {
128 for (DefineConstruct con : defineList) {
129 code = CodeGeneratorUtils.Generate4Define(con);
130 addition = new CodeAddition(con.endLineNum,
132 additions.addCodeAddition(addition);
135 // For interface constructs
136 if (interfaceList != null) {
137 for (InterfaceConstruct con : interfaceList) {
138 code = CodeGeneratorUtils.GenerateInterfaceWrapper(con);
139 addition = new CodeAddition(con.getEndLineNumFunction(),
141 additions.addCodeAddition(addition);
142 // Record the line to be changed
143 renamedLinesMap.put(con.endLineNum + 1, con);
147 // Sort additions by line number increasingly
154 * For a specific file, given the code additions and line changes mapping
155 * for that file, this function will generate the new code for that file and
156 * write it back to the destination directory.
160 * The file to be processed
162 * The sorted code additions for the file
163 * @param renamedLinesMap
164 * The line change mapping for the file
166 private void writeCodeChange(File file, CodeAdditions additions,
167 HashMap<Integer, InterfaceConstruct> renamedLinesMap) {
168 Code newCode = new Code();
169 BufferedReader br = null;
170 LineNumberReader lineReader = null;
172 String curLine = null;
174 String dest = generatedDir + file.getName();
175 CodeAddition curAddition = null;
176 int additionIdx = -1;
177 if (!additions.isEmpty()) {
179 curAddition = additions.codeAdditions.get(0);
183 br = new BufferedReader(new FileReader(file));
184 lineReader = new LineNumberReader(br);
185 while ((curLine = lineReader.readLine()) != null) {
186 lineNum = lineReader.getLineNumber();
187 InterfaceConstruct construct = null;
188 if ((construct = renamedLinesMap.get(lineNum)) != null) {
190 String newLine = construct.getFunctionHeader()
191 .getRenamedFuncLine();
192 newCode.addLine(newLine);
194 // First add the current line
195 newCode.addLine(curLine);
196 // Then check if we need to add code
197 if (curAddition != null
198 && lineNum == curAddition.insertingLine) {
199 // Need to insert code
200 newCode.addLines(curAddition.code);
201 // Increase to the next code addition
203 curAddition = additionIdx == additions.codeAdditions
204 .size() ? null : additions.codeAdditions
209 // Write new code change to destination
210 CodeGeneratorUtils.write2File(dest, newCode.lines);
211 // System.out.println("/*************** " + file.getName()
212 // + " *************/");
213 // System.out.println(newCode);
214 } catch (FileNotFoundException e) {
216 } catch (IOException e) {
223 * This function is the main interface for the CodeGenerator class. After
224 * constructing a CodeGenerator object, users can call this function to
225 * complete the code generation and file writing process.
228 public void generateCode() {
229 // Extract all the code additions and line change
232 // Generate the header file and CPP file
233 Code generatedHeader = CodeGeneratorUtils
234 .GenerateCDSSpecHeaderFile(extractor);
235 Code generatedCPP = CodeGeneratorUtils
236 .GenerateCDSSpecCPPFile(extractor);
238 .write2File(generatedDir + SpecNaming.CDSSpecGeneratedName
239 + ".h", generatedHeader.lines);
240 CodeGeneratorUtils.write2File(generatedDir
241 + SpecNaming.CDSSpecGeneratedCPP, generatedCPP.lines);
243 // Iterate over each file
244 for (int i = 0; i < files.size(); i++) {
245 File file = files.get(i);
246 CodeAdditions additions = allAdditions.get(i);
247 HashMap<Integer, InterfaceConstruct> renamedLinesMap = renamedLinesMapList
249 writeCodeChange(file, additions, renamedLinesMap);
255 * This is just a testing function that outputs the generated code, but not
256 * actually write them to the disk.
259 private void testGenerator() {
260 // Test code generation
261 Code generatedHeader = CodeGeneratorUtils
262 .GenerateCDSSpecHeaderFile(extractor);
263 Code generatedCPP = CodeGeneratorUtils
264 .GenerateCDSSpecCPPFile(extractor);
266 System.out.println("/***** Generated header file *****/");
267 System.out.println(generatedHeader);
268 System.out.println("/***** Generated cpp file *****/");
269 System.out.println(generatedCPP);
271 for (File file : extractor.OPListMap.keySet()) {
272 ArrayList<OPConstruct> list = extractor.OPListMap.get(file);
273 for (OPConstruct con : list) {
274 Code code = CodeGeneratorUtils.Generate4OPConstruct(con);
275 System.out.println("/***** *****/");
276 System.out.println(con.annotation);
277 System.out.println(code);
281 for (File f : extractor.entryMap.keySet()) {
282 EntryConstruct con = extractor.entryMap.get(f);
283 System.out.println("/***** *****/");
284 System.out.println(con.annotation);
285 System.out.println(CodeGeneratorUtils.Generate4Entry(con));
288 for (File file : extractor.interfaceListMap.keySet()) {
289 ArrayList<InterfaceConstruct> list = extractor.interfaceListMap
291 for (InterfaceConstruct con : list) {
292 Code code = CodeGeneratorUtils.GenerateInterfaceWrapper(con);
293 System.out.println("/***** Interface wrapper *****/");
294 System.out.println(con.getFunctionHeader().getHeaderLine());
296 .println(con.getFunctionHeader().getRenamedFuncLine());
297 System.out.println(code);
302 public ArrayList<File> getSrcFiles(String dirName)
303 throws FileNotFoundException {
304 ArrayList<File> res = new ArrayList<File>();
305 File dir = new File(dirName);
306 if (dir.isDirectory() && dir.exists()) {
307 for (String file : dir.list()) {
308 if (file.endsWith(".h") || file.endsWith(".c")
309 || file.endsWith(".cc") || file.endsWith(".cpp")) {
310 res.add(new File(dir.getAbsolutePath() + "/" + file));
314 throw new FileNotFoundException(dirName
315 + " is not a valid directory!");
320 static public void main(String[] args) {
321 // String[] dirNames = { Environment.REGISTER, Environment.MS_QUEUE,
322 // Environment.LINUXRWLOCKS, Environment.MCS_LOCK,
323 // Environment.DEQUE, Environment.TREIBER_STACK };
324 String[] dirNames = args;
326 for (int i = 0; i < dirNames.length; i++) {
327 String dirName = dirNames[i];
328 System.out.println("/********** Processing " + dirName
330 CodeGenerator generator = new CodeGenerator(dirName);
331 generator.generateCode();