more
[cdsspec-compiler.git] / src / edu / uci / eecs / specCompiler / codeGenerator / CodeGenerator.java
1 package edu.uci.eecs.specCompiler.codeGenerator;
2
3 import java.io.BufferedReader;
4 import java.io.File;
5 import java.io.FileNotFoundException;
6 import java.io.FileReader;
7 import java.io.IOException;
8 import java.util.ArrayList;
9 import java.util.Collections;
10 import java.util.HashMap;
11 import java.util.HashSet;
12 import java.util.Iterator;
13
14 import edu.uci.eecs.specCompiler.specExtraction.CPDefineCheckConstruct;
15 import edu.uci.eecs.specCompiler.specExtraction.CPDefineConstruct;
16 import edu.uci.eecs.specCompiler.specExtraction.ClassEndConstruct;
17 import edu.uci.eecs.specCompiler.specExtraction.ConditionalInterface;
18 import edu.uci.eecs.specCompiler.specExtraction.Construct;
19 import edu.uci.eecs.specCompiler.specExtraction.EntryPointConstruct;
20 import edu.uci.eecs.specCompiler.specExtraction.FunctionHeader;
21 import edu.uci.eecs.specCompiler.specExtraction.GlobalConstruct;
22 import edu.uci.eecs.specCompiler.specExtraction.IDExtractor;
23 import edu.uci.eecs.specCompiler.specExtraction.InterfaceConstruct;
24 import edu.uci.eecs.specCompiler.specExtraction.InterfaceDefineConstruct;
25 import edu.uci.eecs.specCompiler.specExtraction.ParserUtils;
26 import edu.uci.eecs.specCompiler.specExtraction.PotentialCPDefineConstruct;
27 import edu.uci.eecs.specCompiler.specExtraction.SequentialDefineSubConstruct;
28 import edu.uci.eecs.specCompiler.specExtraction.SourceFileInfo;
29 import edu.uci.eecs.specCompiler.specExtraction.SpecExtractor;
30
31 /**
32  * <p>
33  * This class will generate the annotated C code that can run on the current
34  * model checker.
35  * </p>
36  * 
37  * @author peizhaoo
38  * 
39  */
40 public class CodeGenerator {
41         private SemanticsChecker _semantics;
42         private SpecExtractor _extractor;
43
44         private File[] srcFiles;
45
46         private HashMap<File, SourceFileInfo> srcFilesInfo;
47
48         private HashMap<File, ArrayList<CodeAddition>> codeAdditions;
49         private String homeDir;
50
51         public CodeGenerator(File[] srcFiles) {
52                 this.srcFiles = srcFiles;
53                 _extractor = new SpecExtractor();
54                 _extractor.extract(srcFiles);
55
56                 this.srcFilesInfo = _extractor.srcFilesInfo;
57
58                 this.codeAdditions = new HashMap<File, ArrayList<CodeAddition>>();
59
60                 _semantics = new SemanticsChecker(_extractor);
61                 try {
62                         _semantics.check();
63                         System.out.println(_semantics);
64                 } catch (SemanticsCheckerException e) {
65                         e.printStackTrace();
66                 }
67         }
68
69         /**
70          * <p>
71          * Generate all the global code, including the "@DefineVar" in each
72          * "@Interface" define
73          * </p>
74          */
75         private void globalConstruct2Code(GlobalConstruct construct) {
76                 ArrayList<String> newCode = CodeVariables.generateGlobalVarDeclaration(
77                                 _semantics, construct);
78                 // Add it to the codeAdditions
79                 if (!codeAdditions.containsKey(construct.file)) {
80                         codeAdditions.put(construct.file, new ArrayList<CodeAddition>());
81                 }
82                 CodeAddition addition = new CodeAddition(construct.beginLineNum,
83                                 newCode);
84                 codeAdditions.get(construct.file).add(addition);
85                 newCode = CodeVariables.generateStaticVarDefine(_semantics, construct);
86                 if (newCode.size() > 0) {
87                         addition = new CodeAddition(
88                                         _semantics.getClassEndConstruct().beginLineNum, newCode);
89                         codeAdditions.get(construct.file).add(addition);
90                 }
91         }
92
93         // Wrap the interface and then renaem it
94         private void interface2Code(InterfaceConstruct construct) {
95                 // If there's no define construct for it, we generate the wrapper just
96                 // in place without declaration
97                 InterfaceDefineConstruct defineConstruct = _semantics.interfaceName2DefineConstruct
98                                 .get(construct.name);
99                 ArrayList<String> newCode;
100                 int lineNum;
101                 CodeAddition addition;
102                 // Then generate the wrapper if necessary
103                 if (defineConstruct != null) { // Need to have a wrapper declaration
104                         newCode = CodeVariables.generateInterfaceWrapperDeclaration(
105                                         _semantics, construct);
106                         lineNum = construct.beginLineNum;
107                         // Add the wrapper declaration
108                         addition = new CodeAddition(lineNum, newCode);
109                         if (!codeAdditions.containsKey(construct.file)) {
110                                 codeAdditions
111                                                 .put(construct.file, new ArrayList<CodeAddition>());
112                         }
113                         codeAdditions.get(construct.file).add(addition);
114
115                         // Add the wrapper definition
116                         newCode = CodeVariables.generateInterfaceWrapperDefinition(
117                                         _semantics, construct);
118                         lineNum = defineConstruct.beginLineNum;
119                         // Add the wrapper declaration
120                         addition = new CodeAddition(lineNum, newCode);
121                         if (!codeAdditions.containsKey(defineConstruct.file)) {
122                                 codeAdditions.put(defineConstruct.file,
123                                                 new ArrayList<CodeAddition>());
124                         }
125                         codeAdditions.get(defineConstruct.file).add(addition);
126                 } else { // No declaration needed but should add forward declaration in
127                                         // Class
128                         // Last generate the definition
129                         newCode = new ArrayList<String>();
130                         if (_semantics.getOption("CLASS") == null) {
131                                 newCode.addAll(CodeVariables
132                                                 .generateInterfaceWrapperDeclaration(_semantics,
133                                                                 construct));
134                         }
135                         newCode.addAll(CodeVariables.generateInterfaceWrapperDefinition(
136                                         _semantics, construct));
137                         lineNum = construct.beginLineNum;
138                         // Add the wrapper declaration
139                         addition = new CodeAddition(lineNum, newCode);
140                         if (!codeAdditions.containsKey(construct.file)) {
141                                 codeAdditions
142                                                 .put(construct.file, new ArrayList<CodeAddition>());
143                         }
144                         codeAdditions.get(construct.file).add(addition);
145                 }
146
147                 // Don't forget to rename the interface
148                 CodeVariables.renameInterface(_semantics, construct);
149         }
150
151         private void potentialCPDefine2Code(PotentialCPDefineConstruct construct) {
152                 int lineNum = construct.beginLineNum;
153                 ArrayList<String> newCode = CodeVariables.generatePotentialCPDefine(
154                                 _semantics, construct);
155
156                 CodeAddition addition = new CodeAddition(lineNum, newCode);
157                 if (!codeAdditions.containsKey(construct.file)) {
158                         codeAdditions.put(construct.file, new ArrayList<CodeAddition>());
159                 }
160                 codeAdditions.get(construct.file).add(addition);
161         }
162
163         private void CPDefine2Code(CPDefineConstruct construct) {
164                 int lineNum = construct.beginLineNum;
165                 ArrayList<String> newCode = CodeVariables.generateCPDefine(_semantics,
166                                 construct);
167
168                 CodeAddition addition = new CodeAddition(lineNum, newCode);
169                 if (!codeAdditions.containsKey(construct.file)) {
170                         codeAdditions.put(construct.file, new ArrayList<CodeAddition>());
171                 }
172                 codeAdditions.get(construct.file).add(addition);
173         }
174
175         private void CPDefineCheck2Code(CPDefineCheckConstruct construct) {
176                 int lineNum = construct.beginLineNum;
177                 ArrayList<String> newCode = CodeVariables.generateCPDefineCheck(
178                                 _semantics, construct);
179
180                 CodeAddition addition = new CodeAddition(lineNum, newCode);
181                 if (!codeAdditions.containsKey(construct.file)) {
182                         codeAdditions.put(construct.file, new ArrayList<CodeAddition>());
183                 }
184                 codeAdditions.get(construct.file).add(addition);
185         }
186
187         /**
188          * private void ClassEnd2Code(ClassEndConstruct construct) { int lineNum =
189          * construct.beginLineNum; ArrayList<String> newCode =
190          * CodeVariables.generateStaticVarDefine(_semantics,
191          * _semantics.getGlobalConstruct());
192          * 
193          * CodeAddition addition = new CodeAddition(lineNum, newCode); if
194          * (!codeAdditions.containsKey(construct.file)) {
195          * codeAdditions.put(construct.file, new ArrayList<CodeAddition>()); }
196          * codeAdditions.get(construct.file).add(addition); }
197          */
198
199         private void EntryPoint2Code(EntryPointConstruct construct) {
200                 int lineNum = construct.beginLineNum;
201                 ArrayList<String> newCode = new ArrayList<String>();
202                 newCode.addAll(CodeVariables.generateEntryPointInitCall());
203
204                 CodeAddition addition = new CodeAddition(lineNum, newCode);
205                 if (!codeAdditions.containsKey(construct.file)) {
206                         codeAdditions.put(construct.file, new ArrayList<CodeAddition>());
207                 }
208                 codeAdditions.get(construct.file).add(addition);
209         }
210
211         private ArrayList<String> insertAnnotation2Src(
212                         ArrayList<CodeAddition> additions, ArrayList<String> content) {
213                 int totalSize = content.size();
214                 for (int i = 0; i < additions.size(); i++) {
215                         totalSize += additions.size();
216                 }
217                 ArrayList<String> newContent = new ArrayList<String>(totalSize);
218                 int curSrcLine = 0;
219                 for (int i = 0; i < additions.size(); i++) {
220                         CodeAddition addition = additions.get(i);
221                         if (curSrcLine < addition.lineNum) {
222                                 // Be careful, subList is the interval [begin, end)
223                                 newContent
224                                                 .addAll(content.subList(curSrcLine, addition.lineNum));
225                                 curSrcLine = addition.lineNum;
226                         }
227                         newContent.addAll(addition.newCode);
228                 }
229                 newContent.addAll(content.subList(curSrcLine, content.size()));
230                 return newContent;
231         }
232
233         public void generateCode() {
234                 for (int i = 0; i < _semantics.constructs.size(); i++) {
235                         Construct construct = _semantics.constructs.get(i);
236                         if (construct instanceof GlobalConstruct) {
237                                 globalConstruct2Code((GlobalConstruct) construct);
238                         } else if (construct instanceof InterfaceConstruct) {
239                                 interface2Code((InterfaceConstruct) construct);
240                         } else if (construct instanceof PotentialCPDefineConstruct) {
241                                 potentialCPDefine2Code((PotentialCPDefineConstruct) construct);
242                         } else if (construct instanceof CPDefineConstruct) {
243                                 CPDefine2Code((CPDefineConstruct) construct);
244                         } else if (construct instanceof CPDefineCheckConstruct) {
245                                 CPDefineCheck2Code((CPDefineCheckConstruct) construct);
246                         } else if (construct instanceof EntryPointConstruct) {
247                                 EntryPoint2Code((EntryPointConstruct) construct);
248                         }
249                 }
250
251                 // ClassEndConstruct endConstruct = _semantics.getClassEndConstruct();
252                 // if (endConstruct != null) {
253                 // ClassEnd2Code(endConstruct);
254                 // }
255
256                 // Sort code additions
257                 for (File file : codeAdditions.keySet()) {
258                         ArrayList<CodeAddition> additions = codeAdditions.get(file);
259
260                         if (additions.size() == 0) // Simply do nothing
261                                 continue;
262                         ArrayList<String> content = _semantics.srcFilesInfo.get(file).content;
263                         Collections.sort(additions, CodeAddition.lineNumComparator);
264                         // Insert generated annotation to the source files
265                         ArrayList<String> newContent = insertAnnotation2Src(additions,
266                                         content);
267                         // Write it back to file
268                         ParserUtils.write2File(file, newContent);
269                 }
270         }
271
272         public static void main(String[] argvs) {
273                 String homeDir = Environment.HOME_DIRECTORY;
274
275                 File[] srcLinuxRWLocks = { new File(homeDir
276                                 + "/benchmark/linuxrwlocks/linuxrwlocks.c") };
277
278                 File[] srcHashtable = {
279                                 new File(homeDir
280                                                 + "/benchmark/cliffc-hashtable/cliffc_hashtable.h"),
281                                 new File(homeDir + "/benchmark/cliffc-hashtable/main.cc") };
282
283                 File[] srcMSQueue = {
284                                 new File(homeDir + "/benchmark/ms-queue/my_queue.c"),
285                                 new File(homeDir + "/benchmark/ms-queue/main.c"),
286                                 new File(homeDir + "/benchmark/ms-queue/my_queue.h") };
287
288                 File[] srcRCU = { new File(homeDir
289                                 + "/benchmark/read-copy-update/rcu.cc") };
290
291                 File[] srcDeque = {
292                                 new File(homeDir + "/benchmark/chase-lev-deque-bugfix/deque.c"),
293                                 new File(homeDir + "/benchmark/chase-lev-deque-bugfix/main.c"),
294                                 new File(homeDir + "/benchmark/chase-lev-deque-bugfix/deque.h") };
295
296                 File[] srcMCSLock = {
297                                 new File(homeDir + "/benchmark/mcs-lock/mcs-lock.cc"),
298                                 new File(homeDir + "/benchmark/mcs-lock/mcs-lock.h") };
299
300                 File[] srcSPSCQueue = {
301                                 new File(homeDir + "/benchmark/spsc-bugfix/spsc-queue.cc"),
302                                 new File(homeDir + "/benchmark/spsc-bugfix/eventcount.h"),
303                                 new File(homeDir + "/benchmark/spsc-bugfix/queue.h") };
304
305                 File[] srcMPMCQueue = {
306                                 new File(homeDir + "/benchmark/mpmc-queue/mpmc-queue.h"),
307                                 new File(homeDir + "/benchmark/mpmc-queue/mpmc-queue.cc") };
308
309                 File[][] sources = { srcLinuxRWLocks, srcHashtable, srcMSQueue, srcRCU,
310                                 srcDeque, srcMCSLock, srcSPSCQueue, srcMPMCQueue };
311
312 //               File[][] sources = { srcDeque };
313                 // Compile all the benchmarks
314                 for (int i = 0; i < sources.length; i++) {
315                         CodeGenerator gen = new CodeGenerator(sources[i]);
316                         gen.generateCode();
317                 }
318         }
319 }