This is the PPoPP17 artifact version
authorPeizhao Ou <peizhaoo@uci.edu>
Wed, 7 Dec 2016 21:54:08 +0000 (13:54 -0800)
committerPeizhao Ou <peizhaoo@uci.edu>
Wed, 7 Dec 2016 21:54:08 +0000 (13:54 -0800)
95 files changed:
Makefile
action.cc
action.h
cdsspec-compiler/build.xml [new file with mode: 0644]
cdsspec-compiler/clean.sh [new file with mode: 0755]
cdsspec-compiler/generate.sh [new file with mode: 0755]
cdsspec-compiler/grammer/util.jj [new file with mode: 0644]
cdsspec-compiler/lib/javacc.jar [new file with mode: 0644]
cdsspec-compiler/notes/definition.cc [new file with mode: 0644]
cdsspec-compiler/notes/generated_code_examples.txt [new file with mode: 0644]
cdsspec-compiler/notes/impl.txt [new file with mode: 0644]
cdsspec-compiler/notes/interesting_examples.txt [new file with mode: 0644]
cdsspec-compiler/notes/nondeterm-spec.txt [new file with mode: 0644]
cdsspec-compiler/notes/register-example/Makefile [new file with mode: 0644]
cdsspec-compiler/notes/register-example/cdsspec-generated.h [new file with mode: 0644]
cdsspec-compiler/notes/register-example/register.cc [new file with mode: 0644]
cdsspec-compiler/notes/register-example/register.cc.original [new file with mode: 0644]
cdsspec-compiler/notes/register-example/register.h [new file with mode: 0644]
cdsspec-compiler/notes/sequential_spec.txt [new file with mode: 0644]
cdsspec-compiler/run-javacc.sh [new file with mode: 0755]
cdsspec-compiler/src/edu/uci/eecs/codeGenerator/CodeAdditions.java [new file with mode: 0644]
cdsspec-compiler/src/edu/uci/eecs/codeGenerator/CodeGenerator.java [new file with mode: 0644]
cdsspec-compiler/src/edu/uci/eecs/codeGenerator/CodeGeneratorUtils.java [new file with mode: 0644]
cdsspec-compiler/src/edu/uci/eecs/codeGenerator/Environment.java [new file with mode: 0644]
cdsspec-compiler/src/edu/uci/eecs/specExtraction/Code.java [new file with mode: 0644]
cdsspec-compiler/src/edu/uci/eecs/specExtraction/CommutativityRule.java [new file with mode: 0644]
cdsspec-compiler/src/edu/uci/eecs/specExtraction/Construct.java [new file with mode: 0644]
cdsspec-compiler/src/edu/uci/eecs/specExtraction/DefineConstruct.java [new file with mode: 0644]
cdsspec-compiler/src/edu/uci/eecs/specExtraction/EntryConstruct.java [new file with mode: 0644]
cdsspec-compiler/src/edu/uci/eecs/specExtraction/FunctionHeader.java [new file with mode: 0644]
cdsspec-compiler/src/edu/uci/eecs/specExtraction/GlobalConstruct.java [new file with mode: 0644]
cdsspec-compiler/src/edu/uci/eecs/specExtraction/InterfaceConstruct.java [new file with mode: 0644]
cdsspec-compiler/src/edu/uci/eecs/specExtraction/OPConstruct.java [new file with mode: 0644]
cdsspec-compiler/src/edu/uci/eecs/specExtraction/OPType.java [new file with mode: 0644]
cdsspec-compiler/src/edu/uci/eecs/specExtraction/QualifiedName.java [new file with mode: 0644]
cdsspec-compiler/src/edu/uci/eecs/specExtraction/SpecExtractor.java [new file with mode: 0644]
cdsspec-compiler/src/edu/uci/eecs/specExtraction/SpecNaming.java [new file with mode: 0644]
cdsspec-compiler/src/edu/uci/eecs/specExtraction/SpecUtils.java [new file with mode: 0644]
cdsspec-compiler/src/edu/uci/eecs/specExtraction/VariableDeclaration.java [new file with mode: 0644]
cdsspec-compiler/src/edu/uci/eecs/specExtraction/WrongAnnotationException.java [new file with mode: 0644]
common.h
common.mk
execution.cc
execution.h
impatomic.cc
include/cdsannotate.h
include/impatomic.h
include/model_memory.h [new file with mode: 0644]
include/stdatomic.h
main.cc
model.cc
model.h
mymemory.cc
mymemory.h
nodestack.cc
nodestack.h
params.h
plugins.cc
scfence/scfence.cc
spec-analysis/.gitignore [new file with mode: 0644]
spec-analysis/Makefile [new file with mode: 0644]
spec-analysis/cdsspec.h [new file with mode: 0644]
spec-analysis/executiongraph.cc [new file with mode: 0644]
spec-analysis/executiongraph.h [new file with mode: 0644]
spec-analysis/include/specannotation-api.h [new file with mode: 0644]
spec-analysis/methodcall.cc [new file with mode: 0644]
spec-analysis/methodcall.h [new file with mode: 0644]
spec-analysis/spec_common.h [new file with mode: 0644]
spec-analysis/specanalysis.cc [new file with mode: 0644]
spec-analysis/specanalysis.h [new file with mode: 0644]
spec-analysis/specannotation.cc [new file with mode: 0644]
spec-analysis/specannotation.h [new file with mode: 0644]
test-cdsspec/Makefile [new file with mode: 0644]
test-cdsspec/benchmarks.mk [new file with mode: 0644]
test-cdsspec/chase-lev-deque-bugfix/Makefile [new file with mode: 0644]
test-cdsspec/cleanse.sh [new file with mode: 0755]
test-cdsspec/concurrent-hashmap/Makefile [new file with mode: 0644]
test-cdsspec/include/unrelacy.h [new file with mode: 0644]
test-cdsspec/linuxrwlocks/Makefile [new file with mode: 0644]
test-cdsspec/mcs-lock/Makefile [new file with mode: 0644]
test-cdsspec/mpmc-queue/Makefile [new file with mode: 0644]
test-cdsspec/ms-queue/.gitignore [new file with mode: 0644]
test-cdsspec/ms-queue/Makefile [new file with mode: 0644]
test-cdsspec/performance.sh [new file with mode: 0755]
test-cdsspec/read-copy-update/Makefile [new file with mode: 0644]
test-cdsspec/run-all.sh [new file with mode: 0755]
test-cdsspec/run.sh [new file with mode: 0755]
test-cdsspec/seqlock/Makefile [new file with mode: 0644]
test-cdsspec/spsc-bugfix/Makefile [new file with mode: 0644]
test-cdsspec/ticket-lock/Makefile [new file with mode: 0644]
test/Makefile
test/iriw.cc [deleted file]
test/iriw_wildcard.cc [deleted file]
threads.cc
traceanalysis.h

index eb84076dcae075324dc3353d52d72617c578fcfe..56d0dab68bd7a39807cedf7f4f07157eeadc960e 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 include common.mk
 
-SCFENCE_DIR := scfence
+SPEC_DIR := spec-analysis
 
 OBJECTS := libthreads.o schedule.o model.o threads.o librace.o action.o \
           nodestack.o clockvector.o main.o snapshot-interface.o cyclegraph.o \
@@ -8,7 +8,9 @@ OBJECTS := libthreads.o schedule.o model.o threads.o librace.o action.o \
           snapshot.o malloc.o mymemory.o common.o mutex.o promise.o conditionvariable.o \
           context.o scanalysis.o execution.o plugins.o libannotate.o
 
-CPPFLAGS += -Iinclude -I. -I$(SCFENCE_DIR)
+include $(SPEC_DIR)/Makefile
+
+CPPFLAGS += -Iinclude -I. -I$(SPEC_DIR)
 LDFLAGS := -ldl -lrt -rdynamic
 SHARED := -shared
 
@@ -34,28 +36,27 @@ docs: *.c *.cc *.h README.html
 README.html: README.md
        $(MARKDOWN) $< > $@
 
+$(LIB_SO): $(OBJECTS)
+       $(CXX) $(SHARED) -o $(LIB_SO) $+ $(LDFLAGS)
 
 malloc.o: malloc.c
-       $(CC) -fPIC -c malloc.c -DMSPACES -DONLY_MSPACES -DHAVE_MMAP=0 $(CPPFLAGS) -Wno-unused-variable
-
-%.o : %.cc
-       $(CXX) -MMD -MF .$@.d -fPIC -c $< $(CPPFLAGS)
-
-include $(SCFENCE_DIR)/Makefile
+       $(CC) -fPIC -c malloc.c -DMSPACES -DONLY_MSPACES -DHAVE_MMAP=0 $(CPPLAGS) -Wno-unused-variable
 
--include $(wildcard $(SCFENCE_DIR)/.*.d)
-
-$(LIB_SO): $(OBJECTS)
-       $(CXX) $(SHARED) -o $(LIB_SO) $+ $(LDFLAGS)
+%.o: %.cc
+       $(CXX) -MMD -MF $(dir $@).$(notdir $@).d -fPIC -c $< -o $@ $(CPPFLAGS)
 
 %.pdf: %.dot
        dot -Tpdf $< -o $@
 
--include $(OBJECTS:%=.%.d)
+# Replace all the basename with 
+ALL_DEPS := $(shell echo $(OBJECTS) | sed -E 's/([^ ]*\/)?([^\/ ]*)/\1\.\2.d/g')
+-include $(ALL_DEPS)
+#-include $(OBJECTS:%=.%.d)
+
 
 PHONY += clean
 clean:
-       rm -f *.o *.so .*.d *.pdf *.dot $(SCFENCE_DIR)/.*.d $(SCFENCE_DIR)/*.o
+       rm -f *.o *.so $(ALL_DEPS) *.pdf *.dot $(OBJECTS)
        $(MAKE) -C $(TESTS_DIR) clean
 
 PHONY += mrclean
index d4c6253caf20c23411c60ba350a91760c386e6fc..2e9deced9ac8e7c7a23f50f054f74b50e51017a9 100644 (file)
--- a/action.cc
+++ b/action.cc
@@ -9,7 +9,6 @@
 #include "common.h"
 #include "threads-model.h"
 #include "nodestack.h"
-#include "wildcard.h"
 
 #define ACTION_INITIAL_CLOCK 0
 
@@ -35,7 +34,6 @@ ModelAction::ModelAction(action_type_t type, memory_order order, void *loc,
                uint64_t value, Thread *thread) :
        type(type),
        order(order),
-       original_order(order),
        location(loc),
        value(value),
        reads_from(NULL),
@@ -555,7 +553,7 @@ const char * ModelAction::get_type_str() const
                case ATOMIC_WAIT: return "wait";
                case ATOMIC_NOTIFY_ONE: return "notify one";
          case ATOMIC_NOTIFY_ALL: return "notify all";
-         case ATOMIC_ANNOTATION: return "annotation";
+         case ATOMIC_ANNOTATION: return "atomic annotation";
                default: return "unknown type";
        };
 }
index c8ad85bcc99bf1e051771d7a6779b99f58f0dae7..ad3b828a6a5da33e61140eb0f9fa57831c00fefc 100644 (file)
--- a/action.h
+++ b/action.h
@@ -96,8 +96,6 @@ public:
        thread_id_t get_tid() const { return tid; }
        action_type get_type() const { return type; }
        memory_order get_mo() const { return order; }
-       memory_order get_original_mo() const { return original_order; }
-       void set_mo(memory_order order) { this->order = order; }
        void * get_location() const { return location; }
        modelclock_t get_seq_number() const { return seq_number; }
        uint64_t get_value() const { return value; }
@@ -196,9 +194,6 @@ private:
        /** @brief The memory order for this operation. */
        memory_order order;
 
-       /** @brief The original memory order parameter for this operation. */
-       memory_order original_order;
-
        /** @brief A pointer to the memory location for this action. */
        void *location;
 
diff --git a/cdsspec-compiler/build.xml b/cdsspec-compiler/build.xml
new file mode 100644 (file)
index 0000000..065bcad
--- /dev/null
@@ -0,0 +1,24 @@
+<project name="SpecCheckerCompiler" default="compile" basedir=".">
+  <!-- Compile variables -->
+  <property name="src" location="src"/>
+  <property name="build" location="classes"/>
+  <property name="lib" location="lib/javacc.jar"/>
+
+  <target name="init">
+  <!-- Create the build directory -->
+    <mkdir dir="${build}"/>
+  </target>
+
+  <target name="compile" depends="init"
+        description="compile the source">
+    <!-- Compile the code from ${src} into ${build} -->
+    <javac srcdir="${src}" destdir="${build}" classpath="${lib}"
+               includeantruntime="false" />
+  </target>
+
+  <target name="clean"
+        description="clean up">
+    <!-- Delete the ${build} directory trees -->
+    <delete dir="${build}"/>
+  </target>
+</project>
diff --git a/cdsspec-compiler/clean.sh b/cdsspec-compiler/clean.sh
new file mode 100755 (executable)
index 0000000..22c313e
--- /dev/null
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+AutoGenDir=$(pwd)/src/edu/uci/eecs/utilParser
+echo "Deleting the old generated java files."
+rm -rf $AutoGenDir
+
+echo "Deleting the class files."
+rm -rf ./classes
diff --git a/cdsspec-compiler/generate.sh b/cdsspec-compiler/generate.sh
new file mode 100755 (executable)
index 0000000..38ec8b2
--- /dev/null
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+BENCH=(ms-queue linuxrwlocks mcs-lock \
+    chase-lev-deque-bugfix spsc-bugfix mpmc-queue ticket-lock \
+    concurrent-hashmap seqlock read-copy-update)
+
+ClassPath=$(dirname ${BASH_SOURCE[0]})/classes
+
+Class=edu/uci/eecs/codeGenerator/CodeGenerator
+
+# Use your own directory.
+# We recommend the original benchmarks and generated instrumented benchmarks to
+# be within the model checker's directory.
+BenchDir=../benchmarks
+GenerateDir=../test-cdsspec
+
+mkdir -p $GenerateDir
+
+java -cp $ClassPath $Class $BenchDir $GenerateDir ${BENCH[*]}
diff --git a/cdsspec-compiler/grammer/util.jj b/cdsspec-compiler/grammer/util.jj
new file mode 100644 (file)
index 0000000..5b5446b
--- /dev/null
@@ -0,0 +1,458 @@
+/* util.jj Grammer definition for utility functions */
+
+options {
+       STATIC = false;
+       JAVA_UNICODE_ESCAPE = true;
+}
+
+PARSER_BEGIN(UtilParser)
+package edu.uci.eecs.utilParser;
+import edu.uci.eecs.specExtraction.FunctionHeader;
+import edu.uci.eecs.specExtraction.QualifiedName;
+import edu.uci.eecs.specExtraction.VariableDeclaration;
+//import edu.uci.eecs.specExtraction.WrongAnnotationException;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.util.ArrayList;
+
+       
+public class UtilParser {
+       public static void main(String[] argvs)
+       throws ParseException, TokenMgrError {
+               try {
+                       File f = new File("./grammer/spec1.txt");
+                       FileInputStream fis = new FileInputStream(f);
+                       UtilParser parser = new UtilParser(fis);
+                       
+                       //parser.Test();
+                       System.out.println("Parsing finished!");
+               } catch (FileNotFoundException e) {
+                       e.printStackTrace();
+               }
+       }
+
+       public static ArrayList<VariableDeclaration> getTemplateArg(String line)
+       throws ParseException {
+               InputStream input = new ByteArrayInputStream(line.getBytes());
+               UtilParser parser = new UtilParser(input);
+               return parser.TemplateParamList();
+       }
+
+       public static FunctionHeader parseFuncHeader(String line)
+       throws ParseException {
+               InputStream input = new ByteArrayInputStream(line.getBytes());
+               UtilParser parser = new UtilParser(input);
+               return parser.FuncDecl();
+       }
+
+       public static VariableDeclaration parseDeclaration(String line)
+       throws ParseException {
+               InputStream input = new ByteArrayInputStream(line.getBytes());
+               UtilParser parser = new UtilParser(input);
+               return parser.Declaration();
+       }
+
+       public static String stringArray2String(ArrayList<String> content) {
+               StringBuilder sb = new StringBuilder();
+               if (content.size() == 1)
+                       return content.get(0);
+               for (int i = 0; i < content.size(); i++) {
+                       sb.append(content.get(i) + "\n");
+               }
+               return sb.toString();
+       }
+}
+PARSER_END(UtilParser)
+
+SKIP :
+{
+       " "
+|
+       "\n"
+|
+       "\r"
+|
+       "\r\n"
+|
+       "\t"
+}
+
+TOKEN :
+{
+/*   Specification & C/C++ shared tokens   */
+// Reserved keywords
+       <CONST: "const">
+|
+       <STRUCT: "struct">
+|
+       <CLASS: "class">
+|
+       <UNSIGNED: "unsigned">
+|
+       <TEMPLATE: "template">
+|
+       <INLINE: "inline">
+|
+       <STATIC: "static">
+|
+       <FOR: "for">
+|
+       <#DIGIT: ["0"-"9"]>
+|
+       <#LETTER: ["a"-"z", "A"-"Z"]>
+|
+       <IDENTIFIER: (<LETTER> | "_") (<LETTER> | <DIGIT> | "_")*>
+|
+       <POUND: "#">
+|
+       <OPEN_BRACKET: "[">
+|
+       <CLOSE_BRACKET: "]">
+|
+       <EQUALS: "=">
+|
+       <OPEN_PAREN: "(">
+|
+       <CLOSE_PAREN: ")">
+|
+       <OPEN_BRACE: "{">
+|
+       <CLOSE_BRACE: "}">
+|
+       <HB_SYMBOL: "->">
+|
+       <COMMA: ",">
+|
+/*   C/C++ only token*/
+       <DOT: ".">
+|
+       <DOLLAR: "$">
+|
+       <STAR: "*">
+|
+       <NEGATE: "~">
+|
+       <EXCLAMATION: "!">
+|
+       <AND: "&">
+|
+       <OR: "|">
+|
+       <MOD: "%">
+|
+       <PLUS: "+">
+|
+       <PLUSPLUS: "++">
+|
+       <MINUS: "-">
+|
+       <MINUSMINUS: "--">
+|
+       <DIVIDE: "/">
+|
+       <BACKSLASH: "\\">
+|
+       <LESS_THAN: "<">
+|
+       <GREATER_THAN: ">">
+|
+       <GREATER_EQUALS: ">=">
+|
+       <LESS_EQUALS: "<=">
+|
+       <LOGICAL_EQUALS: "==">
+|
+       <NOT_EQUALS: "!=">
+|
+       <LOGICAL_AND: "&&">
+|
+       <LOGICAL_OR: "||">
+|
+       <XOR: "^">
+|
+       <QUESTION_MARK: "?">
+|
+       <COLON: ":">
+|
+       <DOUBLECOLON: "::">
+|
+       <DOUBLELESSTHAN: "<<">
+|
+       <DOUBLEGREATERTHAN: ">>">
+|
+       <TRIPLEGREATERTHAN: ">>>">
+|
+       <PLUS_EQUALS: "+=">
+|
+       <MINUS_EQUALS: "-=">
+|
+       <TIMES_EQUALS: "*=">
+|
+       <DIVIDE_EQUALS: "/=">
+|
+       <MOD_EQUALS: "%=">
+|
+       <XOR_EQUALS: "^=">
+|
+       <OR_EQUALS: "|=">
+|
+       <AND_EQUALS: "&=">
+|
+       <SEMI_COLON: ";">
+|
+       <STRING_LITERAL:
+       "\""
+       ((~["\"","\\","\n","\r"])
+       | ("\\"
+               ( ["n","t","b","r","f","\\","'","\""]
+               | ["0"-"7"] ( ["0"-"7"] )?
+               | ["0"-"3"] ["0"-"7"]
+                       ["0"-"7"]
+               )
+               )
+       )*
+       "\"">
+|
+       <CHARACTER_LITERAL:
+       "'"
+       ((~["'","\\","\n","\r"])
+       | ("\\"
+               (["n","t","b","r","f","\\","'","\""]
+               | ["0"-"7"] ( ["0"-"7"] )?
+               | ["0"-"3"] ["0"-"7"]
+               ["0"-"7"]
+               )
+               )
+       )
+       "'">
+|
+       < INTEGER_LITERAL:
+        <DECIMAL_LITERAL> (["l","L"])?
+      | <HEX_LITERAL> (["l","L"])?
+      | <OCTAL_LITERAL> (["l","L"])?>
+|
+       < #DECIMAL_LITERAL: ["1"-"9"] (["0"-"9"])* >
+|
+       < #HEX_LITERAL: "0" ["x","X"] (["0"-"9","a"-"f","A"-"F"])+ >
+|
+       < #OCTAL_LITERAL: "0" (["0"-"7"])* >
+|
+       < FLOATING_POINT_LITERAL:
+        <DECIMAL_FLOATING_POINT_LITERAL>
+      | <HEXADECIMAL_FLOATING_POINT_LITERAL> >
+|
+       < #DECIMAL_FLOATING_POINT_LITERAL:
+        (["0"-"9"])+ "." (["0"-"9"])* (<DECIMAL_EXPONENT>)? (["f","F","d","D"])?
+      | "." (["0"-"9"])+ (<DECIMAL_EXPONENT>)? (["f","F","d","D"])?
+      | (["0"-"9"])+ <DECIMAL_EXPONENT> (["f","F","d","D"])?
+      | (["0"-"9"])+ (<DECIMAL_EXPONENT>)? ["f","F","d","D"]>
+|
+       < #DECIMAL_EXPONENT: ["e","E"] (["+","-"])? (["0"-"9"])+ >
+|
+       < #HEXADECIMAL_FLOATING_POINT_LITERAL:
+        "0" ["x", "X"] (["0"-"9","a"-"f","A"-"F"])+ (".")? <HEXADECIMAL_EXPONENT> (["f","F","d","D"])?
+      | "0" ["x", "X"] (["0"-"9","a"-"f","A"-"F"])* "." (["0"-"9","a"-"f","A"-"F"])+ <HEXADECIMAL_EXPONENT> (["f","F","d","D"])?>
+|
+       < #HEXADECIMAL_EXPONENT: ["p","P"] (["+","-"])? (["0"-"9"])+ >
+|
+       < #SPACE: (" " | "\t")+>
+|
+       < #TO_END_OF_LINE: (~["\n"])+>
+|
+       /* Macro token */
+       <INCLUDE: "#" (<SPACE>)? "include" <SPACE> (<STRING_LITERAL> | "<" (<LETTER> | <DOT>)+ ">")>
+|
+       <DEFINE: "#" (<SPACE>)? <TO_END_OF_LINE>>
+}
+
+String Type() :
+{
+       String type;
+       String str;
+       QualifiedName name;
+}
+{
+       { type = ""; }
+       (<CONST>
+       { type = "const"; }
+       )?
+       (
+               ((str = <STRUCT>.image | str = <CLASS>.image | str = <UNSIGNED>.image) {
+               type = type.equals("") ? type + str : type + " " + str;
+               })? 
+       (
+       name = ParseQualifiedName() {
+               if (!type.equals(""))
+                       type = type + " " + name.fullName;
+               else
+                       type = name.fullName;
+       })
+       )
+       ((str = <CONST>.image {
+               if (!type.equals(""))
+                       type = type + " " + str;
+               else
+                       type = str;
+       }) |
+       (str = <STAR>.image {
+               if (!type.equals(""))
+                       type = type + " " + str;
+               else
+                       type = str;
+       }) |
+       (str = <AND>.image {
+               if (!type.equals(""))
+                       type = type + " " + str;
+               else
+                       type = str;
+       })
+       )*
+       {
+               return type;
+       }
+}
+
+void Test() :
+{
+       String str;     
+       FunctionHeader func;
+}
+{
+       /*
+       str = Type()
+       {
+               System.out.println(str);
+       }
+       */
+       func = FuncDecl() 
+       {
+               System.out.println(func);
+       }
+       
+}
+
+String ParameterizedName() :
+{
+       String res = "";
+       String str;
+}
+{
+       (str = <IDENTIFIER>.image {res = str;})
+       (<LESS_THAN> str = Type() { res = res + "<" + str; }
+       (<COMMA> str = Type() { res = res + ", " + str; })* <GREATER_THAN>
+       { res = res + ">"; }
+       )?
+       {
+               return res;
+       }
+}
+
+FunctionHeader FuncDecl() :
+{
+       String ret;
+       QualifiedName funcName;
+       ArrayList<VariableDeclaration> args;
+}
+{
+       (<STATIC> | <INLINE>)*
+       ret = Type() 
+       funcName = ParseQualifiedName() 
+       args = FormalParamList() 
+       {
+               FunctionHeader res = new FunctionHeader(ret, funcName, args);
+               //System.out.println(res);
+               return res;
+       }
+}
+
+QualifiedName ParseQualifiedName() :
+{
+       String qualifiedName, str;
+}
+{
+       { qualifiedName = ""; }
+       (str = ParameterizedName() { qualifiedName = qualifiedName + str; } )
+       ( <DOUBLECOLON> (str = ParameterizedName() { qualifiedName = qualifiedName +
+       "::" + str; }  ))*
+       {
+               QualifiedName res = new QualifiedName(qualifiedName);
+               //System.out.println(res);
+               return res;
+       }
+}
+
+ArrayList<VariableDeclaration> TemplateParamList() :
+{
+       ArrayList<VariableDeclaration> params;
+       String type;
+       String name;
+}
+{
+       {
+               params = new ArrayList<VariableDeclaration>();
+       }
+       <TEMPLATE>
+       <LESS_THAN>
+       (type = <IDENTIFIER>.image 
+       name = <IDENTIFIER>.image
+       {
+               params.add(new VariableDeclaration(type, name));
+       }
+       )
+
+       (<COMMA> type = <IDENTIFIER>.image 
+       name = <IDENTIFIER>.image
+       {
+               params.add(new VariableDeclaration(type, name));
+       }
+       )*
+       <GREATER_THAN>
+       {
+               //System.out.println(params);
+               return params;
+       }
+}
+
+ArrayList<VariableDeclaration > FormalParamList() :
+{
+       ArrayList<VariableDeclaration > typeParams;
+       VariableDeclaration varDecl;
+}
+{
+       {
+               typeParams = new ArrayList<VariableDeclaration >();
+       }
+       <OPEN_PAREN>
+       ((varDecl = TypeParam() {typeParams.add(varDecl);})
+       ((<COMMA> varDecl = TypeParam() {typeParams.add(varDecl);}))*)?
+       <CLOSE_PAREN>
+       {
+               return typeParams;
+       }
+}
+
+VariableDeclaration Declaration() :
+{
+       String type, param;
+}
+{
+       (type = Type()) (param = <IDENTIFIER>.image)  <SEMI_COLON>
+       {
+               return new VariableDeclaration(type, param);
+       }
+}
+
+VariableDeclaration TypeParam() :
+{
+       String type, param;
+}
+{
+       (type = Type()) (param = <IDENTIFIER>.image)
+       {
+               return new VariableDeclaration(type, param);
+       }
+}
diff --git a/cdsspec-compiler/lib/javacc.jar b/cdsspec-compiler/lib/javacc.jar
new file mode 100644 (file)
index 0000000..abad3c4
Binary files /dev/null and b/cdsspec-compiler/lib/javacc.jar differ
diff --git a/cdsspec-compiler/notes/definition.cc b/cdsspec-compiler/notes/definition.cc
new file mode 100644 (file)
index 0000000..99d5a93
--- /dev/null
@@ -0,0 +1,364 @@
+#include <iostream>
+#include <vector>
+#include <list>
+#include <string>
+#include <iterator>
+#include <algorithm>
+#include <set>
+
+#include <functional>
+
+#include <stdarg.h>
+
+using namespace std;
+
+struct MethodCall;
+
+typedef MethodCall *Method;
+typedef set<Method> *MethodSet;
+
+struct MethodCall {
+       string interfaceName; // The interface label name
+       void *value; // The pointer that points to the struct that have the return
+                                // value and the arguments
+       void *state; // The pointer that points to the struct that represents
+                                         // the state
+       MethodSet prev; // Method calls that are hb right before me
+       MethodSet next; // Method calls that are hb right after me
+       MethodSet concurrent; // Method calls that are concurrent with me
+
+       MethodCall(string name) : MethodCall() { interfaceName = name; }
+       
+       MethodCall() : interfaceName(""), prev(new set<Method>),
+               next(new set<Method>), concurrent(new set<Method>) { }
+
+       void addPrev(Method m) { prev->insert(m); }
+
+       void addNext(Method m) { next->insert(m); }
+       
+       void addConcurrent(Method m) { concurrent->insert(m); }
+
+};
+
+
+typedef vector<int> IntVector;
+typedef list<int> IntList;
+typedef set<int> IntSet;
+
+typedef vector<double> DoubleVector;
+typedef list<double> DoubleList;
+typedef set<double> DoubleSet;
+
+/********** More general specification-related types and operations **********/
+
+#define NewMethodSet new set<Method>
+
+#define CAT(a, b) CAT_HELPER(a, b) /* Concatenate two symbols for macros! */
+#define CAT_HELPER(a, b) a ## b
+#define X(name) CAT(__##name, __LINE__) /* unique variable */
+
+/**
+       This is a generic ForEach primitive for all the containers that support
+       using iterator to iterate.
+*/
+#define ForEach(item, container) \
+       auto X(_container) = (container); \
+       auto X(iter) = X(_container)->begin(); \
+       for (auto item = *X(iter); X(iter) != X(_container)->end(); item = ((++X(iter)) != \
+               X(_container)->end()) ? *X(iter) : 0)
+
+/**
+       This is a common macro that is used as a constant for the name of specific
+       variables. We basically have two usage scenario:
+       1. In Subset operation, we allow users to specify a condition to extract a
+       subset. In that condition expression, we provide NAME, RET(type), ARG(type,
+       field) and STATE(field) to access each item's (method call) information.
+       2. In general specification (in pre- & post- conditions and side effects),
+       we would automatically generate an assignment that assign the current
+       MethodCall* pointer to a variable namedd _M. With this, when we access the
+       state of the current method, we use STATE(field) (this is a reference
+       for read/write).
+*/
+#define ITEM _M
+#define _M ME
+
+#define NAME Name(_M)
+
+#define STATE(field) State(_M, field)
+
+#define VALUE(type, field) Value(_M, type, field)
+#define RET(type) VALUE(type, RET)
+#define ARG(type, arg) VALUE(type, arg)
+
+/*
+#define Subset(s, subset, condition) \
+       MethodSet original = s; \
+       MethodSet subset = NewMethodSet; \
+       ForEach (_M, original) { \
+               if ((condition)) \
+                       subset->insert(_M); \
+       } \
+*/
+
+
+/**
+       This operation is specifically for Method set. For example, when we want to
+       construct an integer set from the state field "x" (which is an
+       integer) of the previous set of method calls (PREV), and the new set goes to
+       "readSet", we would call "MakeSet(int, PREV, readSet, STATE(x));". Then users
+       can use the "readSet" as an integer set (set<int>)
+*/
+#define MakeSet(type, oldset, newset, field) \
+       auto newset = new set<type>; \
+       ForEach (_M, oldset) \
+               newset->insert(field); \
+
+/**
+       We provide a more general subset operation that takes a plain boolean
+       expression on each item (access by the name "ITEM") of the set, and put it
+       into a new set if the boolean expression (Guard) on that item holds.  This
+       is used as the second arguments of the Subset operation. An example to
+       extract a subset of positive elements on an IntSet "s" would be "Subset(s,
+       GeneralGuard(int, ITEM > 0))"
+*/
+#define GeneralGuard(type, expression)  std::function<bool(type)> ( \
+       [&](type ITEM) -> bool { return (expression);}) \
+
+/**
+       This is a more specific guard designed for the Method (MethodCall*). It
+       basically wrap around the GeneralGuard with the type Method. An example to
+       extract the subset of method calls in the PREV set whose state "x" is equal
+       to "val" would be "Subset(PREV, Guard(STATE(x) == val))"
+*/
+#define Guard(expression) GeneralGuard(Method, expression)
+
+/**
+       A general subset operation that takes a condition and returns all the item
+       for which the boolean guard holds.
+*/
+inline MethodSet Subset(MethodSet original, std::function<bool(Method)> condition) {
+       MethodSet res = new SnapSet<Method>;
+       ForEach (_M, original) {
+               if (condition(_M))
+                       res->insert(_M);
+       }
+       return res;
+}
+
+/**
+       A general set operation that takes a condition and returns if there exists
+       any item for which the boolean guard holds.
+*/
+template <class T>
+inline bool HasItem(set<T> *original, std::function<bool(T)> condition) {
+       ForEach (_M, original) {
+               if (condition(_M))
+                       return true;
+       }
+       return false;
+}
+
+
+
+/**
+       A general sublist operation that takes a condition and returns all the item
+       for which the boolean guard holds in the same order as in the old list.
+*/
+template <class T>
+inline list<T>* Sublist(list<T> *original, std::function<bool(T)> condition) {
+       list<T> *res = new list<T>;
+       ForEach (_M, original) {
+               if (condition(_M))
+                       res->push_back(_M);
+       }
+       return res;
+}
+
+/**
+       A general subvector operation that takes a condition and returns all the item
+       for which the boolean guard holds in the same order as in the old vector.
+*/
+template <class T>
+inline vector<T>* Subvector(vector<T> *original, std::function<bool(T)> condition) {
+       vector<T> *res = new vector<T>;
+       ForEach (_M, original) {
+               if (condition(_M))
+                       res->push_back(_M);
+       }
+       return res;
+}
+
+/** General for set, list & vector */
+#define Size(container) ((container)->size())
+
+#define _BelongHelper(type) \
+       template<class T> \
+       inline bool Belong(type<T> *container, T item) { \
+               return std::find(container->begin(), \
+                       container->end(), item) != container->end(); \
+       }
+
+_BelongHelper(set)
+_BelongHelper(vector)
+_BelongHelper(list)
+
+/** General set operations */
+template<class T>
+inline set<T>* Intersect(set<T> *set1, set<T> *set2) {
+       set<T> *res = new set<T>;
+       ForEach (item, set1) {
+               if (Belong(set2, item))
+                       res->insert(item);
+       }
+       return res;
+}
+
+template<class T>
+inline set<T>* Union(set<T> *s1, set<T> *s2) {
+       set<T> *res = new set<T>(*s1);
+       ForEach (item, s2)
+               res->insert(item);
+       return res;
+}
+
+template<class T>
+inline set<T>* Subtract(set<T> *set1, set<T> *set2) {
+       set<T> *res = new set<T>;
+       ForEach (item, set1) {
+               if (!Belong(set2, item))
+                       res->insert(item);
+       }
+       return res;
+}
+
+template<class T>
+inline void Insert(set<T> *s, T item) { s->insert(item); }
+
+template<class T>
+inline void Insert(set<T> *s, set<T> *others) {
+       ForEach (item, others)
+               s->insert(item);
+}
+
+/*
+inline MethodSet MakeSet(int count, ...) {
+       va_list ap;
+       MethodSet res;
+
+       va_start (ap, count);
+       res = NewMethodSet;
+       for (int i = 0; i < count; i++) {
+               Method item = va_arg (ap, Method);
+               res->insert(item);
+       }
+       va_end (ap);
+       return res;
+}
+*/
+
+/********** Method call related operations **********/
+#define Name(method) method->interfaceName
+
+#define State(method, field) ((StateStruct*) method->state)->field
+
+#define Value(method, type, field) ((type*) method->value)->field
+#define Ret(method, type) Value(method, type, RET)
+#define Arg(method, type, arg) Value(method, type, arg)
+
+#define Prev(method) method->prev
+#define PREV _M->prev
+
+#define Next(method) method->next
+#define NEXT _M->next
+
+#define Concurrent(method) method->concurrent
+#define CONCURRENT  _M->concurrent
+
+
+/***************************************************************************/
+/***************************************************************************/
+
+// This auto-generated struct can have different fields according to the read
+// state declaration. Here it's just a test example
+typedef struct StateStruct {
+       int x;
+} StateStruct;
+
+// These auto-generated struct can have different fields according to the return
+// value and arguments of the corresponding interface. The struct will have the
+// same name as the interface name. Here it's just a test example
+typedef struct Store {
+       int *loc;
+       int val;
+} Store;
+
+typedef struct Load {
+       int RET;
+       int *loc;
+} Load;
+
+int main() {
+       set<int> *is1 = new set<int>;
+       set<int> *is2 = new set<int>;
+
+       list<int> *il1 = new list<int>;
+       list<int> *il2 = new list<int>;
+
+       il1->push_back(2);
+       il1->push_back(3);
+       
+       is1->insert(1);
+       is1->insert(3);
+       
+       is2->insert(4);
+       is2->insert(5);
+
+
+       MethodSet ms = NewMethodSet;
+       Method m = new MethodCall;
+       m->interfaceName = "Store";
+       StateStruct *ss = new StateStruct;
+       ss->x = 1;
+       m->state = ss;
+       Store *st = new Store;
+       st->val = 2;
+       m->value = st;
+       ms->insert(m);
+
+       m = new MethodCall;
+       m->interfaceName= "Store";
+       ss = new StateStruct;
+       ss->x = 2;
+       m->state = ss;
+       st = new Store;
+       st->val = 0;
+       m->value = st;
+       ms->insert(m);
+
+       m = new MethodCall;
+       m->interfaceName= "Load";
+       ss = new StateStruct;
+       ss->x = 0;
+       m->state = ss;
+       Load *ld = new Load;
+       ld->RET = 2;
+       m->value = ld;
+       ms->insert(m);
+
+       //MakeSet(int, ms, newis, STATE(x));
+       //cout << "Size=" << Size(newis) << " | val= " << Belong(newis, 2) << endl;
+       
+       int x = 2;
+       int y = 2;
+       cout << "HasItem=" << HasItem(ms, Guard(STATE(x) == x && y == 0)) << endl;
+       
+       //ForEach (i, newis) {
+               //cout << "elem: " << i << endl;
+       //}
+
+
+       //Subset(ms, sub, NAME == "Store" && VALUE(Store, val) != 0);
+       //cout << "Size=" << Size(Subset(ms, Guard(NAME == "Store" && ARG(Store, val)
+               //>= 0 && STATE(x) >= 0 ))) << endl;
+       return 0;
+}
diff --git a/cdsspec-compiler/notes/generated_code_examples.txt b/cdsspec-compiler/notes/generated_code_examples.txt
new file mode 100644 (file)
index 0000000..2a7241c
--- /dev/null
@@ -0,0 +1,256 @@
+******    Example1:    ******
+Global Variable Declaration
+
+/* Include all the header files that contains the interface declaration */
+#inlcude <atomic>
+#include <memory>
+#include <assert.h>
+
+/* Other necessary header files */
+#include <stdint.h>
+#include <specannotation.h>
+#include <spec_lib.h>
+
+/* All other user-defined functions */
+ALL_USER_DEFINED_FUNCTIONS  // Make them static 
+
+/* Definition of interface info struct (per interface) */
+typedef struct Put_info {
+       shared_ptr<TypeV> __RET__;
+       TypeK & key;
+       TypeV & value;
+} Put_info;
+
+typedef struct Get_info {
+       shared_ptr<TypeV> __RET__;
+       TypeK & key;
+} Get_info;
+/* End of info struct definition */
+
+/* ID functions of interface */
+static id_t Put_id() {
+       id_t id = PUT_ID;  // Default ID == 0;
+       return id;
+}
+
+static id_t Get_id() {
+       id_t id = GET_ID;
+       return id;
+}
+/* End of ID functions */
+
+
+
+/* Check_action function of interfaces */
+bool Put_check_action(void *info, id_t __ID__) {
+       bool check_passed;
+       Put_info *theInfo = (Put_info) info;
+       shared_ptr<TypeV> __RET__ = theInfo->__RET__;
+       TypeK & key = theInfo->key;
+       TypeV & value = theInfo->value;
+
+       // __COND_SAT__
+       bool __COND_SAT__ = PUT_CONDITION;
+
+       // Check
+       check_passed = PUT_CHECK_EXPRESSION;
+       if (!check_passed)
+               return false;
+
+       // Action
+       PUT_ACTION
+
+       // Post_check
+       check_passed = PUT_POST_CHECK_EXPRESSION;
+       if (!check_passed)
+               return false;
+
+       // Post_action
+       PUT_POST_ACTION
+}
+
+
+bool Get_check_action(void *info, id_t __ID__) {
+       //...
+}
+/* End of check_action function definitions */ 
+
+/* Initialization of interface<->function_ptr table */
+#define INTERFACE_SIZE 2
+void** func_ptr_table;
+
+/* Beginning of other user-defined variables */
+bool lock_acquired;
+int reader_lock_cnt;
+/* End of other user-defined variables */
+
+
+/* Define function for sequential code initialization */
+void __sequential_init() {
+       /* Init func_ptr_table */
+       func_ptr_table = (void**) malloc(sizeof(void*) * 2);
+       func_ptr_table[0] = (void*) &Put_id;
+       func_ptr_table[1] = (void*) &Put_check_action;
+       func_ptr_table[2] = (void*) &Get_id;
+       func_ptr_table[3] = (void*) &Get_check_action;
+
+       /* Init user-defined variables */
+       lock_acquired = false;
+       reader_lock_cnt = 0;
+
+       /* Pass function table info */
+       anno_func_table_init func_table;
+       func_table.size = INTERFACE_SIZE;
+       func_table.table = func_ptr_table;
+       spec_annotation func_init;
+       func_init.type = FUNC_TABLE_INIT;
+       func_init.annotation = &anno_func_table_init;
+       cdsannotate(SPEC_ANALYSIS, &func_init);
+
+       /* Pass the happens-before initialization here */
+       /* PutIfAbsent (putIfAbsent_Succ) -> Get (true) */
+       anno_hb_init hbConditionInit0;
+       hbConditionInit0.interface_num_before = 1;
+       hbConditionInit0.hb_condition_num_before = 1;
+       hbConditionInit0.interface_num_after = 2;
+       hbConditionInit0.hb_condition_num_after = 0;
+       spec_annotation hb_init0;
+       hb_init0.type = HB_INIT;
+       hb_init0.annotation = &hbConditionInit0;
+       cdsannotate(SPEC_ANALYSIS, &hb_init0);
+}
+/* End of Global construct generation in class */
+
+/* The following static field declaration is necessary for class */
+template <typename T>
+bool CLASS<T>::lock_acquired;
+
+template <typename T>
+int CLASS<T>::reader_lock_cnt;
+/* End of static field definition */
+
+
+******    Example2:    ******
+Interface Wrapper
+
+/* Include the header files first */
+#include <threads.h>
+#include <cdsannotate.h>
+#include <specannotation.h>
+#include <spec_lib.h>
+
+TypeReturn interfaceName(ARGType1 arg1, ARGType2 arg2)
+{
+       // Interface begins
+       anno_interface_begin interface_begin;
+       interface_begin.interface_num = 0; // Interface number
+       spec_annotation annotation_interface_begin;
+       annotation_interface_begin.type = INTERFACE_BEGIN;
+       annotation_interface_begin.annotation = &interface_begin;
+       cdsannotate(SPEC_ANALYSIS, &annoation_interface_begin);
+
+       TypeReturn __RET__ = __wrapper_interfaceName(arg1, arg2);
+
+       // HB conditions (if any)
+       if (HB_CONDITION1) {
+               anno_hb_condition hb_condition1;
+               hb_condition1.interface_num = 0; // Interface number
+               hb_condition1.hb_condition_num = 1; // HB condition number
+               spec_annotation annotation_hb_condition;
+               annotation_hb_condition.type = HB_CONDITION;
+               annotation_hb_condition.annotation = &hb_condition;
+               cdsannotate(SPEC_ANALYSIS, &annotation_hb_condition);
+       }
+       // And more (if any)
+
+       // Interface ends
+       INTERFACE_LABEL_info info = (INTERFACE_LABEL_info*) malloc(sizeof(INTERFACE_LABEL_info));
+       info->__RET__ = __RET__;
+       info->arg1 = arg1;
+       info->arg2 = arg2;
+       anno_interface_end interface_end;
+       interface_end.interface_num = 0; // Interface number
+       interface_end.info = info; // Info
+       spec_annotation annotation_interface_end;
+       annotation_interface_end.type = INTERFACE_END;
+       annotation_interface_end.annotation = &interface_end;
+       cdsannotate(SPEC_ANALYSIS, &annoation_interface_end);
+}
+
+
+******    Example3:    ******
+Potential Commit Point
+
+
+#include <stdint.h>
+#include <cdsannotate.h>
+
+/* Should add the __ATOMIC_RET__ if necessary */
+uint64_t __ATOMIC_RET = somevar.compare_exchange_explicit(...);
+
+if (POTENTIAL_CP_DEFINE_CONDITION) {
+       anno_potential_cp_define potential_cp_define;
+       potential_cp_define.label_num = 1; // Commit point label number
+       spec_annotation annotation_potential_cp_define;
+       annotation_potential_cp_define.type = POTENTIAL_CP_DEFINE;
+       annotation_potential_cp_define.annotation = &potential_cp_define;
+       cdsannotate(SPEC_ANALYSIS, &annotation_potential_cp_define);
+}
+
+******    Example4:    ******
+Commit Point Define
+
+#include <threads.h>
+#include <cdsannotate.h>
+#include <stdint.h>
+
+/* Should add the __ATOMIC_RET__ if necessary */
+uint64_t __ATOMIC_RET = somevar.compare_exchange_explicit(...);
+
+/* For all the interface check at this commit point (if there is multiple
+ * checks here) */
+// Commit point 3 <=> potentialCP 4
+if (COMMIT_POINT3_CONDITION) {
+       anno_cp_define cp_define;
+       cp_define.label_num = 3;
+       cp_define.potential_cp_label_num = 1;
+       spec_annotation annotation_cp_define;
+       annotation_cp_define.type = CP_DEFINE;
+       annotation_cp_define.annotation = &cp_define;
+       cdsannotate(SPEC_ANALYSIS, &annotation_cp_define);
+}
+// More if there are any
+
+}
+
+
+*****    Example5:    ******
+Commit Point Define Check
+
+
+#include <threads.h>
+#include <cdsannotate.h>
+#include <stdint.h>
+
+/* Should add the __ATOMIC_RET__ if necessary */
+uint64_t __ATOMIC_RET = somevar.compare_exchange_explicit(...);
+
+
+/* For all the interface check at this commit point (if there is multiple
+ * checks here) */
+if (COMMIT_POINT3_CONDITION) {
+       anno_cp_define cp_define;
+       uint64_t call_sequence_num = get(&__sequential.interface_call_sequence, tid);
+       bool check_passed = false;
+       cp_define.check_passed = check_passed;
+       cp_define.interface_num = interface_num;
+       cp_define.label_num = 3;
+       cp_define.call_sequence_num = call_sequence_num;
+       spec_annotation annotation_cp_define;
+       annotation_cp_define.type = CP_DEFINE;
+       annotation_cp_define.annotation = &cp_define;
+       cdsannotate(SPEC_ANALYSIS, &annotation_cp_define);
+}
+// More if there are any
+
+}
diff --git a/cdsspec-compiler/notes/impl.txt b/cdsspec-compiler/notes/impl.txt
new file mode 100644 (file)
index 0000000..ea90727
--- /dev/null
@@ -0,0 +1,50 @@
+1. Template support
+  The global specification should be expanded right after the specification
+  definition (the golbal construct). The global variables and functions will be
+  the private members of the data structure. In this case, the template of the
+  data structure can be automatically passed to the variables and functions.
+  Besides, as the public member of the function, all the interface check can
+  access the specification variables and functions just as normal.
+
+2. On-the-fly spec check
+  For a check and action, they will be expanded right at the place where they
+  are declared and will get executed when the inserted annotation gets executed.
+  And the annotation is just a way to pass if the checks are satisfied. However,
+  it is wrong because the annotation is also a type of atomic operation. For
+  example, for a potential commit point and a later commit point check, they
+  might be interleaved by another commit point. Therefore, we need to check in
+  the specanalysis to see if the specific interleaving of annotation is "legal".
+
+3. Happens-before initialization
+  This concerns the place where we pass to the specanalysis the happens-before
+  rules????
+
+4. To make implementation easier and the spec cleaner, we make a difference C
+  and C++ programs. Since C does not support template and class, we require
+  users to provide an entry point where we can initialize the sequential
+  variables. By default, it's a C++ program, and everything is wrapped in an
+  inner class because it can have easy initialization and template support.
+
+5. We add @Interface_define construct in the specification. Basically,
+  @Interface construct can be used in both interface declaration and interface
+  definition, if they are not separated. However, if they are, then @Interface
+  is used for the interface declaration and @Interface_define is for the
+  interface definition. This is redundant information, but it makes the
+  implementation much easier because we don't need to parse the C/C++ program.
+
+6. Checking at runtime or check with complete trace analysis can have the
+  follwing concerns. Checking at runtime, HB might not be established yet (we
+  can leave it at trace analysis though). More importantly, we have potential
+  commit point and commit point check, which might be preempted by another
+  commit point. We can't decide whether to execute the commit point actions or
+  not since we can't decide if it's really a commit point at that time. Checking
+  with complete execution can be more clear and better designed, but it has a
+  tough challenge. Some data structure may check their predicate with pointers,
+  however, we can't guarantee those pointers are still valid (the object they
+  are pointing to may be changed or even deleted). To tackle this, we provide an
+  alternative which requires users to define the snapshot function for the
+  pointers if they are about to check with pointers that might change. In the
+  current data structure, it's not a problem because they only return reference
+  or pointers, which we can do simple equality check. We decided to take the
+  trace analysis approach because it's still more flexible and easier to
+  implement.
diff --git a/cdsspec-compiler/notes/interesting_examples.txt b/cdsspec-compiler/notes/interesting_examples.txt
new file mode 100644 (file)
index 0000000..8b13789
--- /dev/null
@@ -0,0 +1 @@
+
diff --git a/cdsspec-compiler/notes/nondeterm-spec.txt b/cdsspec-compiler/notes/nondeterm-spec.txt
new file mode 100644 (file)
index 0000000..9898a22
--- /dev/null
@@ -0,0 +1,458 @@
+Modification to the current specifications.
+
+I. Order
+-- Sequential order (SO): Some total order that is consistent with the union of
+happens-before and SC relation.
+
+II. State
+Previously, we keep a sequential state throughout the process of executing the
+sequential history. In our model, we keep a state local to each method call.
+Conceptually, this state is the accumulative side effects of the subset of
+method calls that happen before the current method call. 
+
+To evaluate the state of each method call, an obvious approach is to
+execute the subset of methods that happen before the current method in the
+sequential order from the initial state. A optimization we can make is that we
+start to evaluate the state from the most recent deviding node which every other
+node in that subset is either hb before or after.
+
+III. Specifications
+Our specification language supports using the following primitives to access the
+state of method calls so that users can use those to write specifications with
+different level of tightness.
+
+To support tighter specifications, we introduce the concept of concurrent set of
+method calls, meaning that for a specific method call, it can basically see the
+effect of two different categories of method calls --- one that happens before
+it, and one that concurrently execute with it. It is worth noting that when two
+two method calls execute concurrently, in general there can be the following two
+effects: 1) those concurrent methods can happen in either order, and the final
+result remains the same. A concurrent FIFO is an example, in which concurrent
+enqueue and dequeue methods can happen in a random order; and 2) the order of
+those concurrent methods will affect the final result. The C/C++11 atomics is an
+example, in which when concurrent stores to the same location execute in
+different order, a later store will have different result.
+
+1. CONCURRENT: This primitive extracts all the methods that executes
+"concurrently" with the current method --- neither hb/SC before nor after the
+current method --- and returns as a set. It is worth noting that in order to
+preserve composability, when evaluating the state, the concurrent method calls'
+information cannot be used. That is to say, the concurrent set of mehtods are
+only used for assertions.
+
+2. PREV: This primitive extracts all the methods that execute right before the
+current method in the execution graph --- most recent method calls that are
+hb/SC before the current method call --- and returns as a set. For each method
+in this set, the current method's specification can access their state.
+
+3. NEXT: This primitive extracts all the methods that execute right after the
+current method in the execution graph, and returns as a set. For each method in
+this set, the current method's specification CANNOT access their state (for
+preserving composability).
+
+// FIXME: This might break composability!!??!!
+4. FINAL: This is the function that allows users to specify some final check
+on the state. This will enable to users to use the graph model (the relaxed
+atomics can be specified) although the complxity of using that can get quite
+complex.
+
+Our specifications allow two ways of evaluating the state of method calls. One
+way is to define "@Transition" on method calls, and then our checker executes
+the method calls that are hb/SC before me in the sequential order starting from
+the initial state. The other way is to define "@EvaluateState" after
+"@Transition", which can only access the states of method calls that are hb/SC
+before it.  Usually users calculate the state by using the PREV primitive to
+access the state of previous method calls.
+
+IV. Specification Details
+
+/// Global specification
+@State: // Declare the state structure
+@Initial: // How do we initialize the state
+@Commutativity: Method1 <-> Method2 (Guard) // Guard can only access the return
+               // value and the arguments of the two method calls
+
+/// Interface specification
+@Interface: InterfaceName // Required; a label to represent the interface
+@Transition: // Optional; the transitional side effect from the initial state to
+                        // the current method call by executing such effect on method calls
+                        // that are hb/SC before me in sequential order. When this field is
+                        // omitted, the current state seen before checking is the same as
+                        // the initial state.
+@EvaluateState: // Optional; to calculate the state before this
+                               // method call is checked in a customized fashion. This is
+                               // evaluated after "@Transition". If omitted, the state we would
+                               // see is the effect after the "@Transition".
+@PreCondition: // Optional; checking code
+@SideEffect: // Optional; to calculate the side effect this method call
+                                 // have on the state after the "@PreCondition".
+@PostCondition: // Optional; checking code
+
+
+/// Convienient operations
+We define a struct called MethodCall to represent the data we would collect and
+communicate between the real execution and the checking process.
+
+
+STATE(field)   // A primitive to access the current state in the interface
+                               // specification by the name of the field. We can use this as a
+                               // lvalue & rvalue ==> "STATE(x) = 1" and "int i = STATE(x)" are
+                               // both okay
+
+                               // This can also be used to refer to the state of a method item
+                               // in the Subset operation (see Subset)
+
+NAME                   // Used to refer to the name of a method item in the Subset
+                               // operation (see Subset)
+
+RET(type)              // Used to refer to the return value of a method item in the
+                               // Subset operation (see Subset)
+
+ARG(type, arg) // Used to refer to the argument of a method item in the
+                               // Subset operation (see Subset)
+
+
+PREV           // Represent the set of previous method calls of the current method
+                       // call
+
+CONCURRENT     // Represent the set of concurrent method calls of the current
+                               // method call
+
+NEXT           // Represent the set of next method calls of the current method
+                       // call
+
+Name(method)           // The interface label name of the specific method
+
+State(method, field)           // A primitive to access a specific state field of a
+                                                       // specific method. Also used as lvalue and rvalue
+
+Ret(method, type)              // The return value of the specific method; type should
+                                               // be the name of the interface label
+
+Arg(method, type, arg) // The arguement by name of the specific method; type should
+                                               // be the name of the interface label, and arg should be
+                                               // the name of the argument
+
+Prev(method)           // Represent the set of previous method calls of the
+                                       // specific method call
+
+Next(method)           // Represent the set of next method calls of the specific
+                                       // method call
+
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ForEach(item, container) { ... }       // Useful iteration primitive
+
+NewMethodSet           // Create a new method set (set<MethodCall*>*)
+
+MakeSet(type, oldset, newset, field);          // Construct a new set from an
+                                               // old set. We extract a specific field of that set item
+                                               // and form a new set. Specifically we expect users to
+                                               // use this on MethodSet. For example, if we want to
+                                               // construct an integer set from the state "x" of
+                                               // the previous methods, we use "MakeSet(int, PREV,
+                                               // newset, STATE(x))", and the newset contains the new
+                                               // set
+
+Subset(set, condition) // A generic subset operation that takes a condition and
+                                               // returns all the item for which the boolean guard
+                                               // holds. The condition can be specified with GUARD or
+                                               // GeneralGuard shown as follow.
+
+HasItem(set, condition)        // A generic set operation that takes a condition and
+                                               // returns if there exists any item in "set" for which
+                                               // the condition holds. Its syntax is similar to that of
+                                               // Subset() operation
+
+Size(container)                // Return the size of a container type
+
+Belong(container, item)                // Return if item is in the container
+
+Union(set1, set2)      // Union of two sets
+
+Intesection(set1, set2)                // Intersection of two sets
+
+Subtract(set1, set2)   // Returns the new set that represents the result of
+                                               // set1-set2
+Insert(set, item)      // Insert item to set
+
+Insert(set, others)            // Insert the whole set "others" to "set"
+
+ITEM   // Used to refer to the set item in the GeneralGuard shown below
+
+GeneralGuard(type, expression) // Used as a condition for any set<T> type. We
+                                                               // use "ITEM" to refer to a set item. For
+                                                               // example, a subset of positive elements on an
+                                                               // IntSet "s" would be
+                                                               // "Subset(s, GeneralGuard(int, ITEM > 0))"
+
+Guard(expression)      // Used specifically for MethodSet(set<MethodCall*>). An
+                                       // example to extract the subset of method calls in the PREV
+                                       // set that is a "Store" method and whose state "x" is equal
+                                       // to "val" and the return value is 5 would be
+                                       // "Subset(PREV, Guard(STATE(x) == val && NAME == "Store" &&
+                                       // RET(Store) == 5))"
+
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+
+To make things easier, we have the following helper macros.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+/**
+       This is a common macro that is used as a constant for the name of specific
+       variables. We basically have two usage scenario:
+       1. In Subset operation, we allow users to specify a condition to extract a
+       subset. In that condition expression, we provide NAME, RET(type), ARG(type,
+       field) and STATE(field) to access each item's (method call) information.
+       2. In general specification (in pre- & post- conditions and side effects),
+       we would automatically generate an assignment that assign the current
+       MethodCall* pointer to a variable namedd _M. With this, when we access the
+       state of the current method, we use STATE(field) (this is a reference
+       for read/write).
+*/
+#define ITEM _M
+#define _M ME
+
+#define CAT(a, b) CAT_HELPER(a, b) /* Concatenate two symbols for macros! */
+#define CAT_HELPER(a, b) a ## b
+#define X(name) CAT(__##name, __LINE__) /* unique variable */
+
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+*****************************************************************************
+typedef struct MethodCall {
+       string name; // The interface label name
+       void *value; // The pointer that points to the struct that have the return
+                                // value and the arguments
+       void *state; // The pointer that points to the struct that represents
+                                         // the state
+       set<MethodCall*> *prev; // Method calls that are hb right before me
+       set<MethodCall*> *concurrent; // Method calls that are concurrent with me
+       set<MethodCall*> *next; // Method calls that are hb right after me
+} MethodCall;
+
+typedef MethodCall *Method;
+typedef set<Method> *MethodSet;
+
+typedef vector<int> IntVector;
+typedef list<int> IntList;
+typedef set<int> IntSet;
+*****************************************************************************
+
+We will automatically generate two types of struct. One is the state struct, and
+we will call it StateStruct. The other one is a per interface struct, and it
+wraps the return value (RET) and the arguments as its field. We will name those
+struct with the interface label name.
+
+-----------------------------------------------------------------------------
+For example, if we declare an ordered integer list in the specification state ,
+we will generate a struct as follow.
+
+@State: IntList *queue;
+@Initial: queue = new IntList;
+@...
+
+===>
+typedef struct StateStruct {
+       IntList *queue;
+} StateStruct;
+
+-----------------------------------------------------------------------------
+If we have two interface whose specifications are as follow, we would generate
+two struct accordingly.
+
+@Interface: Store
+@...
+void store(atomic_int *loc, int val) ...
+
+@Interface: Load
+@...
+int load(atomic_int *loc) ...
+
+===>
+typedef struct Store {
+       atomic_int *loc;
+       int val;
+} Store;
+
+typedef struct Load {
+       int RET;
+       atomic_int *loc;
+} Load;
+
+-----------------------------------------------------------------------------
+We will put all these generated struct in a automatically-generated header file
+called "generated.h". This file also includes header files that have commonly
+used data types that interface (return value and arguments) accesses. In order
+to make things work, users should include "generated.h" file in the end for
+using our specification checker.
+
+*****************************************************************************
+
+
+/// Ordering point specification
+@OPDefine: condition   // If the specified condition satisfied, the atomic
+                                               // operation right before is an ordering point
+
+@PotentialOP(Label): condition // If the specified condition satisfied, the
+                                                               // atomic operation right before is a potential
+                                                               // ordering point, and we label it with a tag
+
+@OPCheck(Label): condition     // If the specified condition satisfied, the
+                                                       // potential ordering point defined earlier with the
+                                                       // same tag becomes an ordering point
+
+@OPClear: condition            // If the specified condition satisfied, all the
+                                               // ordering points and potential ordering points will be
+                                               // cleared
+
+@OPClearDefine: condition      // If the specified condition satisfied, all the
+                                                       // ordering points and potential ordering points will
+                                                       // be cleared, and the atomic operation right before
+                                                       // becomes an ordering point. This is a syntax sugar
+                                                       // as the combination of an "OPClear" and "OPDefine"
+                                                       // statement
+
+
+V. Examples
+
+!!!!!!! The register example should be extended to commute if we think of their
+transitional effects as set operations --- a set operation that will only mask
+out side the effects of its own previous behavior (things that are hb/SC before
+it)  ---- VERY IMPORTANT note here!!
+
+
+1. The register examples: Basically, we can think of registers as the cache on a
+memory system. The effect of a load or store basically tells us what the current
+value in the cache line is, and a load can read from values that can be
+potentially in the cache --- either one of the concurrent store update the cache
+or it inherites one of the the previous state in the execution graph.
+
+----------   Interfae   ----------
+void init(atomic_int &loc, int initial);
+int load(atomic_int &loc);
+void store(atomic_int &loc, int val);
+----------   Interfae   ----------
+
+a. The SC atomics --- the classic linearizability approach
+
+b. The RA (release/acquire) C/C++ atomics
+// For RA atomics, a load must read its value from a store that happens before
+// it.
+----------   Specification   ----------
+@State: int x;
+@Initial: x = 0;
+@Commutativity: Store <-> Store(true)
+@Commutativity: Load <-> Load(true)
+@Commutativity: Store <-> Load(true)
+
+/** No @Transition */
+@Interface: Store
+@SideEffect: STATE(x) = val;
+void store(int *loc, int val);
+
+@Interface: Load
+@PreCondition:
+       return HasItem(PREV, STATE(x) == RET);
+@SideEffect: STATE(x) = RET;
+int load(int *loc);
+
+c. The C/C++ atomics (a slightly loose specification)
+// Actually, any concurrent data structures that rely modification-order to be
+// correct would not have a precicely tight specification under our model, and
+// C/C++ relaxed atomics is an example. See the following read-read coherence
+// example.
+
+// T1                          // T2
+x = 1;                         x = 2;
+
+// T3
+r1 = x; // r1 == 1
+r2 = x; // r2 == 2
+r3 = x; // r3 == 1
+
+Our model cannot prevent such a case from happening. However, we can still have
+a slightly loose specification which basically states that a load can read from
+any store that either immediately happens before it or concurrently executes.
+
+
+----------   Specification   ----------
+@State: int x;
+@Initial: x = 0;
+
+@Interface: Store
+@SideEffect: STATE(x) = val;
+void store(int *loc, int val);
+
+
+@Interface: Load
+@PreCondition:
+       // Auto generated code
+       // MethodCall *ME = ((SomeTypeConversion) info)->method;
+
+       return HasItem(Prev, STATE(x) == RET) || 
+               + HasItem(CONCURRENT, NAME == "Store" && ARG(Store, val) == RET)
+@SideEffect: STATE(x) = RET;
+int load(int *loc);
+
+d. The C/C++ normal memory accesses
+- Use the admissibility requirement, then the classic linearizability approach
+on the admissible executions
+
+2. The FIFO queue example.
+----------   Specification   ----------
+// A FIFO queue should have the following properties held:
+// 1. The enq() methods should conflict
+// 2. The deq() methods that succeed should conflict
+// 3. Corresponding enq() and deq() methods should conflict
+// 4. An enqueued item can be dequeued by at most once
+// 5. A dequeued item must have a corresponding enqueued item
+// 6. When a queue is NOT "empty" (users can tightly or loosely define
+// emptiness), and there comes a deq() method, the deq() method should succeed
+
+
+@DeclareVar: vector<int> *q;
+@InitVar: q = new voctor<int>;
+@Copy: New.q = new vector<int>(Old.q);
+// Fails to dequeue
+@Commutativity: Deq <-> Deq (!_M1.RET || !_M2.RET)
+@Commutativity: Enq <-> Deq (true)
+
+@Interface: Enq
+@Transition: q->push_back(val);
+void enq(queue_t *q, int val);
+
+@Interface: Deq
+@Transition: if (RET) q->pop_back();
+@PreCondition:
+       // Check whether the queue is really empty
+       // Either the state is an empty queue, or for all those remaining
+       // elements in the queue, there should be some concurrent dequeuers to
+       // dequeue them
+       if (!RET) {
+               // State is empty
+               if (STATE(q)->size() == 0) return true;
+               // Otherwise check there must be other concurrent dequeuers
+               ForEach (item, State(q)) {
+                       // Check there's some concurrent dequeuer for this item
+                       if (!HasItem(CONCURRENT, NAME == "Deq" && RET(Deq) &&
+                               *ARG(Deq, res) == item)) return false;
+               }
+               return true;
+       } else { // Check the global queue state
+               return q->back() == *res;
+       }
+bool deq(queue_t *q, int *res);
+
+
+*******************************************************************************
+A good example to simulate a queue data structure is as follows.
+Suppose we have a special structure
+typedef struct Q {
+       atomic_int x;
+       atomic_int y;
+} Q;
+
+, and we have two interface on Q, read() and write(), where the write and read
+method calls are synchronized by themselves, and they have to read and write the
+x and y fields in turn.
diff --git a/cdsspec-compiler/notes/register-example/Makefile b/cdsspec-compiler/notes/register-example/Makefile
new file mode 100644 (file)
index 0000000..618b173
--- /dev/null
@@ -0,0 +1,12 @@
+include ../benchmarks.mk
+
+TESTNAME = register
+all: $(TESTNAME)
+
+CFLAGS := $(CFLAGS) --std=c++11
+
+$(TESTNAME): $(TESTNAME).cc $(TESTNAME).h
+       $(CXX) -o $@ $< $(CFLAGS) $(LDFLAGS)
+
+clean:
+       rm -f $(TESTNAME) *.o 
diff --git a/cdsspec-compiler/notes/register-example/cdsspec-generated.h b/cdsspec-compiler/notes/register-example/cdsspec-generated.h
new file mode 100644 (file)
index 0000000..dab50eb
--- /dev/null
@@ -0,0 +1,152 @@
+#include <cdsannotate.h>
+#include <modeltypes.h>
+#include <atomic>
+#include <threads.h>
+#include <stdatomic.h>
+
+#include "mymemory.h"
+#include "specannotation.h"
+#include "cdsspec.h"
+#include "methodcall.h"
+
+using namespace std;
+
+typedef struct StateStruct {
+       int val;
+
+       SNAPSHOTALLOC
+} StateStruct;
+
+typedef struct LOAD {
+       int RET;
+       atomic_int *loc;
+} LOAD;
+
+typedef struct STORE {
+       atomic_int *loc;
+       int val;
+} STORE;
+
+inline void _initial(Method m) {
+       StateStruct *state = new StateStruct;
+       state->val = 0;
+       m->state = state;
+}
+
+inline void _copyState(Method dest, Method src) {
+       StateStruct *stateSrc = (StateStruct*) src;
+       StateStruct *stateDest = (StateStruct*) dest;
+       stateDest->val = stateSrc->val;
+}
+
+inline bool _checkCommutativity1(Method m1, Method m2) {
+       if (m1->interfaceName == "LOAD" && m2->interfaceName == "LOAD") {
+               if (true)
+                       return true;
+               else
+                       return false;
+       }
+       return false;
+}
+
+inline bool _checkCommutativity2(Method m1, Method m2) {
+       if (m1->interfaceName == "STORE" && m2->interfaceName == "LOAD") {
+               if (true)
+                       return true;
+               else
+                       return false;
+       }
+       return false;
+}
+
+inline bool _checkCommutativity3(Method m1, Method m2) {
+       if (m1->interfaceName == "STORE" && m2->interfaceName == "STORE") {
+               if (true)
+                       return true;
+               else
+                       return false;
+       }
+       return false;
+}
+
+inline void _LOAD_Transition(Method _M, Method _exec) {
+       return;
+}
+
+inline bool _LOAD_PreCondition(Method _M) {
+       int RET = ((LOAD*) _M->value)->RET;
+       atomic_int *loc = ((LOAD*) _M->value)->loc;
+       return HasItem(PREV, Guard(STATE(val) == RET && loc));
+}
+
+inline void _LOAD_SideEffect(Method _M) {
+       int RET = ((LOAD*) _M->value)->RET;
+       atomic_int *loc = ((LOAD*) _M->value)->loc;
+       STATE(val) = RET;
+}
+
+inline void _STORE_Transition(Method _M, Method _exec) {
+       return;
+}
+
+inline void _STORE_SideEffect(Method _M) {
+       atomic_int *loc = ((STORE*) _M->value)->loc;
+       int val = ((STORE*) _M->value)->val;
+       STATE(val) = val;
+}
+
+inline void _createInitAnnotation() {
+       int CommuteRuleSize = 3;
+       void *raw = CommutativityRule::operator new[](sizeof(CommutativityRule) * CommuteRuleSize);
+       CommutativityRule *commuteRules = static_cast<CommutativityRule*>(raw);
+
+       // Initialize commutativity rule 1
+       new( &commuteRules[0] )CommutativityRule("LOAD", "LOAD", "LOAD <-> LOAD (true)", _checkCommutativity1);
+       // Initialize commutativity rule 2
+       new( &commuteRules[1] )CommutativityRule("Store", "LOAD", "STORE <-> LOAD (true)", _checkCommutativity2);
+       // Initialize commutativity rule 3
+       new( &commuteRules[2] )CommutativityRule("STORE", "STORE", "STORE <-> STORE (true)", _checkCommutativity3);
+
+       // Initialize AnnoInit
+       AnnoInit *anno = new AnnoInit(_initial, _copyState, commuteRules, CommuteRuleSize);
+
+       // Initialize StateFunctions map
+       StateFunctions *stateFuncs;
+
+       // StateFunction for LOAD
+       stateFuncs = new StateFunctions("LOAD", _LOAD_Transition, NULL, _LOAD_PreCondition, _LOAD_SideEffect, NULL);
+       anno->addInterfaceFunctions("LOAD", stateFuncs);
+       // StateFunction for STORE 
+       stateFuncs = new StateFunctions("STORE", _STORE_Transition, NULL, NULL, _STORE_SideEffect, NULL);
+       anno->addInterfaceFunctions("STORE", stateFuncs);
+
+       // Create and instrument with the INIT annotation
+       cdsannotate(SPEC_ANALYSIS, new SpecAnnotation(INIT, anno));
+}
+
+inline Method _createInterfaceBeginAnnotation(string name) {
+       Method cur = new MethodCall(name);
+       // Create and instrument with the INTERFACE_BEGIN annotation
+       cdsannotate(SPEC_ANALYSIS, new SpecAnnotation(INTERFACE_BEGIN, cur));
+       return cur;
+}
+
+inline void _createOPDefineAnnotation() {
+       cdsannotate(SPEC_ANALYSIS, new SpecAnnotation(OP_DEFINE, NULL));
+}
+
+inline void _createPotentialOPAnnotation(string label) {
+       cdsannotate(SPEC_ANALYSIS, new SpecAnnotation(POTENTIAL_OP, new AnnoPotentialOP(label)));
+}
+
+inline void _createOPCheckAnnotation(string label) {
+       cdsannotate(SPEC_ANALYSIS, new SpecAnnotation(OP_CHECK, new AnnoOPCheck(label)));
+}
+
+inline void _createOPClearAnnotation() {
+       cdsannotate(SPEC_ANALYSIS, new SpecAnnotation(OP_CLEAR, NULL));
+}
+
+inline void _createOPClearDefineAnnotation() {
+       cdsannotate(SPEC_ANALYSIS, new SpecAnnotation(OP_CLEAR_DEFINE, NULL));
+}
diff --git a/cdsspec-compiler/notes/register-example/register.cc b/cdsspec-compiler/notes/register-example/register.cc
new file mode 100644 (file)
index 0000000..7f62bb7
--- /dev/null
@@ -0,0 +1,99 @@
+#include <stdio.h>
+#include <threads.h>
+#include <stdatomic.h>
+
+#include "librace.h"
+#include "register.h"
+
+/**    @DeclareState: int val;
+       @Initial: val = 0;
+       @Commutativity: LOAD <-> LOAD (true)
+       @Commutativity: STORE <-> LOAD (true)
+       @Commutativity: STORE <-> STORE (true)
+*/
+
+/** @Interface: LOAD
+       @PreCondition:
+       return HasItem(PREV, STATE(val) == RET);
+       @SideEffect: STATE(val) = RET;
+
+*/
+int Load_WRAPPER__(atomic_int *loc) {
+       return loc->load(memory_order_acquire);
+}
+
+int Load(atomic_int *loc) {
+       // Instrument with the INTERFACE_BEGIN annotation
+       Method cur = _createInterfaceBeginAnnotation("LOAD");
+       // Call the actual function
+       int RET = Load_WRAPPER__(loc);
+       
+       // Initialize the value struct
+       LOAD *value = new LOAD;
+       value->RET = RET;
+       value->loc = loc;
+
+       // Store the value info into the current MethodCall
+       cur->value = value;
+
+       // Return if there exists a return value
+       return RET;
+}
+
+/** @Interface: STORE 
+       @SideEffect: STATE(val) = val;
+
+*/
+void Store_WRAPPER__(atomic_int *loc, int val) {
+       loc->store(val, memory_order_release);
+}
+
+void Store(atomic_int *loc, int val) {
+       // Instrument with the INTERFACE_BEGIN annotation
+       Method cur = _createInterfaceBeginAnnotation("STORE");
+       // Call the actual function
+       Store_WRAPPER__(loc, val);
+       
+       // Initialize the value struct
+       STORE *value = new STORE;
+       value->loc = loc;
+       value->val = val;
+
+       // Store the value info into the current MethodCall
+       cur->value = value;
+}
+
+static void a(void *obj)
+{
+       Store(&x, 1);
+       Store(&x, 2);
+}
+
+static void b(void *obj)
+{
+       Store(&x, 3);
+}
+
+static void c(void *obj)
+{
+       int r1 = Load(&x);
+       int r2 = Load(&x);
+}
+
+int user_main(int argc, char **argv)
+{
+       thrd_t t1, t2, t3;
+
+       /** @Entry */
+       _createInitAnnotation();
+
+       thrd_create(&t1, (thrd_start_t)&a, NULL);
+       thrd_create(&t2, (thrd_start_t)&b, NULL);
+       thrd_create(&t3, (thrd_start_t)&c, NULL);
+
+       thrd_join(t1);
+       thrd_join(t2);
+       thrd_join(t3);
+
+       return 0;
+}
diff --git a/cdsspec-compiler/notes/register-example/register.cc.original b/cdsspec-compiler/notes/register-example/register.cc.original
new file mode 100644 (file)
index 0000000..bd8d032
--- /dev/null
@@ -0,0 +1,65 @@
+#include <stdio.h>
+#include <threads.h>
+#include <stdatomic.h>
+
+#include "librace.h"
+#include "register.h"
+
+/**    @DeclareState: int val;
+       @Initial: val = 0;
+       @Commutativity: LOAD <-> LOAD (true)
+       @Commutativity: STORE <-> LOAD (true)
+       @Commutativity: STORE <-> STORE (true)
+*/
+
+/** @Interface: LOAD
+       @PreCondition:
+       return HasItem(PREV, STATE(val) == RET);
+       @SideEffect: STATE(val) = RET;
+
+*/
+int Load(atomic_int *loc) {
+       return loc->load(memory_order_acquire);
+}
+
+/** @Interface: STORE 
+       @SideEffect: STATE(val) = val;
+
+*/
+void Store(atomic_int *loc, int val) {
+       loc->store(val, memory_order_release);
+}
+
+static void a(void *obj)
+{
+       Store(&x, 1);
+       Store(&x, 2);
+}
+
+static void b(void *obj)
+{
+       Store(&x, 3);
+}
+
+static void c(void *obj)
+{
+       int r1 = Load(&x);
+       int r2 = Load(&x);
+}
+
+int user_main(int argc, char **argv)
+{
+       thrd_t t1, t2, t3;
+
+       /** @Entry */
+
+       thrd_create(&t1, (thrd_start_t)&a, NULL);
+       thrd_create(&t2, (thrd_start_t)&b, NULL);
+       thrd_create(&t3, (thrd_start_t)&c, NULL);
+
+       thrd_join(t1);
+       thrd_join(t2);
+       thrd_join(t3);
+
+       return 0;
+}
diff --git a/cdsspec-compiler/notes/register-example/register.h b/cdsspec-compiler/notes/register-example/register.h
new file mode 100644 (file)
index 0000000..51c350a
--- /dev/null
@@ -0,0 +1,11 @@
+#include <stdio.h>
+#include <stdatomic.h>
+
+#include "librace.h"
+#include "cdsspec-generated.h"
+
+atomic_int x;
+
+int Load(atomic_int *loc);
+
+void Store(atomic_int *loc, int val);
diff --git a/cdsspec-compiler/notes/sequential_spec.txt b/cdsspec-compiler/notes/sequential_spec.txt
new file mode 100644 (file)
index 0000000..ef3baff
--- /dev/null
@@ -0,0 +1,137 @@
+/**
+       This file contains the design thoughts and details about how we use set
+       theory and more formalized way to design a simple specification language to
+       abstractly describe a sequential data structure.
+*/
+
+1. Design goals:
+   We should design a specification language that users (developers of data
+   structures) can use to describe the specification of sequential data
+   structures. The language should be as mathematical and precise as possible,
+   while it provides enough expressiveness and usability for users. That's to
+   say, users can learn the language easily and take advantage of it to describe
+   as many data structures as possible, e.g, Lock, Queue, Dequeue, LinkedList,
+   Stack, Vector, Hashtable, and UnorderedPool(maybe).
+
+2. Common data structures:
+   Data structures, to some degree, can be viewed as a collector with specific
+   operation on it. Those operations are done according to the maintained state
+   and pre-defined logic. Set in mathematics has similar characteristics, which
+   contains a collection of elements. However, elements in a set are distint.
+   Order_list, which is a list of elements that have a total order and can
+   duplicate, can be used to complement set. For example, a queue is a container
+   that has a FIFO order on the elements while a stack with a LIFO order. For
+   hashtable, it is a set of pairs (tuples) that has restrictions on the pairs.
+
+3. Potential constructs:
+   a) Set
+   The set here is conceptually similar to the set in Set Theory. We define our
+   set as a collection of unique and unordered elements. Uniqueness here
+   implicates that the set element should provide an internal equality check.
+   The following is some basic manipulations on set:
+   1) Tuple
+   Every element is an n-dimentional tuple, and each element of a tuple is a
+   tuple. This is basically used to represent the mapping between elements such
+   as a HashMap. Some examples:
+   a or (a) // 1-dimentional tuple, actually any variable is a 1-dimentional tuple
+   (key, value) // 2-dimentional tuple
+   (a, (a, b)) // 2-dimentional tuple, while the second column is a tuple too
+   1-dimentional tuple is the most basic part, it should have a type, such as
+   integer, boolean, or other templated types. The type of a set can be derived
+   from the tuple too. For example, A, B and C are basic types or templated
+   types, we can have Set<(A)>, Set<(A, B)> or Set<(A, (B, C))> as different
+   types. Set<(A)> contains elements of type A, Set<(A, B)> contains tuples of
+   (A, B) and Set<(A, (B, C))> contains tuples of (A, (B, C)). We can get an
+   instance of tuple in a way like (key, value).
+      The tuple has its basic operation dimention(n), which returns the tuple of
+         its nth column.
+   2) Union, intersection, and remove.
+   new_set = union(s1, s2); // returns a new set
+   or
+   s1.union(s2); // s1 becomes the union of s1 and s2, and it returns the new s1
+   It takes two sets and return the union of the two sets. Same for the
+   intersection and complement.
+   3) Cartesian product
+   new_set = prod(s1, s2); // returns the cartisian product of s1 & s2
+   The result of this operation is that a new set of tuples of s1 and s2.
+   4) Remove
+   set.remove(elem);
+   5) Find
+   subset = set.find((key, *)); // use wildcard to find possible subset
+   b) Order_List
+   This is a list of tuples that has an order. It should have the following
+   operations:
+   1) push_back
+   list.push_back(elem);
+   2) push_front
+   list.push_front(elem);
+   3) remove_back
+   elem = list.remove_back();
+   4) remove_front
+   elem = list.remove_front();
+   5) Find
+   elem = list.find(elem);
+   6) IndexOf
+   index = list.indexOf(elem);
+   index = list.indexOf(elem, 1);
+   7) PushAtIndex
+   list.pushAtIndex(1);
+   8) PushAfterElem
+   list.pushAfterElem(target, elem, 10); // find the first matched target from index 10,
+                                         // insert elem after target
+   9) RemoveIfExists
+   RemoveIfExists(elem)
+
+4. Examples:
+   1) Hashtable
+   @Declare:
+     Set<(Key, Value)> table;
+   @Manipulation:
+     void Put((Key) key, (Value) value) {
+       table.remove(table.find((key, *))).union((key,value));
+        }
+     
+        (Value) Get((Key) key) {
+       return table.find((key, *));
+        }
+
+   2) Stack
+   @Declare:
+     Order_List<(Type)> stack;
+   @Manipulation:
+     void Push((Type) elem) {
+       stack.push_back(elem);
+        }
+
+        (Type) Pop() {
+       return stack.remove_back();
+        }
+
+   3) LinkedList
+   // Suppose we store the pointer and they are unique??
+   @Declare:
+     Order_List<(Type)> list;
+   @Manipulation:
+     void add((Type) target, (Type) elem) {
+       assert(list.find(elem).size() == 1);
+          list.insertAfterElem(target, elem);
+        }
+
+        void remove((Type) target) {
+       list.remove(target);
+        }
+
+   4) UnorderPool
+   // A possible data structure, basically returns an element only once
+   @Declare:
+     Order_List<(Type)> pool;
+   @Manipulation:
+     void insert((Type) elem) {
+       pool.push_back(elem);
+        }
+
+     // Check if elem is possible to be removed; if yes, remove it & return true,
+        // otherwise return false.
+        bool remove((Type) elem) {
+       return pool.removeIfExists(elem);
+        }
diff --git a/cdsspec-compiler/run-javacc.sh b/cdsspec-compiler/run-javacc.sh
new file mode 100755 (executable)
index 0000000..8965426
--- /dev/null
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+SPEC_COMPILER_HOME=$(pwd)
+
+echo "CDSSpec Compiler home: " $SPEC_COMPILER_HOME
+
+JAVACC_PATH=$SPEC_COMPILER_HOME/lib
+
+UTIL_FILE=$SPEC_COMPILER_HOME/grammer/util.jj
+
+UTIL_OUTPUT_PATH=$SPEC_COMPILER_HOME/src/edu/uci/eecs/utilParser
+
+echo "Deleting the old generated java files."
+rm -rf $UTIL_OUTPUT_PATH/*
+
+mkdir -p $UTIL_OUTPUT_PATH
+
+java -cp $JAVACC_PATH/javacc.jar javacc -OUTPUT_DIRECTORY=$UTIL_OUTPUT_PATH $UTIL_FILE
diff --git a/cdsspec-compiler/src/edu/uci/eecs/codeGenerator/CodeAdditions.java b/cdsspec-compiler/src/edu/uci/eecs/codeGenerator/CodeAdditions.java
new file mode 100644 (file)
index 0000000..6d57975
--- /dev/null
@@ -0,0 +1,87 @@
+package edu.uci.eecs.codeGenerator;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+
+import edu.uci.eecs.specExtraction.Code;
+
+/**
+ * <p>
+ * This class represents all the code additions that should be added to a
+ * specific file.
+ * </p>
+ * 
+ * @author Peizhao Ou
+ * 
+ */
+public class CodeAdditions {
+
+       /**
+        * <p>
+        * This class represents the addition of code for a specific file. It
+        * records a list of lines to be inserted for a specific file, and the line
+        * after which the code should be inserted to the file.
+        * </p>
+        * 
+        * @author Peizhao Ou
+        * 
+        */
+       public static class CodeAddition {
+               // The line after which the code should be inserted to the file
+               // E.g. insertingLine == 0 => insert the lines ine very beginning.
+               public final int insertingLine;
+
+               // The code to be added to the specified place
+               public final Code code;
+
+               public CodeAddition(int insertingLine, Code code) {
+                       this.insertingLine = insertingLine;
+                       this.code = code;
+               }
+
+               public static Comparator<CodeAddition> lineNumComparator = new Comparator<CodeAddition>() {
+                       public int compare(CodeAddition addition1, CodeAddition addition2) {
+                               return addition1.insertingLine - addition2.insertingLine;
+                       }
+               };
+       }
+
+       // A list of code addition for the same file
+       public final ArrayList<CodeAddition> codeAdditions;
+
+       // The file that the list of additions belong to
+       public final File file;
+
+       public CodeAdditions(File file) {
+               this.file = file;
+               codeAdditions = new ArrayList<CodeAddition>();
+       }
+
+       public void addCodeAddition(CodeAddition a) {
+               this.codeAdditions.add(a);
+       }
+
+       /**
+        * <p>
+        * Whether the addition list is empty
+        * </p>
+        * 
+        * @return
+        */
+       public boolean isEmpty() {
+               return this.codeAdditions.size() == 0;
+       }
+
+       /**
+        * <p>
+        * Sort the list of code additions to the same file in an increasing order
+        * by the inserting line number of the code additions. We will call this
+        * function so that we can process code addition more conveniently.
+        * </p>
+        */
+       public void sort() {
+               Collections.sort(codeAdditions, CodeAddition.lineNumComparator);
+       }
+}
diff --git a/cdsspec-compiler/src/edu/uci/eecs/codeGenerator/CodeGenerator.java b/cdsspec-compiler/src/edu/uci/eecs/codeGenerator/CodeGenerator.java
new file mode 100644 (file)
index 0000000..ca6401d
--- /dev/null
@@ -0,0 +1,364 @@
+package edu.uci.eecs.codeGenerator;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.LineNumberReader;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+
+import edu.uci.eecs.codeGenerator.CodeAdditions.CodeAddition;
+import edu.uci.eecs.specExtraction.Code;
+import edu.uci.eecs.specExtraction.Construct;
+import edu.uci.eecs.specExtraction.DefineConstruct;
+import edu.uci.eecs.specExtraction.EntryConstruct;
+import edu.uci.eecs.specExtraction.InterfaceConstruct;
+import edu.uci.eecs.specExtraction.OPConstruct;
+import edu.uci.eecs.specExtraction.SpecExtractor;
+import edu.uci.eecs.specExtraction.SpecNaming;
+import edu.uci.eecs.specExtraction.WrongAnnotationException;
+import edu.uci.eecs.utilParser.ParseException;
+
+/**
+ * <p>
+ * This class represents the engine to generate instrumented code. To construct
+ * an object of this file, users need provide a string that represents the
+ * sub-directory under the benchmarks directory, then the engine will explore
+ * all the C/C++ files that ends with ".cc/.cpp/.c/.h" and extract specification
+ * annotations and generate instrumented code in the generated directory.
+ * </p>
+ * 
+ * @author Peizhao Ou
+ * 
+ */
+public class CodeGenerator {
+       // Files that we need to process
+       private ArrayList<File> files;
+
+       // Code addition list --- per file
+       private ArrayList<CodeAdditions> allAdditions;
+       // Line change map list --- per file; Each map represents the
+       // line->InterfaceConstruct mapping that will rename the interface
+       // declaration line.
+       private ArrayList<HashMap<Integer, InterfaceConstruct>> renamedLinesMapList;
+
+       // The string that users provide as a sub-directory in the benchmarks
+       // directory: e.g. ms-queue
+       public final String dirName;
+
+       // The original directory --- the benchmarks directory: e.g.
+       // ~/model-checker/benchmarks/
+       public final String originalDir;
+       // The directory for generated files: e.g. ~/model-checker/test-cdsspec/
+       public final String generatedDir;
+
+       // The specification annotation extractor
+       private SpecExtractor extractor;
+
+       public CodeGenerator(String originalDir, String generatedDir, String dirName) {
+               this.dirName = dirName;
+               this.originalDir = originalDir + "/" + dirName + "/";
+               this.generatedDir = generatedDir + "/" + dirName + "/";
+               
+               //this.originalDir = Environment.BenchmarksDir + dirName + "/";
+               //this.generatedDir = Environment.GeneratedFilesDir + dirName + "/";
+               
+               try {
+                       files = this.getSrcFiles(this.originalDir);
+                       System.out.println("Original benchmarks directory: " + this.originalDir);
+                       System.out.println("Generated benchmark directory: " + this.generatedDir);
+                       System.out.println("The specific benchmark directory: " + this.dirName);
+                       for (int i = 0; i < files.size(); i++) {
+                               System.out.println("    Processing: " + files.get(i));
+                       }
+               } catch (FileNotFoundException e) {
+                       e.printStackTrace();
+               }
+               extractor = new SpecExtractor();
+               try {
+                       extractor.extract(files);
+               } catch (WrongAnnotationException e) {
+                       e.printStackTrace();
+               } catch (ParseException e) {
+                       e.printStackTrace();
+               }
+       }
+
+       /**
+        * <p>
+        * This function initializes the list of code additions and line changes for
+        * all the files. For the code additions of a file, we sort them in an
+        * increasing order by the inserting line number.
+        * </p>
+        * 
+        */
+       private void getAllCodeChanges() {
+               allAdditions = new ArrayList<CodeAdditions>();
+               renamedLinesMapList = new ArrayList<HashMap<Integer, InterfaceConstruct>>();
+               for (int i = 0; i < files.size(); i++) {
+                       File file = files.get(i);
+                       // One CodeAdditions per file
+                       CodeAdditions additions = new CodeAdditions(file);
+                       // Add the additions for this file to the list
+                       allAdditions.add(additions);
+
+                       // One CodeChange per file
+                       HashMap<Integer, InterfaceConstruct> renamedLinesMap = new HashMap<Integer, InterfaceConstruct>();
+                       // Add it the the list
+                       renamedLinesMapList.add(renamedLinesMap);
+
+                       // Extract all the additions
+                       ArrayList<OPConstruct> OPList = extractor.OPListMap.get(file);
+                       EntryConstruct entry = extractor.entryMap.get(file);
+                       ArrayList<DefineConstruct> defineList = extractor.defineListMap
+                                       .get(file);
+                       ArrayList<InterfaceConstruct> interfaceList = extractor.interfaceListMap
+                                       .get(file);
+                       Code code = null;
+                       CodeAddition addition = null;
+                       // For ordering point constructs
+                       if (OPList != null) {
+                               for (OPConstruct con : OPList) {
+                                       code = CodeGeneratorUtils.Generate4OPConstruct(con);
+                                       addition = new CodeAddition(con.beginLineNum, code);
+                                       additions.addCodeAddition(addition);
+                               }
+                       }
+                       // For entry constructs
+                       if (entry != null) {
+                               code = CodeGeneratorUtils.Generate4Entry(entry);
+                               addition = new CodeAddition(entry.beginLineNum, code);
+                               additions.addCodeAddition(addition);
+                       }
+                       // For define constructs
+                       if (defineList != null) {
+                               for (DefineConstruct con : defineList) {
+                                       code = CodeGeneratorUtils.Generate4Define(con);
+                                       addition = new CodeAddition(con.endLineNum, code);
+                                       additions.addCodeAddition(addition);
+                               }
+                       }
+                       // For interface constructs
+                       if (interfaceList != null) {
+                               for (InterfaceConstruct con : interfaceList) {
+                                       code = CodeGeneratorUtils.GenerateInterfaceWrapper(con);
+                                       addition = new CodeAddition(con.getEndLineNumFunction(),
+                                                       code);
+                                       additions.addCodeAddition(addition);
+                                       // Record the line to be changed
+                                       renamedLinesMap.put(con.endLineNum + 1, con);
+                               }
+                       }
+
+                       // Sort additions by line number increasingly
+                       additions.sort();
+               }
+       }
+
+       /**
+        * <p>
+        * For a specific file, given the code additions and line changes mapping
+        * for that file, this function will generate the new code for that file and
+        * write it back to the destination directory.
+        * </p>
+        * 
+        * @param file
+        *            The file to be processed
+        * @param additions
+        *            The sorted code additions for the file
+        * @param renamedLinesMap
+        *            The line change mapping for the file
+        */
+       private void writeCodeChange(File file, CodeAdditions additions,
+                       HashMap<Integer, InterfaceConstruct> renamedLinesMap) {
+               Code newCode = new Code();
+               BufferedReader br = null;
+               LineNumberReader lineReader = null;
+               int lineNum = 0;
+               String curLine = null;
+
+               String dest = generatedDir + file.getName();
+               CodeAddition curAddition = null;
+               int additionIdx = -1;
+               if (!additions.isEmpty()) {
+                       additionIdx = 0;
+                       curAddition = additions.codeAdditions.get(0);
+               }
+
+               // Include the header for C/C++ files (.c/.cc/.cpp)
+               String name = file.getName();
+               if (name.endsWith(".c") || name.endsWith(".cc")
+                               || name.endsWith(".cpp")) {
+                       newCode.addLine(CodeGeneratorUtils.Comment("Add the"
+                                       + SpecNaming.CDSSpecGeneratedHeader + " header file"));
+                       newCode.addLine(CodeGeneratorUtils
+                                       .IncludeHeader(SpecNaming.CDSSpecGeneratedHeader));
+                       newCode.addLine("");
+               }
+
+               try {
+                       br = new BufferedReader(new FileReader(file));
+                       lineReader = new LineNumberReader(br);
+                       while ((curLine = lineReader.readLine()) != null) {
+                               lineNum = lineReader.getLineNumber();
+                               InterfaceConstruct construct = null;
+                               if ((construct = renamedLinesMap.get(lineNum)) != null) {
+                                       // Rename line
+                                       String newLine = construct.getFunctionHeader()
+                                                       .getRenamedFuncLine();
+                                       newCode.addLine(newLine);
+                               } else {
+                                       // First add the current line
+                                       newCode.addLine(curLine);
+                                       // Then check if we need to add code
+                                       if (curAddition != null
+                                                       && lineNum == curAddition.insertingLine) {
+                                               // Need to insert code
+                                               newCode.addLines(curAddition.code);
+                                               // Increase to the next code addition
+                                               additionIdx++;
+                                               curAddition = additionIdx == additions.codeAdditions
+                                                               .size() ? null : additions.codeAdditions
+                                                               .get(additionIdx);
+                                       }
+                               }
+                       }
+                       // Write new code change to destination
+                       CodeGeneratorUtils.write2File(dest, newCode.lines);
+                       // System.out.println("/*************** " + file.getName()
+                       // + "  *************/");
+                       // System.out.println(newCode);
+               } catch (FileNotFoundException e) {
+                       e.printStackTrace();
+               } catch (IOException e) {
+                       e.printStackTrace();
+               }
+       }
+
+       /**
+        * <p>
+        * This function is the main interface for the CodeGenerator class. After
+        * constructing a CodeGenerator object, users can call this function to
+        * complete the code generation and file writing process.
+        * </p>
+        */
+       public void generateCode() {
+               // Extract all the code additions and line change
+               getAllCodeChanges();
+
+               // Generate the header file and CPP file
+               Code generatedHeader = CodeGeneratorUtils
+                               .GenerateCDSSpecHeaderFile(extractor);
+               Code generatedCPP = CodeGeneratorUtils
+                               .GenerateCDSSpecCPPFile(extractor);
+               CodeGeneratorUtils
+                               .write2File(generatedDir + SpecNaming.CDSSpecGeneratedName
+                                               + ".h", generatedHeader.lines);
+               CodeGeneratorUtils.write2File(generatedDir
+                               + SpecNaming.CDSSpecGeneratedCPP, generatedCPP.lines);
+
+               // Iterate over each file
+               for (int i = 0; i < files.size(); i++) {
+                       File file = files.get(i);
+                       CodeAdditions additions = allAdditions.get(i);
+                       HashMap<Integer, InterfaceConstruct> renamedLinesMap = renamedLinesMapList
+                                       .get(i);
+                       writeCodeChange(file, additions, renamedLinesMap);
+               }
+       }
+
+       /**
+        * <p>
+        * This is just a testing function that outputs the generated code, but not
+        * actually write them to the disk.
+        * </p>
+        */
+       private void testGenerator() {
+               // Test code generation
+               Code generatedHeader = CodeGeneratorUtils
+                               .GenerateCDSSpecHeaderFile(extractor);
+               Code generatedCPP = CodeGeneratorUtils
+                               .GenerateCDSSpecCPPFile(extractor);
+
+               System.out.println("/***** Generated header file *****/");
+               System.out.println(generatedHeader);
+               System.out.println("/***** Generated cpp file *****/");
+               System.out.println(generatedCPP);
+
+               for (File file : extractor.OPListMap.keySet()) {
+                       ArrayList<OPConstruct> list = extractor.OPListMap.get(file);
+                       for (OPConstruct con : list) {
+                               Code code = CodeGeneratorUtils.Generate4OPConstruct(con);
+                               System.out.println("/*****  *****/");
+                               System.out.println(con.annotation);
+                               System.out.println(code);
+                       }
+               }
+
+               for (File f : extractor.entryMap.keySet()) {
+                       EntryConstruct con = extractor.entryMap.get(f);
+                       System.out.println("/*****  *****/");
+                       System.out.println(con.annotation);
+                       System.out.println(CodeGeneratorUtils.Generate4Entry(con));
+               }
+
+               for (File file : extractor.interfaceListMap.keySet()) {
+                       ArrayList<InterfaceConstruct> list = extractor.interfaceListMap
+                                       .get(file);
+                       for (InterfaceConstruct con : list) {
+                               Code code = CodeGeneratorUtils.GenerateInterfaceWrapper(con);
+                               System.out.println("/***** Interface wrapper *****/");
+                               System.out.println(con.getFunctionHeader().getHeaderLine());
+                               System.out
+                                               .println(con.getFunctionHeader().getRenamedFuncLine());
+                               System.out.println(code);
+                       }
+               }
+       }
+
+       public ArrayList<File> getSrcFiles(String dirName)
+                       throws FileNotFoundException {
+               ArrayList<File> res = new ArrayList<File>();
+               File dir = new File(dirName);
+               if (dir.isDirectory() && dir.exists()) {
+                       for (String file : dir.list()) {
+                               if (file.endsWith(".h") || file.endsWith(".c")
+                                               || file.endsWith(".cc") || file.endsWith(".cpp")) {
+                                       res.add(new File(dir.getAbsolutePath() + "/" + file));
+                               }
+                       }
+               } else {
+                       throw new FileNotFoundException(dirName
+                                       + " is not a valid directory!");
+               }
+               return res;
+       }
+
+       static public void main(String[] args) {
+               if (args.length < 3) {
+                       System.out
+                                       .println("Usage: CodeGenerator <Benchmarks-directory> <Directory-for-generated-files> <specific-benchmark-lists...>");
+                       return;
+               }
+               
+               // String[] dirNames = args;
+               
+               String[] dirNames = new String[args.length - 2];
+               for (int i = 0; i < args.length - 2; i++) {
+                       dirNames[i] = args[i + 2];
+               }
+//             String[] dirNames = Environment.Benchmarks;
+
+               for (int i = 0; i < dirNames.length; i++) {
+                       String dirName = dirNames[i];
+                       System.out.println("/**********   Generating CDSSpec files for "
+                                       + dirName + "    **********/");
+//                     CodeGenerator generator = new CodeGenerator(Environment.BenchmarksDir, Environment.GeneratedFilesDir, dirName);
+                       CodeGenerator generator = new CodeGenerator(args[0], args[1], dirName);
+                       generator.generateCode();
+               }
+       }
+}
diff --git a/cdsspec-compiler/src/edu/uci/eecs/codeGenerator/CodeGeneratorUtils.java b/cdsspec-compiler/src/edu/uci/eecs/codeGenerator/CodeGeneratorUtils.java
new file mode 100644 (file)
index 0000000..f85ec8e
--- /dev/null
@@ -0,0 +1,1280 @@
+package edu.uci.eecs.codeGenerator;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+
+import edu.uci.eecs.specExtraction.Code;
+import edu.uci.eecs.specExtraction.CommutativityRule;
+import edu.uci.eecs.specExtraction.DefineConstruct;
+import edu.uci.eecs.specExtraction.EntryConstruct;
+import edu.uci.eecs.specExtraction.FunctionHeader;
+import edu.uci.eecs.specExtraction.GlobalConstruct;
+import edu.uci.eecs.specExtraction.InterfaceConstruct;
+import edu.uci.eecs.specExtraction.OPConstruct;
+import edu.uci.eecs.specExtraction.SpecExtractor;
+import edu.uci.eecs.specExtraction.SpecNaming;
+import edu.uci.eecs.specExtraction.VariableDeclaration;
+
+/**
+ * <p>
+ * Some utility functions for generating specification checking code.
+ * </p>
+ * 
+ * @author Peizhao Ou
+ * 
+ */
+public class CodeGeneratorUtils {
+
+       public static void PrintCode(ArrayList<String> code) {
+               for (int i = 0; i < code.size(); i++) {
+                       System.out.println(code.get(i));
+               }
+       }
+
+       public static String Comment(String comment) {
+               return "/** " + comment + " */";
+       }
+
+       public static String ShortComment(String comment) {
+               return "// " + comment;
+       }
+
+       public static String IncludeHeader(String header) {
+               return "#include " + header;
+       }
+
+       public static String Brace(String val) {
+               return "(" + val + ")";
+       }
+
+       public static String Quote(String val) {
+               return "\"" + val + "\"";
+       }
+
+       public static String Assign(String varName, String val) {
+               return varName + " = " + val + ";";
+       }
+
+       public static String AssignToPtr(String structName, String field, String val) {
+               return structName + "->" + field + " = " + val + ";";
+       }
+
+       public static String Declare(String type, String name) {
+               return type + " " + name + ";";
+       }
+
+       public static String Declare(VariableDeclaration varDecl) {
+               return Declare(varDecl.type, varDecl.name);
+       }
+
+       public static String DeclareDefine(String type, String var, String val) {
+               return type + " " + var + " = " + val + ";";
+       }
+
+       /**
+        * <p>
+        * Insert a number of tabs at the beginning of the line.
+        * </p>
+        * 
+        * @param line
+        *            Input line
+        * @param tabCnt
+        *            The number of tabs to be inserted
+        * @return A line that starts with the specific inserted tabs
+        */
+       public static String TabbedLine(String line, int tabCnt) {
+               String res = "";
+               for (int i = 0; i < tabCnt; i++)
+                       res = "\t" + res;
+               res = res + line;
+               return res;
+       }
+
+       /**
+        * <p>
+        * Insert a tab at the beginning of the line.
+        * </p>
+        * 
+        * @param line
+        *            Input line
+        * @return A line that starts with one inserted tab
+        */
+       public static String TabbedLine(String line) {
+               return "\t" + line;
+       }
+
+       /**
+        * <p>
+        * This function generates the code for the header file that our
+        * specification generates automatically --- cdsspec-generated.h.
+        * </p>
+        * 
+        * @param extractor
+        *            The SpecExtractor that contains the extracted information
+        * @return The generated code
+        */
+       public static Code GenerateCDSSpecHeaderFile(SpecExtractor extractor) {
+               HashSet<String> headerFiles = extractor.headerFiles;
+               GlobalConstruct globalConstruct = extractor.getGlobalConstruct();
+               HashMap<File, ArrayList<InterfaceConstruct>> interfaceListMap = extractor.interfaceListMap;
+               HashSet<String> OPLabelSet = extractor.OPLabelSet;
+
+               Code code = new Code();
+
+               // Add auto-generated comments
+               code.addLine("/**");
+               code.addLine(TabbedLine("This is a header file auto-generated by CDSSpec compiler; together, CDSSpec"));
+               code.addLine(TabbedLine("compiler should have generated the accompanying implementation file that"));
+               code.addLine(TabbedLine("implements the some functions declared in this file. In order to instrument"));
+               code.addLine(TabbedLine("your benchmark for CDSSpec checker to check, you should include this header"));
+               code.addLine(TabbedLine("file in every file you use an CDSSpec annotation. Note that it should be"));
+               code.addLine(TabbedLine("placed in the end of all other header files. Currently we require a C++"));
+               code.addLine(TabbedLine("compiler that supports C++11."));
+               code.addLine("*/");
+               code.addLine("");
+
+               code.addLine("#ifndef _"
+                               + SpecNaming.CDSSpecGeneratedName.toUpperCase().replace('-',
+                                               '_') + "_H");
+               code.addLine("#define _"
+                               + SpecNaming.CDSSpecGeneratedName.toUpperCase().replace('-',
+                                               '_') + "_H");
+               code.addLine("");
+
+               // FIXME: We have included ad-hoc header files here
+               // System included headers
+               code.addLine(ShortComment("System included headers go here"));
+               code.addLine(IncludeHeader(SpecNaming.SPECANNOTATION_API));
+               code.addLine(IncludeHeader(SpecNaming.STDLIB));
+
+               code.addLine("");
+
+               // Users included headers
+               code.addLine(ShortComment("User included headers go here"));
+               for (String header : headerFiles) {
+                       code.addLine(IncludeHeader(header));
+               }
+               code.addLine("");
+
+               // Decalre extern "C" --- begin
+               code.addLine("#ifdef __cplusplus");
+               code.addLine("extern \"C\" {");
+               code.addLine("#endif");
+               code.addLine("");
+
+               // Declare _createOPDefineUnattached
+               code.addLine(ShortComment("Declare _createOPDefineUnattached"));
+               // void _createOPDefineUnattached();
+               code.addLine("void _createOPDefineUnattached();");
+               code.addLine("");
+
+               // Declare _createOPClearDefineUnattached
+               code.addLine(ShortComment("Declare _createOPClearDefineUnattached"));
+               // void _createOPClearDefineUnattached();
+               code.addLine("void _createOPClearDefineUnattached();");
+               code.addLine("");
+
+               code.addLine(ShortComment("Declaration of some c-strings (CSTR)"));
+
+               // Interface name strings
+               code.addLine(ShortComment("Interface name strings"));
+               for (File file : interfaceListMap.keySet()) {
+                       ArrayList<InterfaceConstruct> list = interfaceListMap.get(file);
+                       for (InterfaceConstruct construct : list) {
+                               String name = construct.getName();
+                               code.addLine(Declare("extern " + SpecNaming.CString,
+                                               SpecNaming.AppendStr(name)));
+                       }
+               }
+               code.addLine("");
+
+               // Ordering points label strings
+               code.addLine(ShortComment("Ordering points label strings"));
+               for (String label : OPLabelSet) {
+                       code.addLine(Declare("extern " + SpecNaming.CString,
+                                       SpecNaming.AppendStr(label)));
+               }
+               code.addLine("");
+
+               // Declare customized value struct
+               for (File file : interfaceListMap.keySet()) {
+                       ArrayList<InterfaceConstruct> list = interfaceListMap.get(file);
+                       for (InterfaceConstruct construct : list) {
+                               // Declare custom value struct for the interface
+                               String name = construct.getName();
+                               String structName = construct.getStructName();
+                               code.addLine(ShortComment("Declare custom value struct for "
+                                               + name));
+                               code.addLine("typedef struct " + structName + " {");
+                               FunctionHeader funcHeader = construct.getFunctionHeader();
+                               // C_RET & also the S_RET
+                               // The idea is that we store the S_RET in the __value struct, and every time we access/update
+                               // S_RET, we actually access "__value->S_RET" (good for read and write)...
+                               if (!funcHeader.returnType.equals("void")) {
+                                       code.addLine(TabbedLine(Declare(funcHeader.returnType,
+                                                       SpecNaming.C_RET)));
+                                       code.addLine(TabbedLine(Declare(funcHeader.returnType,
+                                                       SpecNaming.S_RET)));
+                               }
+                               // Arguments
+                               for (VariableDeclaration decl : funcHeader.args) {
+                                       code.addLine(TabbedLine(Declare(decl)));
+                               }
+                               code.addLine("} " + structName + ";");
+                               code.addLine("");
+                       }
+               }
+
+               // Declare INIT annotation instrumentation function
+               code.addLine(ShortComment("Declare INIT annotation instrumentation function"));
+               code.addLine("void _createInitAnnotation();");
+               code.addLine("");
+
+               // Decalre extern "C" --- begin
+               code.addLine("#ifdef __cplusplus");
+               code.addLine("};");
+               code.addLine("#endif");
+               code.addLine("");
+
+               // Declare #endif
+               code.addLine("#endif");
+
+               return code;
+       }
+
+       /**
+        * <p>
+        * This function generates the code for the CPP file that our specification
+        * generates automatically --- cdsspec-generated.cc.
+        * </p>
+        * 
+        * @param extractor
+        *            The SpecExtractor that contains the extracted information
+        * @return The generated code
+        */
+       public static Code GenerateCDSSpecCPPFile(SpecExtractor extractor) {
+               GlobalConstruct globalConstruct = extractor.getGlobalConstruct();
+               HashMap<File, ArrayList<InterfaceConstruct>> interfaceListMap = extractor.interfaceListMap;
+               HashSet<String> OPLabelSet = extractor.OPLabelSet;
+
+               Code code = new Code();
+               String line = null;
+               Code fieldsInit = null;
+
+               // Add auto-generated comments
+               code.addLine("/**");
+               code.addLine(TabbedLine("This is an implementation file auto-generated by CDSSpec compiler to"));
+               code.addLine(TabbedLine("instrument your benchmark for CDSSpec checker to check. Currently we require"));
+               code.addLine(TabbedLine("a C++ compiler that supports C++11."));
+               code.addLine("*/");
+               code.addLine("");
+
+               code.addLine("#include " + SpecNaming.CDSSpecGeneratedHeader);
+               code.addLine("#include " + SpecNaming.CDSANNOTATE);
+               code.addLine("#include " + SpecNaming.SPEC_COMMON);
+               code.addLine("#include " + SpecNaming.METHODCALL);
+               code.addLine("#include " + SpecNaming.CDSSPEC);
+               code.addLine("#include " + SpecNaming.SPECANNOTATION);
+               code.addLine("");
+               code.addLine("");
+
+               // Declare customized StateStruct
+               code.addLine(ShortComment("Declare customized StateStruct"));
+               code.addLine("typedef struct " + SpecNaming.StateStruct + " {");
+               for (VariableDeclaration decl : globalConstruct.declState) {
+                       code.addLine(TabbedLine(Declare(decl)));
+               }
+               code.addLine("");
+               // Define state destructor
+               code.addLine(TabbedLine(ShortComment("Define state destructor")));
+               code.addLine(TabbedLine("~" + SpecNaming.StateStruct + "() {"));
+               if (!globalConstruct.autoGenClear) {
+                       code.addLine(TabbedLine(
+                                       ShortComment("Execute user-defined state clear code"), 2));
+               } else {
+                       code.addLine(TabbedLine(
+                                       ShortComment("Execute auto-generated state clear code"), 2));
+               }
+               globalConstruct.clearState.align(2);
+               code.addLines(globalConstruct.clearState);
+               code.addLine(TabbedLine("}"));
+               code.addLine("");
+
+               code.addLine(TabbedLine("SNAPSHOTALLOC"));
+               code.addLine("");
+               code.addLine("} " + SpecNaming.StateStruct + ";");
+               code.addLine("");
+               code.addLine("");
+
+               // Define the fake ordering point operation
+               code.addLine(ShortComment("Define the fake ordering point operation"));
+               // atomic_int _FAKE_OP_;
+               code.addLine("atomic_int " + SpecNaming.FakeOP + ";");
+               code.addLine("");
+
+               // Define _createOPDefineUnattached
+               code.addLine(ShortComment("Define _createOPDefineUnattached"));
+               code.addLine("void " + SpecNaming.CreateOPDefineUnattachedFunc + "() {");
+               code.addLine(TabbedLine(ShortComment("A load acting as the fake OP")));
+               code.addLine(TabbedLine(SpecNaming.FakeOP
+                               + ".load(memory_order_relaxed);"));
+               code.addLine(TabbedLine(SpecNaming.CreateOPDefineAnnoFunc + "();"));
+               code.addLine("}");
+
+               // Define _createOPClearDefineUnattached
+               code.addLine(ShortComment("Define _createOPClearDefineUnattached"));
+               code.addLine("void " + SpecNaming.CreateOPClearDefineUnattachedFunc
+                               + "() {");
+               code.addLine(TabbedLine(ShortComment("A load acting as the fake OP")));
+               code.addLine(TabbedLine(SpecNaming.FakeOP
+                               + ".load(memory_order_relaxed);"));
+               code.addLine(TabbedLine(SpecNaming.CreateOPClearDefineAnnoFunc + "();"));
+               code.addLine("}");
+
+               code.addLine(ShortComment("Definition of some c-strings (CSTR)"));
+               code.addLine(ShortComment("A special empty string"));
+               code.addLine(DeclareDefine(SpecNaming.CString, SpecNaming.EmptyCString,
+                               "\"\""));
+               code.addLine("");
+
+               // Interface name strings
+               code.addLine(ShortComment("Interface name strings"));
+               for (File file : interfaceListMap.keySet()) {
+                       ArrayList<InterfaceConstruct> list = interfaceListMap.get(file);
+                       for (InterfaceConstruct construct : list) {
+                               String name = construct.getName();
+                               code.addLine(DeclareDefine(SpecNaming.CString,
+                                               SpecNaming.AppendStr(name), Quote(name)));
+                       }
+               }
+               code.addLine("");
+
+               // Commutativity rule strings
+               code.addLine(ShortComment("Commutativity rule strings"));
+               for (int i = 1; i <= globalConstruct.commutativityRules.size(); i++) {
+                       CommutativityRule rule = globalConstruct.commutativityRules
+                                       .get(i - 1);
+                       code.addLine(DeclareDefine(SpecNaming.CString,
+                                       SpecNaming.AppendStr(SpecNaming.Commutativity + i),
+                                       Quote(rule.toString())));
+               }
+               code.addLine("");
+
+               // Ordering points label strings
+               code.addLine(ShortComment("Ordering points label strings"));
+               for (String label : OPLabelSet) {
+                       code.addLine(DeclareDefine(SpecNaming.CString,
+                                       SpecNaming.AppendStr(label), Quote(label)));
+               }
+               code.addLine("");
+
+               // Special function name strings
+               code.addLine(ShortComment("Special function name strings"));
+               code.addLine(DeclareDefine(SpecNaming.CString,
+                               SpecNaming.AppendStr(SpecNaming.InitalState), Quote("_"
+                                               + SpecNaming.InitalState.toLowerCase())));
+               code.addLine(DeclareDefine(SpecNaming.CString,
+                               SpecNaming.AppendStr(SpecNaming.CopyState), Quote("_"
+                                               + SpecNaming.CopyState.toLowerCase())));
+               code.addLine(DeclareDefine(SpecNaming.CString,
+                               SpecNaming.AppendStr(SpecNaming.ClearState), Quote("_"
+                                               + SpecNaming.ClearState.toLowerCase())));
+               code.addLine(DeclareDefine(SpecNaming.CString,
+                               SpecNaming.AppendStr(SpecNaming.FinalState), Quote("_"
+                                               + SpecNaming.FinalState.toLowerCase())));
+               code.addLine(DeclareDefine(SpecNaming.CString,
+                               SpecNaming.AppendStr(SpecNaming.PrintState), Quote("_"
+                                               + SpecNaming.PrintState.toLowerCase())));
+               code.addLine("");
+
+               // Interface name strings
+               for (File file : interfaceListMap.keySet()) {
+                       ArrayList<InterfaceConstruct> list = interfaceListMap.get(file);
+                       for (InterfaceConstruct construct : list) {
+                               String name = construct.getName();
+                               code.addLine(ShortComment(name + " function strings"));
+                               // Transition
+                               String tmpFunc = name + "_" + SpecNaming.Transition;
+                               code.addLine(DeclareDefine(SpecNaming.CString,
+                                               SpecNaming.AppendStr(tmpFunc), Quote("_" + tmpFunc)));
+                               // PreCondition
+                               tmpFunc = name + "_" + SpecNaming.PreCondition;
+                               if (!construct.preCondition.isEmpty())
+                                       code.addLine(DeclareDefine(SpecNaming.CString,
+                                                       SpecNaming.AppendStr(tmpFunc), Quote("_" + tmpFunc)));
+                               else
+                                       code.addLine(DeclareDefine(SpecNaming.CString,
+                                                       SpecNaming.AppendStr(tmpFunc),
+                                                       SpecNaming.EmptyCString));
+                               // JustifyingPrecondition
+                               tmpFunc = name + "_" + SpecNaming.JustifyingPrecondition;
+                               if (!construct.justifyingPrecondition.isEmpty())
+                                       code.addLine(DeclareDefine(SpecNaming.CString,
+                                                       SpecNaming.AppendStr(tmpFunc), Quote("_" + tmpFunc)));
+                               else
+                                       code.addLine(DeclareDefine(SpecNaming.CString,
+                                                       SpecNaming.AppendStr(tmpFunc),
+                                                       SpecNaming.EmptyCString));
+                               // JustifyingPostcondition
+                               tmpFunc = name + "_" + SpecNaming.JustifyingPostcondition;
+                               if (!construct.justifyingPostcondition.isEmpty())
+                                       code.addLine(DeclareDefine(SpecNaming.CString,
+                                                       SpecNaming.AppendStr(tmpFunc), Quote("_" + tmpFunc)));
+                               else
+                                       code.addLine(DeclareDefine(SpecNaming.CString,
+                                                       SpecNaming.AppendStr(tmpFunc),
+                                                       SpecNaming.EmptyCString));
+                               // PostCondition
+                               tmpFunc = name + "_" + SpecNaming.PostCondition;
+                               if (!construct.postCondition.isEmpty())
+                                       code.addLine(DeclareDefine(SpecNaming.CString,
+                                                       SpecNaming.AppendStr(tmpFunc), Quote("_" + tmpFunc)));
+                               else
+                                       code.addLine(DeclareDefine(SpecNaming.CString,
+                                                       SpecNaming.AppendStr(tmpFunc),
+                                                       SpecNaming.EmptyCString));
+                               // Print
+                               tmpFunc = name + "_" + SpecNaming.PrintValue;
+                               if (!construct.print.isEmpty())
+                                       code.addLine(DeclareDefine(SpecNaming.CString,
+                                                       SpecNaming.AppendStr(tmpFunc), Quote("_" + tmpFunc)));
+                               else
+                                       code.addLine(DeclareDefine(SpecNaming.CString,
+                                                       SpecNaming.AppendStr(tmpFunc),
+                                                       SpecNaming.EmptyCString));
+                               code.addLine("");
+                       }
+               }
+
+               // Define @Initial
+               code.addLine(ShortComment("Define @" + SpecNaming.InitalState));
+               code.addLine("void _" + SpecNaming.InitalState.toLowerCase() + "("
+                               + SpecNaming.Method + " " + SpecNaming.Method1 + ") {");
+               code.addLine(TabbedLine(DeclareDefine(SpecNaming.StateStruct, "*"
+                               + SpecNaming.StateInst, "new " + SpecNaming.StateStruct)));
+               // Define macros
+               for (VariableDeclaration decl : globalConstruct.declState) {
+                       code.addLine(TabbedLine("#define " + decl.name + " "
+                                       + SpecNaming.StateInst + "->" + decl.name));
+               }
+               if (!globalConstruct.autoGenInitial)
+                       code.addLine(TabbedLine(ShortComment("User-defined state intialization code")));
+               else
+                       // Auto-generated the initialization function
+                       code.addLine(TabbedLine(ShortComment("Auto-generated state intialization code")));
+               // Align the code with one tab
+               globalConstruct.initState.align(1);
+               code.addLines(globalConstruct.initState);
+               // Undefine macros
+               for (VariableDeclaration decl : globalConstruct.declState) {
+                       code.addLine(TabbedLine("#undef " + decl.name));
+               }
+               code.addLine("");
+               code.addLine(TabbedLine(AssignToPtr(SpecNaming.Method1,
+                               SpecNaming.StateInst, SpecNaming.StateInst)));
+               code.addLine("}");
+               code.addLine("");
+
+               // Define @Copy
+               code.addLine(ShortComment("Define @" + SpecNaming.CopyState));
+               code.addLine("void _" + SpecNaming.CopyState.toLowerCase() + "("
+                               + SpecNaming.Method + " " + "dest, " + SpecNaming.Method
+                               + " src) {");
+               // StateStruct *OLD = (StateStruct*) src->state;
+               code.addLine(TabbedLine(DeclareDefine(SpecNaming.StateStruct, "*"
+                               + SpecNaming.OldStateInst, Brace(SpecNaming.StateStruct + "*")
+                               + " src->" + SpecNaming.StateInst)));
+               // StateStruct *NEW = new StateStruct;
+               code.addLine(TabbedLine(DeclareDefine(SpecNaming.StateStruct, "*"
+                               + SpecNaming.NewStateInst, "new " + SpecNaming.StateStruct)));
+               if (!globalConstruct.autoGenCopy)
+                       code.addLine(TabbedLine(ShortComment("User-defined state copy statements")));
+               else
+                       // Auto-generated the copy function
+                       code.addLine(TabbedLine(ShortComment("Auto-generated state copy statements")));
+               globalConstruct.copyState.align(1);
+               code.addLines(globalConstruct.copyState);
+               code.addLine("");
+               code.addLine(TabbedLine(AssignToPtr("dest", SpecNaming.StateInst,
+                               SpecNaming.NewStateInst)));
+               code.addLine("}");
+               code.addLine("");
+
+               // Define @Clear
+               code.addLine(ShortComment("Define @" + SpecNaming.ClearState));
+               code.addLine("void _" + SpecNaming.ClearState.toLowerCase() + "("
+                               + SpecNaming.Method + " " + SpecNaming.Method1 + ") {");
+               // Retrieve the state
+               code.addLine(TabbedLine(ShortComment("Retrieve the state")));
+               code.addLine(TabbedLine(DeclareDefine(SpecNaming.StateStruct, "*"
+                               + SpecNaming.StateInst, "(" + SpecNaming.StateStruct + "*) "
+                               + SpecNaming.Method1 + "->state")));
+               // Explicitly call the state destructor
+               code.addLine(TabbedLine(ShortComment("Explicitly call the state destructor")));
+               code.addLine(TabbedLine("delete " + SpecNaming.StateInst + ";"));
+               code.addLine("}");
+               code.addLine("");
+
+               // Define @Print
+               code.addLine(ShortComment("Define @" + SpecNaming.PrintState));
+               code.addLine("void _" + SpecNaming.PrintState.toLowerCase() + "("
+                               + SpecNaming.Method + " " + SpecNaming.Method1 + ") {");
+
+               // Initialize state struct fields
+               fieldsInit = GenerateStateFieldsInitialization(SpecNaming.Method1,
+                               SpecNaming.StateInst, globalConstruct);
+               fieldsInit.align(1);
+               code.addLines(fieldsInit);
+               code.addLine("");
+               if (!globalConstruct.autoGenPrint)
+                       code.addLine(TabbedLine(ShortComment("Execute user-defined state printing code")));
+               else
+                       // Auto-generated the copy function
+                       code.addLine(TabbedLine(ShortComment("Execute auto-generated state printing code")));
+
+               // Align the code with one tab
+               globalConstruct.printState.align(1);
+               code.addLines(globalConstruct.printState);
+               code.addLine("}");
+               code.addLine("");
+
+               // Define @Commutativity
+               code.addLine(ShortComment("Define commutativity checking functions"));
+               for (int i = 1; i <= globalConstruct.commutativityRules.size(); i++) {
+                       CommutativityRule rule = globalConstruct.commutativityRules
+                                       .get(i - 1);
+                       code.addLine("bool _check" + SpecNaming.Commutativity + i + "("
+                                       + SpecNaming.Method + " m1, " + SpecNaming.Method
+                                       + " m2) {");
+                       // if (m1->name == _ENQ_str && m2->name == _DEQ_str) {
+                       code.addLine(TabbedLine("if (m1->name == "
+                                       + SpecNaming.AppendStr(rule.method1) + " && m2->name == "
+                                       + SpecNaming.AppendStr(rule.method2) + ") {"));
+                       // Initialize M1 & M2 in commutativity rule
+                       // e.g. ENQ *M1 = (ENQ*) m1->value;
+                       String structName1 = InterfaceConstruct
+                                       .createStructName(rule.method1);
+                       String structName2 = InterfaceConstruct
+                                       .createStructName(rule.method2);
+                       code.addLine(TabbedLine(
+                                       DeclareDefine(structName1, "*M1", "(" + structName1
+                                                       + "*) m1->value"), 2));
+                       code.addLine(TabbedLine(
+                                       DeclareDefine(structName2, "*M2", "(" + structName2
+                                                       + "*) m2->value"), 2));
+                       code.addLine(TabbedLine("return !(" + rule.condition + ");", 2));
+                       code.addLine(TabbedLine("}"));
+                       code.addLine(TabbedLine("return true;"));
+
+                       code.addLine("}");
+                       code.addLine("");
+               }
+
+               // Define customized interface functions
+               for (File file : interfaceListMap.keySet()) {
+                       ArrayList<InterfaceConstruct> list = interfaceListMap.get(file);
+                       for (InterfaceConstruct construct : list) {
+                               fieldsInit = null;
+
+                               // Define interface functions
+                               String name = construct.getName();
+                               String structName = construct.getStructName();
+                               code.addLine("/**********    " + name
+                                               + " functions    **********/");
+                               // Define @Transition for INTERFACE
+                               code.addLine(ShortComment("Define @" + SpecNaming.Transition
+                                               + " for " + name));
+                               code.addLine("bool _" + name + "_" + SpecNaming.Transition
+                                               + "(" + SpecNaming.Method + " " + SpecNaming.Method1
+                                               + ", " + SpecNaming.Method + " " + SpecNaming.Method2
+                                               + ") {");
+
+                               // Initialize value struct fields
+                               fieldsInit = GenerateInterfaceFieldsInitialization(
+                                               SpecNaming.Method2, SpecNaming.InterfaceValueInst,
+                                               construct);
+                               fieldsInit.align(1);
+                               code.addLines(fieldsInit);
+
+                               construct.transition.align(1);
+                               code.addLine(TabbedLine(ShortComment("Execute Transition")));
+                               code.addLines(construct.transition);
+
+                               // By default, we will return true for state transition
+                               code.addLine(TabbedLine(ShortComment("By default @Transition returns true")));
+                               code.addLine(TabbedLine("return true;"));
+                               code.addLine("}");
+                               code.addLine("");
+
+                               // Define @PreCondition
+                               if (!construct.preCondition.isEmpty()) {
+                                       code.addLine(ShortComment("Define @"
+                                                       + SpecNaming.PreCondition + " for " + name));
+                                       code.addLine("bool _" + name + "_" + SpecNaming.PreCondition
+                                                       + "(" + SpecNaming.Method + " " + SpecNaming.Method1
+                                                       + ", " + SpecNaming.Method + " " + SpecNaming.Method2
+                                                       + ") {");
+
+                                       // Initialize value struct fields
+                                       fieldsInit = GenerateInterfaceFieldsInitialization(
+                                                       SpecNaming.Method2, SpecNaming.InterfaceValueInst,
+                                                       construct);
+                                       fieldsInit.align(1);
+                                       code.addLines(fieldsInit);
+
+                                       construct.preCondition.align(1);
+                                       code.addLine(TabbedLine(ShortComment("Execute PreCondition")));
+                                       code.addLines(construct.preCondition);
+
+                                       // By default, we will return true for @PreCondition
+                                       code.addLine(TabbedLine(ShortComment("By default @PreCondition returns true")));
+                                       code.addLine(TabbedLine("return true;"));
+
+                                       code.addLine("}");
+                                       code.addLine("");
+
+                               }
+                               // Define @JustifyingPrecondition
+                               if (!construct.justifyingPrecondition.isEmpty()) {
+                                       code.addLine(ShortComment("Define @"
+                                                       + SpecNaming.JustifyingPrecondition + " for " + name));
+                                       code.addLine("bool _" + name + "_" + SpecNaming.JustifyingPrecondition
+                                                       + "(" + SpecNaming.Method + " " + SpecNaming.Method1
+                                                       + ", " + SpecNaming.Method + " " + SpecNaming.Method2
+                                                       + ") {");
+
+                                       // Initialize value struct fields
+                                       fieldsInit = GenerateInterfaceFieldsInitialization(
+                                                       SpecNaming.Method2, SpecNaming.InterfaceValueInst,
+                                                       construct);
+                                       fieldsInit.align(1);
+                                       code.addLines(fieldsInit);
+
+                                       construct.justifyingPrecondition.align(1);
+                                       code.addLine(TabbedLine(ShortComment("Execute JustifyingPrecondition")));
+                                       code.addLines(construct.justifyingPrecondition);
+
+                                       // By default, we will return true for @JustifyingPrecondition
+                                       code.addLine(TabbedLine(ShortComment("By default @JustifyingPrecondition returns true")));
+                                       code.addLine(TabbedLine("return true;"));
+
+                                       code.addLine("}");
+                                       code.addLine("");
+
+                               }
+                               // Define @JustifyingPostcondition
+                               if (!construct.justifyingPostcondition.isEmpty()) {
+                                       code.addLine(ShortComment("Define @"
+                                                       + SpecNaming.JustifyingPostcondition + " for " + name));
+                                       code.addLine("bool _" + name + "_" + SpecNaming.JustifyingPostcondition
+                                                       + "(" + SpecNaming.Method + " " + SpecNaming.Method1
+                                                       + ", " + SpecNaming.Method + " " + SpecNaming.Method2
+                                                       + ") {");
+
+                                       // Initialize value struct fields
+                                       fieldsInit = GenerateInterfaceFieldsInitialization(
+                                                       SpecNaming.Method2, SpecNaming.InterfaceValueInst,
+                                                       construct);
+                                       fieldsInit.align(1);
+                                       code.addLines(fieldsInit);
+
+                                       construct.justifyingPostcondition.align(1);
+                                       code.addLine(TabbedLine(ShortComment("Execute JustifyingPostcondition")));
+                                       code.addLines(construct.justifyingPostcondition);
+
+                                       // By default, we will return true for @JustifyingPostcondition
+                                       code.addLine(TabbedLine(ShortComment("By default @JustifyingPostcondition returns true")));
+                                       code.addLine(TabbedLine("return true;"));
+
+                                       code.addLine("}");
+                                       code.addLine("");
+
+                               }
+                               // Define @PostCondition
+                               if (!construct.postCondition.isEmpty()) {
+                                       code.addLine(ShortComment("Define @"
+                                                       + SpecNaming.PostCondition + " for " + name));
+                                       code.addLine("bool _" + name + "_" + SpecNaming.PostCondition
+                                                       + "(" + SpecNaming.Method + " " + SpecNaming.Method1
+                                                       + ", " + SpecNaming.Method + " " + SpecNaming.Method2
+                                                       + ") {");
+
+                                       // Initialize value struct fields
+                                       fieldsInit = GenerateInterfaceFieldsInitialization(
+                                                       SpecNaming.Method2, SpecNaming.InterfaceValueInst,
+                                                       construct);
+                                       fieldsInit.align(1);
+                                       code.addLines(fieldsInit);
+
+                                       construct.postCondition.align(1);
+                                       code.addLine(TabbedLine(ShortComment("Execute PostCondition")));
+                                       code.addLines(construct.postCondition);
+
+                                       // By default, we will return true for @PostCondition
+                                       code.addLine(TabbedLine(ShortComment("By default @PostCondition returns true")));
+                                       code.addLine(TabbedLine("return true;"));
+
+                                       code.addLine("}");
+                                       code.addLine("");
+                               }
+                               // Define @Print
+                               if (!construct.print.isEmpty()) {
+                                       code.addLine(ShortComment("Define @"
+                                                       + SpecNaming.PrintValue + " for " + name));
+                                       code.addLine("void _" + name + "_" + SpecNaming.PrintValue
+                                                       + "(" + SpecNaming.Method + " "
+                                                       + SpecNaming.Method1 + ") {");
+                                       // Initialize value struct fields
+                                       fieldsInit = GenerateInterfaceFieldsInitialization(
+                                                       SpecNaming.Method1, SpecNaming.InterfaceValueInst,
+                                                       construct);
+                                       fieldsInit.align(1);
+                                       code.addLines(fieldsInit);
+
+                                       construct.print.align(1);
+                                       if (!construct.autoGenPrint)
+                                               code.addLine(TabbedLine(ShortComment("Execute user-defined value printing code")));
+                                       else
+                                               // Auto-generated the value printing function
+                                               code.addLine(TabbedLine(ShortComment("Execute auto-generated value printing code")));
+                                       code.addLines(construct.print);
+
+                                       code.addLine("}");
+                                       code.addLine("");
+                               }
+                       }
+               }
+
+               // Define INIT annotation instrumentation function
+               code.addLine(ShortComment("Define INIT annotation instrumentation function"));
+               code.addLine("void _createInitAnnotation() {");
+
+               // Init the fake ordering point place holder
+               code.addLine(TabbedLine(ShortComment("Init the fake ordering point place holder")));
+               code.addLine(TabbedLine(SpecNaming.FakeOP
+                               + ".store(1, memory_order_relaxed);"));
+
+               // Init commutativity rules
+               code.addLine(TabbedLine(ShortComment("Init commutativity rules")));
+               code.addLine(TabbedLine(DeclareDefine("int",
+                               SpecNaming.CommutativityRuleSizeInst,
+                               Integer.toString(globalConstruct.commutativityRules.size()))));
+               String tmp = SpecNaming.NewSize
+                               + Brace(SpecNaming.CommutativityRule + ", sizeof"
+                                               + Brace(SpecNaming.CommutativityRule) + " * "
+                                               + SpecNaming.CommutativityRuleSizeInst);
+               code.addLine(TabbedLine(DeclareDefine(SpecNaming.CommutativityRule, "*"
+                               + SpecNaming.CommutativityRuleInst, tmp)));
+               for (int i = 1; i <= globalConstruct.commutativityRules.size(); i++) {
+                       CommutativityRule rule = globalConstruct.commutativityRules
+                                       .get(i - 1);
+                       code.addLine(TabbedLine(ShortComment("Initialize commutativity rule ")
+                                       + i));
+                       // new( &commuteRules[0] )CommutativityRule(_ENQ_str, _DEQ_str,
+                       // _Commutativity1_str, _checkCommutativity1)
+                       line = "new"
+                                       + Brace(" &" + SpecNaming.CommutativityRuleInst + "["
+                                                       + (i - 1) + "] ") + SpecNaming.CommutativityRule
+                                       + "(" + SpecNaming.AppendStr(rule.method1) + ", "
+                                       + SpecNaming.AppendStr(rule.method2) + ", "
+                                       + SpecNaming.AppendStr(SpecNaming.Commutativity + i) + ", "
+                                       + "_check" + SpecNaming.Commutativity + i + ");";
+                       code.addLine(TabbedLine(line));
+               }
+
+               // Initialize AnnoInit
+               code.addLine(TabbedLine(ShortComment("Initialize AnnoInit")));
+               // AnnoInit *init = new AnnoInit(
+               code.addLine(TabbedLine(SpecNaming.AnnoInit + " *"
+                               + SpecNaming.AnnoInitInst + " = new " + SpecNaming.AnnoInit
+                               + "("));
+               // new NamedFunction(_Initial_str, INITIAL, (void*) _initial),
+               code.addLine(TabbedLine("new " + SpecNaming.NamedFunction + "("
+                               + SpecNaming.AppendStr(SpecNaming.InitalState) + ", "
+                               + SpecNaming.InitalState.toUpperCase() + ", " + "(void*) _"
+                               + SpecNaming.InitalState.toLowerCase() + "),", 2));
+               // new NamedFunction(_Final_str, FINAL, (void*) NULL_FUNC),
+               line = "new " + SpecNaming.NamedFunction + "("
+                               + SpecNaming.AppendStr(SpecNaming.FinalState) + ", "
+                               + SpecNaming.FinalState.toUpperCase() + ", " + "(void*) ";
+               if (globalConstruct.finalState.isEmpty()) {
+                       line = line + SpecNaming.NullFunc + "),";
+               } else {
+                       line = line + "_" + SpecNaming.FinalState.toUpperCase();
+               }
+               code.addLine(TabbedLine(line, 2));
+               // new NamedFunction(_Copy_str, COPY, (void*) _copy),
+               code.addLine(TabbedLine("new " + SpecNaming.NamedFunction + "("
+                               + SpecNaming.AppendStr(SpecNaming.CopyState) + ", "
+                               + SpecNaming.CopyState.toUpperCase() + ", " + "(void*) _"
+                               + SpecNaming.CopyState.toLowerCase() + "),", 2));
+               // new NamedFunction(_Clear_str, CLEAR, (void*) _clear),
+               code.addLine(TabbedLine("new " + SpecNaming.NamedFunction + "("
+                               + SpecNaming.AppendStr(SpecNaming.ClearState) + ", "
+                               + SpecNaming.ClearState.toUpperCase() + ", " + "(void*) _"
+                               + SpecNaming.ClearState.toLowerCase() + "),", 2));
+               // new NamedFunction(_Print_str, PRINT_STATE, (void*) _print),
+               code.addLine(TabbedLine("new " + SpecNaming.NamedFunction + "("
+                               + SpecNaming.AppendStr(SpecNaming.PrintState) + ", "
+                               + SpecNaming.PrintStateType + ", " + "(void*) _"
+                               + SpecNaming.PrintState.toLowerCase() + "),", 2));
+               // commuteRules, CommuteRuleSize);
+               code.addLine(TabbedLine(SpecNaming.CommutativityRuleInst + ", "
+                               + SpecNaming.CommutativityRuleSizeInst + ");", 2));
+               code.addLine("");
+
+               // Declare StateFunctions map
+               code.addLine(TabbedLine(ShortComment("Declare StateFunctions map")));
+               code.addLine(TabbedLine(Declare(SpecNaming.StateFunctions, "*"
+                               + SpecNaming.StateFunctionsInst)));
+               code.addLine("");
+
+               // StateFunction for interface
+               for (File file : interfaceListMap.keySet()) {
+                       ArrayList<InterfaceConstruct> list = interfaceListMap.get(file);
+                       for (InterfaceConstruct construct : list) {
+                               String name = construct.getName();
+                               code.addLine(TabbedLine(ShortComment("StateFunction for "
+                                               + name)));
+                               // stateFuncs = new StateFunctions(
+                               code.addLine(TabbedLine(SpecNaming.StateFunctionsInst
+                                               + " = new " + SpecNaming.StateFunctions + "("));
+                               // new NamedFunction(_ENQ_Transition_str, TRANSITION, (void*)
+                               // _ENQ_Transition),
+                               // Transition
+                               code.addLine(TabbedLine(
+                                               "new "
+                                                               + SpecNaming.NamedFunction
+                                                               + "("
+                                                               + SpecNaming.AppendStr(name + "_"
+                                                                               + SpecNaming.Transition) + ", "
+                                                               + SpecNaming.TransitionType + ", (void*) _"
+                                                               + name + "_" + SpecNaming.Transition + "),", 2));
+                               // PreCondition
+                               line = "new "
+                                               + SpecNaming.NamedFunction
+                                               + "("
+                                               + SpecNaming.AppendStr(name + "_"
+                                                               + SpecNaming.PreCondition) + ", "
+                                               + SpecNaming.PreConditionType + ", (void*) ";
+                               if (construct.preCondition.isEmpty()) {
+                                       line = line + SpecNaming.NullFunc + "),";
+                               } else {
+                                       line = line + "_" + name + "_" + SpecNaming.PreCondition
+                                                       + "),";
+                               }
+                               code.addLine(TabbedLine(line, 2));
+                               // JustifyingPrecondition
+                               line = "new "
+                                               + SpecNaming.NamedFunction
+                                               + "("
+                                               + SpecNaming.AppendStr(name + "_"
+                                                               + SpecNaming.JustifyingPrecondition) + ", "
+                                               + SpecNaming.JustifyingPreconditionType + ", (void*) ";
+                               if (construct.justifyingPrecondition.isEmpty()) {
+                                       line = line + SpecNaming.NullFunc + "),";
+                               } else {
+                                       line = line + "_" + name + "_" + SpecNaming.JustifyingPrecondition
+                                                       + "),";
+                               }
+                               code.addLine(TabbedLine(line, 2));
+                               // JustifyingPostcondition
+                               line = "new "
+                                               + SpecNaming.NamedFunction
+                                               + "("
+                                               + SpecNaming.AppendStr(name + "_"
+                                                               + SpecNaming.JustifyingPostcondition) + ", "
+                                               + SpecNaming.JustifyingPostconditionType + ", (void*) ";
+                               if (construct.justifyingPostcondition.isEmpty()) {
+                                       line = line + SpecNaming.NullFunc + "),";
+                               } else {
+                                       line = line + "_" + name + "_" + SpecNaming.JustifyingPostcondition
+                                                       + "),";
+                               }
+                               code.addLine(TabbedLine(line, 2));
+                               // PostCondition
+                               line = "new "
+                                               + SpecNaming.NamedFunction
+                                               + "("
+                                               + SpecNaming.AppendStr(name + "_"
+                                                               + SpecNaming.PostCondition) + ", "
+                                               + SpecNaming.PostConditionType + ", (void*) ";
+                               if (construct.postCondition.isEmpty()) {
+                                       line = line + SpecNaming.NullFunc + "),";
+                               } else {
+                                       line = line + "_" + name + "_" + SpecNaming.PostCondition
+                                                       + "),";
+                               }
+                               code.addLine(TabbedLine(line, 2));
+                               // Print (PrintValue
+                               line = "new "
+                                               + SpecNaming.NamedFunction
+                                               + "("
+                                               + SpecNaming.AppendStr(name + "_"
+                                                               + SpecNaming.PrintValue) + ", "
+                                               + SpecNaming.PrintValueType + ", (void*) ";
+                               if (construct.print.isEmpty()) {
+                                       line = line + SpecNaming.NullFunc + ")";
+                               } else {
+                                       line = line + "_" + name + "_" + SpecNaming.PrintValue
+                                                       + ")";
+                               }
+                               code.addLine(TabbedLine(line, 2));
+                               code.addLine(TabbedLine(");"));
+
+                               // init->addInterfaceFunctions(_ENQ_str, stateFuncs);
+                               code.addLine(TabbedLine(SpecNaming.AnnoInitInst
+                                               + "->"
+                                               + SpecNaming.AddInterfaceFunctions
+                                               + Brace(SpecNaming.AppendStr(name) + ", "
+                                                               + SpecNaming.StateFunctionsInst) + ";"));
+                               code.addLine("");
+                       }
+               }
+
+               // Create and instrument with the INIT annotation
+               code.addLine(TabbedLine(ShortComment("Create and instrument with the INIT annotation")));
+               // cdsannotate(SPEC_ANALYSIS, new SpecAnnotation(INIT, init));
+               code.addLine(TabbedLine(SpecNaming.CDSAnnotateFunc
+                               + Brace(SpecNaming.SPEC_ANALYSIS
+                                               + ", new "
+                                               + SpecNaming.SpecAnnotation
+                                               + Brace(SpecNaming.AnnoTypeInit + ", "
+                                                               + SpecNaming.AnnoInitInst)) + ";"));
+
+               code.addLine("}");
+               code.addLine("");
+
+               return code;
+       }
+
+       /**
+        * <p>
+        * This function generates a list of lines that initialize the fields of the
+        * global state struct. See below.
+        * </p>
+        * 
+        * <p>
+        * <code>
+        * StateStruct *state = (StateStruct*) _M->state;
+        * <br>
+        * IntList * q = state->q;
+        * </code>
+        * </p>
+        * 
+        * <p>
+        * In this example, _M --> methodInst, state --> inst.
+        * </p>
+        * 
+        * @param methodInst
+        *            See description
+        * @param inst
+        *            See description
+        * @param construct
+        *            The global state construct
+        * @return The generated code
+        */
+       public static Code GenerateStateFieldsInitialization(String methodInst,
+                       String inst, GlobalConstruct construct) {
+               Code res = new Code();
+               res.addLine(ShortComment("Initialize " + SpecNaming.StateStruct
+                               + " fields"));
+               res.addLine(DeclareDefine(SpecNaming.StateStruct, "*" + inst, "("
+                               + SpecNaming.StateStruct + "*) " + methodInst + "->state"));
+               for (VariableDeclaration decl : construct.declState) {
+                       res.addLine(DeclareDefine(decl.type, decl.name, inst + "->"
+                                       + decl.name));
+               }
+               return res;
+       }
+
+       /**
+        * <p>
+        * This function generates a list of lines that initialize the fields of a
+        * specific interface struct. See below.
+        * </p>
+        * 
+        * <p>
+        * <code>
+        * ENQ *info = (ENQ*) _M->value;
+        * <br>
+        * IntList * q = info->q;
+        * </code>
+        * </p>
+        * 
+        * <p>
+        * In this example, ENQ --> structType, _M --> methodInst, info --> inst
+        * </p>
+        * 
+        * @param methodInst
+        *            See description
+        * @param inst
+        *            See description
+        * @param construct
+        *            The corresponding interface construct
+        * @return The generated code
+        */
+       public static Code GenerateInterfaceFieldsInitialization(String methodInst,
+                       String inst, InterfaceConstruct construct) {
+               Code res = new Code();
+               String name = construct.getName();
+               String structName = construct.getStructName();
+               res.addLine(ShortComment("Initialize fields for " + name));
+               // The very first assignment "
+               res.addLine(DeclareDefine(structName, "*" + inst, "(" + structName
+                               + "*) " + methodInst + "->" + SpecNaming.MethodValueField));
+               // Don't leave out the C_RET field
+               if (!construct.getFunctionHeader().isReturnVoid()) {
+                       res.addLine(DeclareDefine(construct.getFunctionHeader().returnType,
+                                       SpecNaming.C_RET, inst + "->" + SpecNaming.C_RET));
+               }
+               // For arguments
+               for (VariableDeclaration decl : construct.getFunctionHeader().args) {
+                       res.addLine(DeclareDefine(decl.type, decl.name, inst + "->"
+                                       + decl.name));
+               }
+               return res;
+       }
+
+       /**
+        * <p>
+        * This function generates the code to be inserted right after the ordering
+        * point construct (instrumentation code)
+        * </p>
+        * 
+        * @param construct
+        *            The corresponding ordering point construct
+        * @return The generated code
+        */
+       public static Code Generate4OPConstruct(OPConstruct construct) {
+               Code code = new Code();
+               String curLine = construct.annotation;
+               String label = construct.label;
+               String prefixTabs = curLine.substring(0, curLine.indexOf("/**"));
+               if (!construct.condition.equals("true")) {
+                       code.addLine(prefixTabs + "if (" + construct.condition + ")");
+                       prefixTabs = prefixTabs + "\t";
+               }
+
+               switch (construct.type) {
+               case OPDefine:
+                       code.addLine(prefixTabs + SpecNaming.CreateOPDefineAnnoFunc + "();");
+                       break;
+               case OPDefineUnattached:
+                       code.addLine(prefixTabs + SpecNaming.CreateOPDefineUnattachedFunc
+                                       + "();");
+                       break;
+               case PotentialOP:
+                       code.addLine(prefixTabs + SpecNaming.CreatePotentialOPAnnoFunc
+                                       + "(" + SpecNaming.AppendStr(label) + ");");
+                       break;
+               case OPCheck:
+                       code.addLine(prefixTabs + SpecNaming.CreateOPCheckAnnoFunc + "("
+                                       + SpecNaming.AppendStr(label) + ");");
+                       break;
+               case OPClear:
+                       code.addLine(prefixTabs + SpecNaming.CreateOPClearAnnoFunc + "();");
+                       break;
+               case OPClearDefine:
+                       code.addLine(prefixTabs + SpecNaming.CreateOPClearDefineAnnoFunc
+                                       + "();");
+                       break;
+               case OPClearDefineUnattached:
+                       code.addLine(prefixTabs
+                                       + SpecNaming.CreateOPClearDefineUnattachedFunc + "();");
+                       break;
+               default:
+                       break;
+               }
+               return code;
+       }
+
+       /**
+        * <p>
+        * This function generates the code to be inserted right after the entry
+        * construct (instrumentation code)
+        * </p>
+        * 
+        * @param construct
+        *            The corresponding entry construct
+        * @return
+        */
+       public static Code Generate4Entry(EntryConstruct construct) {
+               Code res = new Code();
+               String curLine = construct.annotation;
+               String prefixTabs = curLine.substring(0, curLine.indexOf("/**"));
+               // _createInitAnnotation();
+               res.addLine(prefixTabs + SpecNaming.CreateInitAnnoFunc + "();");
+               return res;
+       }
+
+       /**
+        * <p>
+        * This function generates the code to be inserted right after the "@Define"
+        * construct (instrumentation code)
+        * </p>
+        * 
+        * @param construct
+        *            The corresponding entry construct
+        * @return
+        */
+       public static Code Generate4Define(DefineConstruct construct) {
+               Code code = new Code();
+               code.addLine("");
+               code.addLine("/**********    User-defined code in annotation (BEGIN)    **********/");
+               code.addLines(construct.code);
+               code.addLine("/**********    User-defined code in annotation (END)    **********/");
+               return code;
+       }
+
+       /**
+        * <p>
+        * This function generates the new interface wrapper code to be inserted
+        * right after the end of the interface definition
+        * </p>
+        * 
+        * @param construct
+        *            The corresponding interface construct
+        * @return The generated code
+        */
+       public static Code GenerateInterfaceWrapper(InterfaceConstruct construct) {
+               Code code = new Code();
+
+               String name = construct.getName();
+               String structName = construct.getStructName();
+               String beginLine = construct.getFunctionHeader().getHeaderLine();
+               Pattern regexpSpace = Pattern.compile("^(\\s*)\\S.*$");
+               Matcher matcherSpace = regexpSpace.matcher(beginLine);
+               String prefixTabs = "";
+               if (matcherSpace.find())
+                       prefixTabs = matcherSpace.group(1);
+
+               // Add one line to separate
+               code.addLine("");
+               code.addLine(prefixTabs
+                               + ShortComment("Generated wrapper interface for " + name));
+               if (beginLine.indexOf('{') == -1) { // We need to add the '{' to the end
+                                                                                       // of the line
+                       code.addLine(beginLine + " {");
+               } else {
+                       code.addLine(beginLine);
+               }
+               // Instrument with the INTERFACE_BEGIN annotations
+               code.addLine(prefixTabs
+                               + "\t"
+                               + ShortComment("Instrument with the INTERFACE_BEGIN annotation"));
+               // CAnnoInterfaceInfo info = _createInterfaceBeginAnnotation(_DEQ_str);
+               code.addLine(prefixTabs
+                               + "\t"
+                               + DeclareDefine(SpecNaming.AnnoInterfaceInfo, "*"
+                                               + SpecNaming.AnnoInterfaceInfoInst,
+                                               SpecNaming.CreateInterfaceBeginAnnoFunc
+                                                               + Brace(SpecNaming.AppendStr(name))));
+               // Call the actual function
+               code.addLine(prefixTabs + "\t"
+                               + ShortComment("Call the actual function"));
+               // bool C_RET = dequeue_ORIGINAL__(q, retVal, reclaimNode);
+               code.addLine(prefixTabs + "\t"
+                               + construct.getFunctionHeader().getRenamedCall() + ";");
+               code.addLine("");
+
+               // Initialize the value struct
+               code.addLine(prefixTabs + "\t"
+                               + ShortComment("Initialize the value struct"));
+               // The very first assignment "
+               code.addLine(prefixTabs
+                               + "\t"
+                               + DeclareDefine(structName,
+                                               "*" + SpecNaming.InterfaceValueInst, SpecNaming.New
+                                                               + Brace(structName)));
+               // Don't leave out the C_RET field
+               if (!construct.getFunctionHeader().isReturnVoid())
+                       code.addLine(prefixTabs
+                                       + "\t"
+                                       + AssignToPtr(SpecNaming.InterfaceValueInst,
+                                                       SpecNaming.C_RET, SpecNaming.C_RET));
+               // For arguments
+               for (VariableDeclaration decl : construct.getFunctionHeader().args)
+                       code.addLine(prefixTabs
+                                       + "\t"
+                                       + AssignToPtr(SpecNaming.InterfaceValueInst, decl.name,
+                                                       decl.name));
+               code.addLine("");
+
+               // Store the value info into the current MethodCall
+               // _setInterfaceBeginAnnotationValue(info, value);
+               code.addLine(prefixTabs
+                               + "\t"
+                               + ShortComment("Store the value info into the current MethodCall"));
+               code.addLine(prefixTabs
+                               + "\t"
+                               + SpecNaming.SetInterfaceBeginAnnoValueFunc
+                               + Brace(SpecNaming.AnnoInterfaceInfoInst + ", "
+                                               + SpecNaming.InterfaceValueInst) + ";");
+               code.addLine("");
+
+               // Instrument with the INTERFACE_END annotations
+               code.addLine(prefixTabs + "\t"
+                               + ShortComment("Instrument with the INTERFACE_END annotation"));
+               // _createInterfaceEndAnnotation(_DEQ_str);
+               code.addLine(prefixTabs + "\t"
+                               + SpecNaming.CreateInterfaceEndAnnoFunc
+                               + Brace(SpecNaming.AppendStr(name)) + ";");
+
+               // Return if necessary
+               if (!construct.getFunctionHeader().isReturnVoid())
+                       code.addLine(prefixTabs + "\treturn " + SpecNaming.C_RET + ";");
+               code.addLine(prefixTabs + "}");
+
+               return code;
+       }
+
+       /**
+        * <p>
+        * Write a list of lines (as the whole of the file) to a file ---
+        * newFileName. If that file does not exist, we create that file and then
+        * write the lines.
+        * </p>
+        * 
+        * @param newFileName
+        *            The name of the file to be written
+        * @param content
+        *            The list of lines that as a whole become the content of the
+        *            file
+        */
+       public static void write2File(String newFileName, ArrayList<String> content) {
+               File newFile = new File(newFileName);
+               newFile.getParentFile().mkdirs();
+               if (!newFile.exists()) {
+                       try {
+                               newFile.createNewFile();
+                       } catch (IOException e) {
+                               e.printStackTrace();
+                       }
+               }
+               BufferedWriter bw = null;
+               try {
+                       bw = new BufferedWriter(new FileWriter(newFile));
+                       for (int i = 0; i < content.size(); i++) {
+                               bw.write(content.get(i) + "\n");
+                       }
+                       bw.flush();
+               } catch (IOException e) {
+                       e.printStackTrace();
+               } finally {
+                       if (bw != null)
+                               try {
+                                       bw.close();
+                               } catch (IOException e) {
+                                       e.printStackTrace();
+                               }
+               }
+       }
+}
diff --git a/cdsspec-compiler/src/edu/uci/eecs/codeGenerator/Environment.java b/cdsspec-compiler/src/edu/uci/eecs/codeGenerator/Environment.java
new file mode 100644 (file)
index 0000000..b746060
--- /dev/null
@@ -0,0 +1,57 @@
+package edu.uci.eecs.codeGenerator;
+
+import java.util.ArrayList;
+
+/**
+ * <p>
+ * This class contains some constant strings related to the code generation
+ * process.
+ * </p>
+ * 
+ * @author Peizhao Ou
+ * 
+ */
+public class Environment {
+       public final static String HomeDir = System.getProperty("user.dir");
+       public final static String ModelCheckerHome = System
+                       .getProperty("user.home")
+                       + "/model-checker-priv/model-checker-priv/";
+       public final static String BenchmarksDir = ModelCheckerHome
+                       + "/benchmarks/";
+       public final static String ModelCheckerTestDir = ModelCheckerHome
+                       + "/test-cdsspec/";
+       public final static String GeneratedFilesDir = ModelCheckerTestDir;
+
+       public final static String REGISTER_ACQREL = "register-acqrel";
+       public final static String REGISTER_RELAXED = "register-relaxed";
+       public final static String MS_QUEUE = "ms-queue";
+       public final static String LINUXRWLOCKS = "linuxrwlocks";
+       public final static String MCS_LOCK = "mcs-lock";
+       public final static String DEQUE = "chase-lev-deque-bugfix";
+       public final static String DEQUE_BUGGY = "chase-lev-deque";
+       public final static String TREIBER_STACK = "treiber-stack";
+       public final static String TICKET_LOCK = "ticket-lock";
+       public final static String SEQLOCK = "seqlock";
+       public final static String READ_COPY_UPDATE = "read-copy-update";
+       public final static String CONCURRENT_MAP = "concurrent-hashmap";
+       public final static String SPSC = "spsc-bugfix";
+       public final static String MPMC = "mpmc-queue";
+       
+       public final static String BLOCKING_QUEUE_EXAMPLE = "blocking-mpmc-example";
+       
+       public final static String[] Benchmarks = {
+               MS_QUEUE,
+               LINUXRWLOCKS,
+               MCS_LOCK,
+               DEQUE,
+               DEQUE_BUGGY,
+               TICKET_LOCK,
+               SEQLOCK,
+               READ_COPY_UPDATE,
+               SPSC,
+               CONCURRENT_MAP,
+               MPMC,
+               BLOCKING_QUEUE_EXAMPLE,
+       }; 
+
+}
diff --git a/cdsspec-compiler/src/edu/uci/eecs/specExtraction/Code.java b/cdsspec-compiler/src/edu/uci/eecs/specExtraction/Code.java
new file mode 100644 (file)
index 0000000..d7bc5b1
--- /dev/null
@@ -0,0 +1,197 @@
+package edu.uci.eecs.specExtraction;
+
+import java.util.ArrayList;
+
+import edu.uci.eecs.specExtraction.SpecUtils.IntObj;
+
+/**
+ * <p>
+ * This class represents a piece of code --- a list of strings (lines). Such a
+ * wrapper makes code extraction and generation easier.
+ * </p>
+ * 
+ * @author Peizhao Ou
+ * 
+ */
+public class Code {
+
+       // The list that represents all the lines of this code snippet
+       public final ArrayList<String> lines;
+
+       public Code() {
+               lines = new ArrayList<String>();
+       }
+
+       /**
+        * <p>
+        * It adds a line, which is very likely to be a simple C/C++ statement,
+        * which is a string lines of statement.
+        * </p>
+        * 
+        * @param line
+        *            A C/C++ line of statement
+        */
+       public void addLine(String line) {
+               lines.add(line);
+       }
+
+       /**
+        * <p>
+        * It adds a list of lines, which are very likely to be simple C/C++
+        * statements.
+        * </p>
+        * 
+        * @param line
+        *            A list of C/C++ lines of statement
+        */
+       public void addLines(ArrayList<String> code) {
+               for (int i = 0; i < code.size(); i++)
+                       lines.add(code.get(i));
+       }
+
+       /**
+        * <p>
+        * It adds a list of lines, which are very likely to be simple C/C++
+        * statements.
+        * </p>
+        * 
+        * @param line
+        *            A Code object --- list of C/C++ lines of statement
+        */
+       public void addLines(Code code) {
+               addLines(code.lines);
+       }
+
+       /**
+        * @return Whether this code snippet is empty
+        */
+       public boolean isEmpty() {
+               return lines.size() == 0;
+       }
+
+       /**
+        * <p>
+        * Align the set of code with an initial number of tabs. This basically
+        * tries to make the generated code more readable.
+        * 
+        * @param initialTabsCnt
+        *            The number of tabs that we want to put before the code
+        *            initially.
+        */
+       public void align(int initialTabsCnt) {
+               int tabLevel = initialTabsCnt;
+               IntObj idx = new IntObj(0);
+               alignHelper(idx, tabLevel, false);
+       }
+
+       /**
+        * <p>
+        * This is a helper function to align a list of code. Caller should
+        * initialize an IntObj with intial value "0", and pass with the initial tab
+        * level and pass the value of "false" to the noBraceKeyword.
+        * 
+        * @param idx
+        *            The IntObj that represents the current index of the code lines
+        * @param tabLevel
+        *            The tab level we are currently at
+        * @param noBraceKeyword
+        *            Whether we just encountered a "noBraceKeyword"
+        */
+       private void alignHelper(IntObj idx, int tabLevel, boolean noBraceKeyword) {
+               for (; idx.getVal() < lines.size(); idx.inc()) {
+                       String curLine = lines.get(idx.getVal());
+                       String newLine = null;
+                       // Return to the previous recursive level
+                       if (closingBrace(curLine)) {
+                               return;
+                       }
+                       if ((noBraceKeyword && !keywordBrace(curLine) && !keywordNoBrace(curLine))) {
+                               // Before returning, we just need to first add the line with the
+                               // current tab
+                               newLine = makeTabs(tabLevel) + curLine;
+                               lines.set(idx.getVal(), newLine);
+                               return;
+                       }
+
+                       newLine = makeTabs(tabLevel) + curLine;
+                       lines.set(idx.getVal(), newLine);
+
+                       if (keywordBrace(curLine)) {
+                               idx.inc();
+                               alignHelper(idx, tabLevel + 1, false);
+                               // Add the closing line
+                               curLine = lines.get(idx.getVal());
+                               newLine = makeTabs(tabLevel) + curLine;
+                               lines.set(idx.getVal(), newLine);
+                       } else if (keywordNoBrace(curLine)) { // No brace
+                               idx.inc();
+                               alignHelper(idx, tabLevel + 1, true);
+                               if (noBraceKeyword)
+                                       return;
+                       }
+               }
+       }
+
+       /**
+        * <p>
+        * Lines that starts with a key word and ends with ";".
+        * </p>
+        * 
+        * @param curLine
+        * @return
+        */
+       private boolean closingBrace(String curLine) {
+               return curLine.endsWith("}");
+       }
+
+       /**
+        * <p>
+        * Lines that starts with a key word and ends with "{".
+        * </p>
+        * 
+        * @param curLine
+        * @return
+        */
+       private boolean keywordBrace(String curLine) {
+               return (curLine.startsWith("for") || curLine.startsWith("ForEach")
+                               || curLine.startsWith("if") || curLine.startsWith("else")
+                               || curLine.startsWith("while") || curLine.startsWith("do"))
+                               && curLine.endsWith("{");
+       }
+
+       /**
+        * <p>
+        * Lines that starts with a key word and ends with no "{" and no ";".
+        * </p>
+        * 
+        * @param curLine
+        * @return
+        */
+       private boolean keywordNoBrace(String curLine) {
+               return (curLine.startsWith("for") || curLine.startsWith("ForEach")
+                               || curLine.startsWith("if") || curLine.startsWith("else")
+                               || curLine.startsWith("while") || curLine.startsWith("do"))
+                               && !curLine.endsWith("{") && !curLine.endsWith(";");
+       }
+
+       /**
+        * @param tabCnt
+        *            The number of tabs
+        * @return Generate a string whose content is a specific number (tabCnt) of
+        *         tab symbols.
+        */
+       private String makeTabs(int tabCnt) {
+               String res = "";
+               for (int i = 0; i < tabCnt; i++)
+                       res = res + "\t";
+               return res;
+       }
+
+       public String toString() {
+               StringBuilder sb = new StringBuilder();
+               for (int i = 0; i < lines.size(); i++) {
+                       sb.append(lines.get(i) + "\n");
+               }
+               return sb.toString();
+       }
+}
diff --git a/cdsspec-compiler/src/edu/uci/eecs/specExtraction/CommutativityRule.java b/cdsspec-compiler/src/edu/uci/eecs/specExtraction/CommutativityRule.java
new file mode 100644 (file)
index 0000000..98b3cf9
--- /dev/null
@@ -0,0 +1,22 @@
+package edu.uci.eecs.specExtraction;
+
+/**
+ * <p> This class represents a commutativity rule in the specification.
+ * @author Peizhao Ou
+ *
+ */
+public class CommutativityRule {
+       public final String method1, method2;
+       
+       public final String condition;
+       
+       public CommutativityRule(String m1, String m2, String condition) {
+               this.method1 = m1;
+               this.method2 = m2;
+               this.condition = condition;
+       }
+       
+       public String toString() {
+               return method1 + " <-> " + method2 + ": " + condition; 
+       }
+}
diff --git a/cdsspec-compiler/src/edu/uci/eecs/specExtraction/Construct.java b/cdsspec-compiler/src/edu/uci/eecs/specExtraction/Construct.java
new file mode 100644 (file)
index 0000000..19aa44e
--- /dev/null
@@ -0,0 +1,28 @@
+package edu.uci.eecs.specExtraction;
+
+import java.io.File;
+
+/**
+ * <p>
+ * An abstract class for all different specification constructs, including
+ * global construct, interface construct and ordering point construct.
+ * </p>
+ * 
+ * @author Peizhao Ou
+ * 
+ */
+abstract public class Construct {
+       // The file that this construct is in
+       public final File file;
+       // The beginning line number of this construct (the plain text line number)
+       public final int beginLineNum;
+
+       public Construct(File file, int beginLineNum) {
+               this.file = file;
+               this.beginLineNum = beginLineNum;
+       }
+
+       public String toString() {
+               return file.getName() + ": Line " + Integer.toString(beginLineNum);
+       }
+}
diff --git a/cdsspec-compiler/src/edu/uci/eecs/specExtraction/DefineConstruct.java b/cdsspec-compiler/src/edu/uci/eecs/specExtraction/DefineConstruct.java
new file mode 100644 (file)
index 0000000..809519e
--- /dev/null
@@ -0,0 +1,51 @@
+package edu.uci.eecs.specExtraction;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import edu.uci.eecs.specExtraction.SpecUtils.IntObj;
+import edu.uci.eecs.specExtraction.SpecUtils.Primitive;
+import edu.uci.eecs.utilParser.ParseException;
+import edu.uci.eecs.utilParser.UtilParser;
+
+/**
+ * <p>
+ * This class is a subclass of Construct. It represents user-defined code that
+ * we allow in the header file. Note that the code here basically are the same
+ * as writing code right in place. We require function declaration/definition to
+ * be inline. Users should be responsible for the correctness of their code.
+ * </p>
+ * 
+ * @author Peizhao Ou
+ * 
+ */
+public class DefineConstruct extends Construct {
+       public final Code code;
+
+       // The ending line number of the specification annotation construct
+       public final int endLineNum;
+
+       public DefineConstruct(File file, int beginLineNum, int endLineNum,
+                       ArrayList<String> annotations) throws WrongAnnotationException {
+               super(file, beginLineNum);
+               code = new Code();
+               this.endLineNum = endLineNum;
+               Primitive define = SpecUtils.extractPrimitive(file, beginLineNum,
+                               annotations, new IntObj(0));
+               code.addLines(define.contents);
+       }
+
+       public String toString() {
+               StringBuilder sb = new StringBuilder();
+               sb.append(super.toString() + "\n");
+               sb.append("@Define:\n");
+               if (!code.isEmpty()) {
+                       sb.append(code);
+                       sb.append("\n");
+               }
+               return sb.toString();
+       }
+}
diff --git a/cdsspec-compiler/src/edu/uci/eecs/specExtraction/EntryConstruct.java b/cdsspec-compiler/src/edu/uci/eecs/specExtraction/EntryConstruct.java
new file mode 100644 (file)
index 0000000..4ce90bd
--- /dev/null
@@ -0,0 +1,30 @@
+package edu.uci.eecs.specExtraction;
+
+import java.io.File;
+
+/**
+ * <p>
+ * This class is a subclass of Construct. It represents a complete entry
+ * annotation.
+ * </p>
+ * 
+ * @author Peizhao Ou
+ * 
+ */
+public class EntryConstruct extends Construct {
+
+       // The original line of text of the entry annotation
+       public final String annotation;
+
+       public EntryConstruct(File file, int beginLineNum, String annotation) {
+               super(file, beginLineNum);
+               this.annotation = annotation;
+       }
+
+       public String toString() {
+               StringBuffer res = new StringBuffer();
+               res.append(super.toString() + "\n");
+               res.append("@Entry");
+               return res.toString();
+       }
+}
diff --git a/cdsspec-compiler/src/edu/uci/eecs/specExtraction/FunctionHeader.java b/cdsspec-compiler/src/edu/uci/eecs/specExtraction/FunctionHeader.java
new file mode 100644 (file)
index 0000000..d07a0a1
--- /dev/null
@@ -0,0 +1,183 @@
+package edu.uci.eecs.specExtraction;
+
+import java.util.ArrayList;
+
+/**
+ * <p>
+ * This represents a function declaration header. For example,
+ * "void myFunction(int arg1, bool arg2)" is a function declaration header.
+ * </p>
+ * 
+ * @author Peizhao Ou
+ * 
+ */
+public class FunctionHeader {
+       private ArrayList<VariableDeclaration> templateList;
+
+       // The return type of the function
+       public final String returnType;
+       // The function name
+       public final QualifiedName funcName;
+       // The argument list (with formal parameter names)
+       public final ArrayList<VariableDeclaration> args;
+
+       // The actually function definition line in plain text.
+       // E.g. "void myFunction(int arg1, bool arg2) {"
+       private String headerLine;
+
+       public FunctionHeader(String returnType, QualifiedName qualifiedName,
+                       ArrayList<VariableDeclaration> args) {
+               this.templateList = null;
+               this.returnType = returnType;
+               this.funcName = qualifiedName;
+               this.args = args;
+       }
+
+       /**
+        * 
+        * @return Whether the return type is void
+        */
+       public boolean isReturnVoid() {
+               return returnType.equals("void");
+       }
+
+       public void setTemplateList(ArrayList<VariableDeclaration> templateList) {
+               this.templateList = templateList;
+       }
+
+       public ArrayList<VariableDeclaration> getTemplateList() {
+               return this.templateList;
+       }
+
+       public String getTemplateFullStr() {
+               String templateStr = "";
+               if (templateList == null)
+                       return templateStr;
+               VariableDeclaration decl;
+               decl = templateList.get(0);
+               templateStr = "<" + decl.type + " " + decl.name;
+               for (int i = 1; i < templateList.size(); i++) {
+                       decl = templateList.get(i);
+                       templateStr = templateStr + ", " + decl.type + " " + decl.name;
+               }
+               templateStr = templateStr + ">";
+               return templateStr;
+       }
+
+       public String getTemplateArgStr() {
+               String templateStr = null;
+               if (templateList.size() == 0)
+                       return templateStr;
+               templateStr = "<" + templateList.get(0).name;
+               for (int i = 1; i < templateList.size(); i++) {
+                       templateStr = templateStr + ", " + templateList.get(i);
+               }
+               templateStr = templateStr + ">";
+               return templateStr;
+       }
+
+       public String getFuncStr() {
+               String res = returnType + " " + funcName.fullName + "(";
+               if (args.size() >= 1) {
+                       res = res + args.get(0);
+               }
+               for (int i = 1; i < args.size(); i++) {
+                       res = res + ", " + args.get(i);
+               }
+               res = res + ")";
+               return res;
+       }
+
+       public String toString() {
+               String res = returnType + " " + funcName.fullName + "(";
+               if (args.size() >= 1) {
+                       res = res + args.get(0);
+               }
+               for (int i = 1; i < args.size(); i++) {
+                       res = res + ", " + args.get(i);
+               }
+               res = res + ")";
+               return res;
+       }
+
+       public String getRenamedFuncName() {
+               return funcName.qualifiedName + SpecNaming.WrapperPrefix + "_"
+                               + funcName.bareName;
+       }
+
+       public FunctionHeader getRenamedHeader(String prefix) {
+               String newFullName = getRenamedFuncName();
+               FunctionHeader newHeader = new FunctionHeader(returnType,
+                               new QualifiedName(newFullName), args);
+               return newHeader;
+       }
+
+       public FunctionHeader getRenamedHeader() {
+               return getRenamedHeader(SpecNaming.WrapperPrefix);
+       }
+
+       /**
+        * 
+        * @return The string that represents the renamed function header line. For
+        *         example, we would return
+        *         <code>"bool Wrapper_myFunc(int x, int y)"</code> for the fucntion
+        *         <code>"bool myFunc(int x, int y) {"</code>
+        */
+       public String getRenamedFuncLine() {
+               String bareName = this.funcName.bareName;
+               String newName = this.getRenamedFuncName();
+               return this.headerLine.replaceFirst(bareName, newName);
+       }
+
+       /**
+        * 
+        * @return The string that represents the renamed function call. For
+        *         example, we would return <code>"bool RET = myFunc(x, y)"</code>
+        *         for the fucntion <code>"bool myFunc(int x, int y)"</code>
+        */
+       public String getRenamedCall() {
+               return getRenamedCall(SpecNaming.WrapperPrefix);
+       }
+
+       /**
+        * 
+        * @return The original plain text line of the function header
+        */
+       public String getHeaderLine() {
+               return headerLine;
+       }
+       
+       
+       // No support for template right now
+       public String getDeclaration() {
+               String res = returnType + " " + funcName.fullName + "(";
+               if (args.size() >= 1) {
+                       res = res + args.get(0).type + " " + args.get(0).name;
+               }
+               for (int i = 1; i < args.size(); i++) {
+                       res = res + ", " + args.get(i).type + " " + args.get(i).name;
+               }
+               res = res + ")";
+               return res;
+       }
+
+       public String getRenamedCall(String prefix) {
+               String res = "";
+               if (!isReturnVoid()) {
+                       res = res + returnType + " " + SpecNaming.C_RET + " = ";
+               }
+               res = res + prefix + "_" + funcName.fullName + "(";
+               if (args.size() >= 1) {
+                       res = res + args.get(0).name;
+               }
+               for (int i = 1; i < args.size(); i++) {
+                       res = res + ", " + args.get(i).name;
+               }
+               res = res + ")";
+               return res;
+       }
+
+       public void setHeaderLine(String headerLine) {
+               this.headerLine = headerLine;
+       }
+}
diff --git a/cdsspec-compiler/src/edu/uci/eecs/specExtraction/GlobalConstruct.java b/cdsspec-compiler/src/edu/uci/eecs/specExtraction/GlobalConstruct.java
new file mode 100644 (file)
index 0000000..cfd935c
--- /dev/null
@@ -0,0 +1,367 @@
+package edu.uci.eecs.specExtraction;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import edu.uci.eecs.specExtraction.SpecUtils.IntObj;
+import edu.uci.eecs.specExtraction.SpecUtils.Primitive;
+
+/**
+ * <p>
+ * This class is a subclass of Construct. It represents a complete global state
+ * annotation.
+ * </p>
+ * 
+ * @author Peizhao Ou
+ * 
+ */
+public class GlobalConstruct extends Construct {
+       public final ArrayList<VariableDeclaration> declState;
+       public final Code initState;
+       public final Code copyState;
+       public final Code clearState;
+       public final Code finalState;
+       public final Code printState;
+       public final ArrayList<CommutativityRule> commutativityRules;
+
+       // Whether the state declaration is empty
+       public final boolean emptyState;
+       // Whether we have auto-gen the state initialization code
+       public final boolean autoGenInitial;
+       // Whether we have auto-gen the state copying code
+       public final boolean autoGenCopy;
+       // Whether we have auto-gen the state clearing code
+       public final boolean autoGenClear;
+       // Whether we have auto-gen the state printing code
+       public final boolean autoGenPrint;
+
+       public GlobalConstruct(File file, int beginLineNum,
+                       ArrayList<String> annotations) throws WrongAnnotationException {
+               super(file, beginLineNum);
+               declState = new ArrayList<VariableDeclaration>();
+               initState = new Code();
+               copyState = new Code();
+               clearState = new Code();
+               finalState = new Code();
+               printState = new Code();
+               commutativityRules = new ArrayList<CommutativityRule>();
+
+               processAnnotations(annotations);
+
+               emptyState = declState.isEmpty();
+               if (emptyState) {
+                       WrongAnnotationException.warning(file, beginLineNum,
+                                       "The state is empty. Make sure that's what you want!");
+                       // Add a fake state declaration
+                       declState.add(new VariableDeclaration("int", "FakeState"));
+               }
+
+               autoGenInitial = initState.isEmpty();
+               if (autoGenInitial) {
+                       Code code = generateAutoInitalFunction();
+                       initState.addLines(code);
+               }
+
+               autoGenCopy = copyState.isEmpty();
+               if (autoGenCopy) {
+                       Code code = generateAutoCopyFunction();
+                       copyState.addLines(code);
+               }
+
+               autoGenClear = clearState.isEmpty();
+               if (autoGenClear) {
+                       Code code = generateAutoClearFunction();
+                       clearState.addLines(code);
+               }
+
+               autoGenPrint = printState.isEmpty();
+               if (autoGenPrint) {
+                       Code code = generateAutoPrintFunction();
+                       printState.addLines(code);
+               }
+       }
+
+       /**
+        * <p>
+        * This function will automatically generate the initial statements for
+        * supported types if the user has not defined the "@Initial" primitive
+        * </p>
+        * 
+        * @return The auto-generated state intialization statements
+        * @throws WrongAnnotationException
+        */
+       private Code generateAutoInitalFunction() throws WrongAnnotationException {
+               Code code = new Code();
+               if (emptyState) // Empty state should have empty initial function
+                       return code;
+               for (VariableDeclaration decl : declState) {
+                       String type = decl.type;
+                       String name = decl.name;
+                       // Primitive types
+                       if (type.equals("int") || type.equals("unsigned")
+                                       || type.equals("unsigned int")
+                                       || type.equals("int unsigned") || type.equals("double")
+                                       || type.equals("double") || type.equals("bool")) {
+                               // x = 0;
+                               code.addLine(name + " = 0;");
+                       } else if (type.equals("IntList") || type.equals("IntSet")
+                                       || type.equals("IntMap")) {
+                               // Supported types
+                               // q = IntList();
+                               code.addLine(name + " = " + type + "();");
+                       } else if (type.equals("IntList *") || type.equals("IntSet *")
+                                       || type.equals("IntMap *")) {
+                               // Supported pointer types
+                               // q = new IntList;
+                               String originalType = SpecUtils.trimSpace(type
+                                               .replace('*', ' '));
+                               code.addLine(name + " = new " + originalType + "();");
+                       } else {
+                               WrongAnnotationException
+                                               .err(file,
+                                                               beginLineNum,
+                                                               "You have types in the state declaration that we do not support auto-gen initial function.");
+                       }
+               }
+
+               return code;
+       }
+
+       /**
+        * <p>
+        * This function will automatically generate the copy statements for
+        * supported types if the user has not defined the "@Copy" primitive
+        * </p>
+        * 
+        * @return The auto-generated state copy statements
+        * @throws WrongAnnotationException
+        */
+       private Code generateAutoCopyFunction() throws WrongAnnotationException {
+               Code code = new Code();
+               if (emptyState) // Empty state should have empty copy function
+                       return code;
+               for (VariableDeclaration decl : declState) {
+                       String type = decl.type;
+                       String name = decl.name;
+                       // Primitive types
+                       if (type.equals("int") || type.equals("unsigned")
+                                       || type.equals("unsigned int")
+                                       || type.equals("int unsigned") || type.equals("double")
+                                       || type.equals("double") || type.equals("bool")) {
+                               // NEW->x = OLD->x;
+                               code.addLine(SpecNaming.NewStateInst + "->" + name + " = "
+                                               + SpecNaming.OldStateInst + "->" + name + ";");
+                       } else if (type.equals("IntList") || type.equals("IntSet")
+                                       || type.equals("IntMap")) {
+                               // Supported types
+                               // New->q = IntList(OLD->q);
+                               code.addLine(SpecNaming.NewStateInst + "->" + name + " = "
+                                               + type + "(" + SpecNaming.OldStateInst + "->" + name
+                                               + ");");
+                       } else if (type.equals("IntList *") || type.equals("IntSet *")
+                                       || type.equals("IntMap *")) {
+                               // Supported pointer types
+                               // New->q = new IntList(*OLD->q);
+                               String originalType = SpecUtils.trimSpace(type
+                                               .replace('*', ' '));
+                               code.addLine(SpecNaming.NewStateInst + "->" + name + " = new "
+                                               + originalType + "(*" + SpecNaming.OldStateInst + "->"
+                                               + name + ");");
+                       } else {
+                               WrongAnnotationException
+                                               .err(file,
+                                                               beginLineNum,
+                                                               "You have types in the state declaration that we do not support auto-gen copy function.");
+                       }
+               }
+
+               return code;
+       }
+       
+       /**
+        * <p>
+        * This function will automatically generate the clear statements for
+        * supported types if the user has not defined the "@Clear" primitive
+        * </p>
+        * 
+        * @return The auto-generated state copy statements
+        * @throws WrongAnnotationException
+        */
+       private Code generateAutoClearFunction() throws WrongAnnotationException {
+               Code code = new Code();
+               if (emptyState) // Empty state should have empty copy function
+                       return code;
+               
+               // FIXME: Just try our best to generate recycling statements
+               for (VariableDeclaration decl : declState) {
+                       String type = decl.type;
+                       String name = decl.name;
+                       if (type.equals("IntList *") || type.equals("IntSet *")
+                                       || type.equals("IntMap *")) {
+                               // Supported pointer types
+                               // if (stack) delete stack;
+                               code.addLine("if (" + name + ") delete " + name + ";");
+                       }
+               }
+
+               return code;
+       }
+
+       /**
+        * <p>
+        * This function will automatically generate the printing statements for
+        * supported types if the user has not defined the "@Print" primitive
+        * </p>
+        * 
+        * @return The auto-generated state printing statements
+        * @throws WrongAnnotationException
+        */
+       private Code generateAutoPrintFunction() throws WrongAnnotationException {
+               Code code = new Code();
+               if (emptyState) // Empty state should have empty printing function
+                       return code;
+               for (VariableDeclaration decl : declState) {
+                       String type = decl.type;
+                       String name = decl.name;
+                       code.addLines(SpecUtils.generatePrintStatement(type, name));
+               }
+
+               return code;
+       }
+
+       /**
+        * <p>
+        * Assert that the global state primitive is valid; if not, throws an
+        * exception.
+        * </p>
+        * 
+        * @param file
+        *            Current file
+        * @param primitive
+        *            The primitive that we have extracted earlier
+        * @throws WrongAnnotationException
+        */
+       private void assertValidPrimitive(File file, Primitive primitive)
+                       throws WrongAnnotationException {
+               int lineNum = primitive.beginLineNum;
+               String name = primitive.name;
+               if (!name.equals(SpecNaming.DeclareState)
+                               && !name.equals(SpecNaming.InitalState)
+                               && !name.equals(SpecNaming.CopyState)
+                               && !name.equals(SpecNaming.ClearState)
+                               && !name.equals(SpecNaming.FinalState)
+                               && !name.equals(SpecNaming.Commutativity)
+                               && !name.equals(SpecNaming.PrintState)) {
+                       WrongAnnotationException.err(file, lineNum, name
+                                       + " is NOT a valid CDSSpec global state primitive.");
+               }
+       }
+
+       /**
+        * <p>
+        * Given a "@DeclareState" primitive that has a list of strings of
+        * declarations, we initialize our local "declState" members.
+        * 
+        * @param primitive
+        * @throws WrongAnnotationException
+        */
+       private void processDeclState(Primitive primitive)
+                       throws WrongAnnotationException {
+               for (int i = 0; i < primitive.contents.size(); i++) {
+                       int lineNum = i + primitive.beginLineNum;
+                       String declLine = primitive.contents.get(i);
+                       VariableDeclaration tmp = new VariableDeclaration(file, lineNum,
+                                       declLine);
+                       declState.add(tmp);
+               }
+       }
+
+       /**
+        * <p>
+        * Given a "@DeclareState" primitive that has a list of strings of
+        * declarations, we initialize our local "declState" members.
+        * 
+        * @param primitive
+        * @throws WrongAnnotationException
+        */
+       private void processCommutativity(Primitive primitive)
+                       throws WrongAnnotationException {
+               // Mathch commutativity rule
+               Pattern regexpCommute = Pattern
+                               .compile("\\s*(\\w+)\\s*<->\\s*(\\w+)\\s*\\((.*)\\)\\s*$");
+               Matcher matcherCommute = regexpCommute.matcher("");
+
+               for (int i = 0; i < primitive.contents.size(); i++) {
+                       // FIXME: Currently we only allow a one-line commutativity rule
+                       int curLineNum = primitive.beginLineNum + i;
+                       String line = primitive.contents.get(i);
+                       matcherCommute.reset(line);
+                       if (matcherCommute.find()) {
+                               String method1 = matcherCommute.group(1);
+                               String method2 = matcherCommute.group(2);
+                               String code = matcherCommute.group(3);
+                               String rule = SpecUtils.trimSpace(SpecUtils
+                                               .trimTrailingCommentSymbol(code));
+                               commutativityRules.add(new CommutativityRule(method1, method2,
+                                               rule));
+                       } else {
+                               WrongAnnotationException
+                                               .err(file,
+                                                               curLineNum,
+                                                               "The @Commutativity annotation should be: @Commutativity: Method1 <-> Method2 (condition)\n\t"
+                                                                               + "Problematic line: \"" + line + "\"");
+                       }
+                       // Done with processing the current commutativity
+               }
+       }
+
+       private void processAnnotations(ArrayList<String> annotations)
+                       throws WrongAnnotationException {
+               IntObj curIdx = new IntObj(0);
+               Primitive primitive = null;
+
+               while ((primitive = SpecUtils.extractPrimitive(file, beginLineNum,
+                               annotations, curIdx)) != null) {
+                       String name = primitive.name;
+                       assertValidPrimitive(file, primitive);
+                       if (primitive.contents.size() == 0)
+                               continue;
+                       if (name.equals(SpecNaming.DeclareState)) {
+                               processDeclState(primitive);
+                       } else if (name.equals(SpecNaming.InitalState)) {
+                               initState.addLines(primitive.contents);
+                       } else if (name.equals(SpecNaming.CopyState)) {
+                               copyState.addLines(primitive.contents);
+                       } else if (name.equals(SpecNaming.ClearState)) {
+                               clearState.addLines(primitive.contents);
+                       } else if (name.equals(SpecNaming.FinalState)) {
+                               finalState.addLines(primitive.contents);
+                       } else if (name.equals(SpecNaming.PrintState)) {
+                               printState.addLines(primitive.contents);
+                       } else if (name.equals(SpecNaming.Commutativity)) {
+                               processCommutativity(primitive);
+                       }
+               }
+       }
+
+       public String toString() {
+               StringBuilder sb = new StringBuilder("");
+               sb.append(super.toString() + "\n");
+               sb.append("@DeclareState:\n");
+               sb.append(declState);
+               sb.append("\n");
+               sb.append("@InitState:\n");
+               sb.append(initState);
+               if (!printState.isEmpty()) {
+                       sb.append("@Print:\n");
+                       sb.append(printState);
+               }
+
+               for (int i = 0; i < commutativityRules.size(); i++) {
+                       sb.append("@Commutativity: " + commutativityRules + "\n");
+               }
+               return sb.toString();
+       }
+}
diff --git a/cdsspec-compiler/src/edu/uci/eecs/specExtraction/InterfaceConstruct.java b/cdsspec-compiler/src/edu/uci/eecs/specExtraction/InterfaceConstruct.java
new file mode 100644 (file)
index 0000000..ddc2614
--- /dev/null
@@ -0,0 +1,269 @@
+package edu.uci.eecs.specExtraction;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import edu.uci.eecs.specExtraction.SpecUtils.IntObj;
+import edu.uci.eecs.specExtraction.SpecUtils.Primitive;
+import edu.uci.eecs.utilParser.ParseException;
+import edu.uci.eecs.utilParser.UtilParser;
+
+/**
+ * <p>
+ * This class is a subclass of Construct. It represents a complete interface
+ * annotation.
+ * </p>
+ * 
+ * @author Peizhao Ou
+ * 
+ */
+public class InterfaceConstruct extends Construct {
+       // The interface label of the current interface; If not specified, we use
+       // the actual interface name to represent this interface
+       private String name;
+       // Each interface interface will have an auto-generated struct that
+       // represents the return value and the arguments of that interface method
+       // call. We will mangle the interface label name to get this name in case we
+       // have other name conflict
+       private String structName;
+       public final Code preCondition;
+       public final Code justifyingPrecondition;
+       public final Code transition;
+       public final Code justifyingPostcondition;
+       public final Code postCondition;
+       public final Code print;
+
+       // The ending line number of the specification annotation construct
+       public final int endLineNum;
+
+       // The ending line number of the function definition
+       private int endLineNumFunction;
+       // The function header of the corresponding interface --- The list of
+       // variable declarations that represent the RETURN value and
+       // arguments of the interface
+       private FunctionHeader funcHeader;
+
+       public final boolean autoGenPrint;
+
+       public InterfaceConstruct(File file, int beginLineNum, int endLineNum,
+                       ArrayList<String> annotations) throws WrongAnnotationException {
+               super(file, beginLineNum);
+               this.endLineNum = endLineNum;
+               this.name = null;
+               this.structName = null;
+               this.preCondition = new Code();
+               this.justifyingPrecondition = new Code();
+               this.transition = new Code();
+               this.justifyingPostcondition = new Code();
+               this.postCondition = new Code();
+               this.print = new Code();
+
+               processAnnotations(annotations);
+
+               autoGenPrint = print.isEmpty();
+       }
+
+       public FunctionHeader getFunctionHeader() {
+               return this.funcHeader;
+       }
+
+       public boolean equals(Object other) {
+               if (!(other instanceof InterfaceConstruct)) {
+                       return false;
+               }
+               InterfaceConstruct o = (InterfaceConstruct) other;
+               if (o.name.equals(this.name))
+                       return true;
+               else
+                       return false;
+       }
+
+       public String getName() {
+               return this.name;
+       }
+
+       /**
+        * <p>
+        * This function will automatically generate the printing statements for
+        * supported types if the user has not defined the "@Print" primitive
+        * </p>
+        * 
+        * @return The auto-generated state printing statements
+        * @throws WrongAnnotationException
+        */
+       private Code generateAutoPrintFunction() {
+               Code code = new Code();
+               // For C_RET
+               code.addLines(SpecUtils.generatePrintStatement(funcHeader.returnType,
+                               SpecNaming.C_RET));
+               // For arguments
+               for (VariableDeclaration decl : funcHeader.args) {
+                       String type = decl.type;
+                       String name = decl.name;
+                       code.addLines(SpecUtils.generatePrintStatement(type, name));
+               }
+               return code;
+       }
+
+       /**
+        * <p>
+        * Assert that the interface primitive is valid; if not, throws an exception
+        * </p>
+        * 
+        * @param file
+        *            Current file
+        * @param primitive
+        *            The primitive string that we have extracted earlier
+        * @throws WrongAnnotationException
+        */
+       private void assertValidPrimitive(File file, Primitive primitive)
+                       throws WrongAnnotationException {
+               int lineNum = primitive.beginLineNum;
+               String name = primitive.name;
+               if (!name.equals(SpecNaming.Interface)
+                               && !name.equals(SpecNaming.Transition)
+                               && !name.equals(SpecNaming.PreCondition)
+                               && !name.equals(SpecNaming.JustifyingPrecondition)
+                               && !name.equals(SpecNaming.SideEffect)
+                               && !name.equals(SpecNaming.JustifyingPostcondition)
+                               && !name.equals(SpecNaming.PostCondition)
+                               && !name.equals(SpecNaming.PrintValue)) {
+                       WrongAnnotationException.err(file, lineNum, name
+                                       + " is NOT a valid CDSSpec interface primitive.");
+               }
+       }
+
+       /**
+        * <p>
+        * Assert that the "@Interface" primitive has correct syntax; if not, throws
+        * an exception. If so, it basically checks whether content of the primitive
+        * is a valid word and then return interface label name.
+        * </p>
+        * 
+        * @param file
+        *            Current file
+        * @param lineNum
+        *            Current line number
+        * @param primitive
+        *            The primitive string that we have extracted earlier
+        * @throws WrongAnnotationException
+        */
+       private String extractInterfaceName(File file, Primitive primitive)
+                       throws WrongAnnotationException {
+               int lineNum = primitive.beginLineNum;
+               String name = primitive.name;
+               if (primitive.contents.size() != 1)
+                       WrongAnnotationException.err(file, lineNum,
+                                       "The @Interface primitive: " + name + " has wrong syntax.");
+               String line = primitive.contents.get(0);
+               SpecUtils.matcherWord.reset(line);
+               if (!SpecUtils.matcherWord.find())
+                       WrongAnnotationException.err(file, lineNum, name
+                                       + " is NOT a valid CDSSpec @Interface primitive.");
+               return line;
+       }
+
+       private void processAnnotations(ArrayList<String> annotations)
+                       throws WrongAnnotationException {
+               IntObj curIdx = new IntObj(0);
+               Primitive primitive = null;
+
+               while ((primitive = SpecUtils.extractPrimitive(file, beginLineNum,
+                               annotations, curIdx)) != null) {
+                       String name = primitive.name;
+                       assertValidPrimitive(file, primitive);
+                       if (primitive.contents.size() == 0)
+                               continue;
+                       if (name.equals(SpecNaming.Interface)) {
+                               String interName = extractInterfaceName(file, primitive); 
+                               setNames(interName);
+                       } else if (name.equals(SpecNaming.Transition)) {
+                               this.transition.addLines(primitive.contents);
+                       } else if (name.equals(SpecNaming.PreCondition)) {
+                               this.preCondition.addLines(primitive.contents);
+                       } else if (name.equals(SpecNaming.JustifyingPrecondition)) {
+                               this.justifyingPrecondition.addLines(primitive.contents);
+                       } else if (name.equals(SpecNaming.JustifyingPostcondition)) {
+                               this.justifyingPostcondition.addLines(primitive.contents);
+                       } else if (name.equals(SpecNaming.PostCondition)) {
+                               this.postCondition.addLines(primitive.contents);
+                       } else if (name.equals(SpecNaming.PrintValue)) {
+                               this.print.addLines(primitive.contents);
+                       }
+               }
+       }
+
+       /**
+        * <p>
+        * This function is called to extract all the declarations that should go to
+        * the corresponding value struct --- a C++ struct to be generated for this
+        * interface that contains the information of the return value and the
+        * arguments.
+        * </p>
+        * 
+        * @param line
+        *            The line that represents the interface declaration line
+        * @throws ParseException
+        */
+       public void processFunctionDeclaration(String line) throws ParseException {
+               // FIXME: Currently we only allow the declaration to be one-liner
+               funcHeader = UtilParser.parseFuncHeader(line);
+               // Record the original declaration line
+               funcHeader.setHeaderLine(line);
+
+               // If users have not defined @Interface, we should use the function name
+               // as the interface label
+               if (name == null) {
+                       setNames(funcHeader.funcName.bareName);
+               }
+
+               // Once we have the compelte function declaration, we can auto-gen the
+               // print-out statements if it's not defined
+               if (autoGenPrint) {
+                       print.addLines(generateAutoPrintFunction());
+               }
+       }
+
+       public String toString() {
+               StringBuilder sb = new StringBuilder();
+               sb.append(super.toString() + "\n");
+               sb.append("@Interface: " + name + "\n");
+               if (!transition.isEmpty())
+                       sb.append("@Transition:\n" + transition);
+               if (!preCondition.isEmpty())
+                       sb.append("@PreCondition:\n" + preCondition);
+               if (!postCondition.isEmpty())
+                       sb.append("@PostCondition:\n" + postCondition);
+               if (!print.isEmpty())
+                       sb.append("@Print:\n" + print + "\n");
+               sb.append(funcHeader);
+
+               return sb.toString();
+       }
+
+       public int getEndLineNumFunction() {
+               return endLineNumFunction;
+       }
+
+       public void setEndLineNumFunction(int endLineNumFunction) {
+               this.endLineNumFunction = endLineNumFunction;
+       }
+
+       public String getStructName() {
+               return structName;
+       }
+
+       private void setNames(String name) {
+               this.name = name;
+               if (name == null)
+                       return;
+               structName = createStructName(name);
+       }
+       
+       static public String createStructName(String labelName) {
+               return "__struct_" + labelName + "__";
+       }
+}
diff --git a/cdsspec-compiler/src/edu/uci/eecs/specExtraction/OPConstruct.java b/cdsspec-compiler/src/edu/uci/eecs/specExtraction/OPConstruct.java
new file mode 100644 (file)
index 0000000..72b02d5
--- /dev/null
@@ -0,0 +1,51 @@
+package edu.uci.eecs.specExtraction;
+
+import java.io.File;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * <p>
+ * This class represents one complete ordering point annotation. We integrate
+ * all ordering point annotations into this class. We use the ordering point
+ * type (OPType) to differentiate each specific ordering point annotation.
+ * </p>
+ * 
+ * @author Peizhao Ou
+ * 
+ */
+public class OPConstruct extends Construct {
+       // The ordering point type
+       public final OPType type;
+       // The ordering point label --- only for OPCheck and PotentialOP; otherwise
+       // null
+       public final String label;
+       // The condition under which the current annotation will be instrumented
+       public final String condition;
+
+       // The original line of text of the entry annotation
+       public final String annotation;
+
+       public OPConstruct(File file, int beginLineNum, OPType type, String label,
+                       String condition, String annotation) {
+               super(file, beginLineNum);
+               this.type = type;
+               this.label = label;
+               // Trim the preceding and trailing spaces
+               this.condition = SpecUtils.trimSpace(condition);
+               this.annotation = annotation;
+       }
+
+       public String toString() {
+               StringBuffer res = new StringBuffer();
+               res.append(super.toString() + "\n");
+               res.append("@");
+               res.append(type);
+               if (type == OPType.PotentialOP || type == OPType.OPCheck) {
+                       res.append("(" + label + ")");
+               }
+               res.append(": ");
+               res.append(condition + "\n");
+               return res.toString();
+       }
+}
diff --git a/cdsspec-compiler/src/edu/uci/eecs/specExtraction/OPType.java b/cdsspec-compiler/src/edu/uci/eecs/specExtraction/OPType.java
new file mode 100644 (file)
index 0000000..4be1269
--- /dev/null
@@ -0,0 +1,13 @@
+package edu.uci.eecs.specExtraction;
+
+/**
+ * <p>
+ * The ordering point types.
+ * </p>
+ * 
+ * @author Peizhao Ou
+ * 
+ */
+public enum OPType {
+       OPDefine, PotentialOP, OPCheck, OPClear, OPClearDefine, OPDefineUnattached, OPClearDefineUnattached
+}
diff --git a/cdsspec-compiler/src/edu/uci/eecs/specExtraction/QualifiedName.java b/cdsspec-compiler/src/edu/uci/eecs/specExtraction/QualifiedName.java
new file mode 100644 (file)
index 0000000..2535a0d
--- /dev/null
@@ -0,0 +1,47 @@
+package edu.uci.eecs.specExtraction;
+
+/**
+ * <p>
+ * This class represents a qualified variable name in C++, e.g.
+ * Base::Mine::func. We use this class in the FunctionHeader class to represent
+ * the name of the function. However, for the sake of simplicity in usage, we
+ * only use it as a plain string with the bareName.
+ * </p>
+ * 
+ * @author Peizhao Ou
+ * 
+ */
+public class QualifiedName {
+       // The full name --- Base::Mine::func
+       public final String fullName;
+       // The bare name --- func
+       public final String bareName;
+       // The qualified name --- Base::Mine
+       public final String qualifiedName;
+
+       public QualifiedName(String fullName) {
+               this.fullName = fullName;
+               this.bareName = getBareName();
+               this.qualifiedName = getQualifiedName();
+       }
+
+       private String getBareName() {
+               int beginIdx;
+               beginIdx = fullName.lastIndexOf(':');
+               if (beginIdx == -1)
+                       return fullName;
+               else
+                       return fullName.substring(beginIdx + 1);
+       }
+
+       private String getQualifiedName() {
+               int endIdx = fullName.lastIndexOf(bareName);
+               if (endIdx == 0)
+                       return "";
+               return fullName.substring(0, endIdx);
+       }
+
+       public String toString() {
+               return fullName + "\n" + bareName;
+       }
+}
diff --git a/cdsspec-compiler/src/edu/uci/eecs/specExtraction/SpecExtractor.java b/cdsspec-compiler/src/edu/uci/eecs/specExtraction/SpecExtractor.java
new file mode 100644 (file)
index 0000000..8c47855
--- /dev/null
@@ -0,0 +1,735 @@
+package edu.uci.eecs.specExtraction;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.LineNumberReader;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import edu.uci.eecs.codeGenerator.CodeGeneratorUtils;
+import edu.uci.eecs.codeGenerator.Environment;
+import edu.uci.eecs.utilParser.ParseException;
+
+/**
+ * <p>
+ * This class represents the specification extractor of the specification. The
+ * main function of this class is to read C/C++11 source files and extract the
+ * corresponding specifications, and record corresponding information such as
+ * location, e.g., the file name and the line number, to help the code
+ * generation process.
+ * </p>
+ * 
+ * @author Peizhao Ou
+ * 
+ */
+public class SpecExtractor {
+       public final HashMap<File, ArrayList<DefineConstruct>> defineListMap;
+       public final HashMap<File, ArrayList<InterfaceConstruct>> interfaceListMap;
+       public final HashMap<File, ArrayList<OPConstruct>> OPListMap;
+       public final HashSet<String> OPLabelSet;
+       // Note that we only allow one entry per file at most
+       public final HashMap<File, EntryConstruct> entryMap;
+
+       public final HashSet<String> headerFiles;
+
+       // In the generated header file, we need to forward the user-defined
+       public final HashSet<String> forwardClass;
+
+       private GlobalConstruct globalConstruct;
+
+       public SpecExtractor() {
+               defineListMap = new HashMap<File, ArrayList<DefineConstruct>>();
+               interfaceListMap = new HashMap<File, ArrayList<InterfaceConstruct>>();
+               OPListMap = new HashMap<File, ArrayList<OPConstruct>>();
+               OPLabelSet = new HashSet<String>();
+               entryMap = new HashMap<File, EntryConstruct>();
+               headerFiles = new HashSet<String>();
+               forwardClass = new HashSet<String>();
+               globalConstruct = null;
+       }
+
+       private void addDefineConstruct(DefineConstruct construct) {
+               ArrayList<DefineConstruct> list = defineListMap.get(construct.file);
+               if (list == null) {
+                       list = new ArrayList<DefineConstruct>();
+                       defineListMap.put(construct.file, list);
+               }
+               list.add(construct);
+       }
+
+       private void addInterfaceConstruct(InterfaceConstruct construct) {
+               ArrayList<InterfaceConstruct> list = interfaceListMap
+                               .get(construct.file);
+               if (list == null) {
+                       list = new ArrayList<InterfaceConstruct>();
+                       interfaceListMap.put(construct.file, list);
+               }
+               list.add(construct);
+       }
+
+       private void addOPConstruct(OPConstruct construct) {
+               ArrayList<OPConstruct> list = OPListMap.get(construct.file);
+               if (list == null) {
+                       list = new ArrayList<OPConstruct>();
+                       OPListMap.put(construct.file, list);
+               }
+               list.add(construct);
+       }
+
+       private void addEntryConstruct(File file, EntryConstruct construct)
+                       throws WrongAnnotationException {
+               EntryConstruct old = entryMap.get(file);
+               if (old == null)
+                       entryMap.put(file, construct);
+               else { // Error processing
+                       String errMsg = "Multiple @Entry annotations in the same file.\n\t Other @Entry at Line "
+                                       + old.beginLineNum + ".";
+                       WrongAnnotationException.err(file, construct.beginLineNum, errMsg);
+               }
+       }
+
+       public GlobalConstruct getGlobalConstruct() {
+               return this.globalConstruct;
+       }
+
+       /**
+        * <p>
+        * A print out function for the purpose of debugging. Note that we better
+        * call this function after having called the checkSemantics() function to
+        * check annotation consistency.
+        * </p>
+        */
+       public void printAnnotations() {
+               System.out
+                               .println("/**********    Print out of specification extraction    **********/");
+               System.out.println("// Extracted header files");
+               for (String header : headerFiles)
+                       System.out.println(header);
+
+               System.out.println("// Global State Construct");
+               if (globalConstruct != null)
+                       System.out.println(globalConstruct);
+
+               for (File file : interfaceListMap.keySet()) {
+                       ArrayList<InterfaceConstruct> list = interfaceListMap.get(file);
+                       System.out.println("// Interface in file: " + file.getName());
+                       for (InterfaceConstruct construct : list) {
+                               System.out.println(construct);
+                               System.out.println("EndLineNumFunc: "
+                                               + construct.getEndLineNumFunction());
+                       }
+               }
+
+               for (File file : OPListMap.keySet()) {
+                       System.out.println("// Ordering points in file: " + file.getName());
+                       ArrayList<OPConstruct> list = OPListMap.get(file);
+                       for (OPConstruct construct : list)
+                               System.out.println(construct);
+               }
+
+               for (File file : entryMap.keySet()) {
+                       System.out.println("// Entry in file: " + file.getName());
+                       System.out.println(entryMap.get(file));
+               }
+       }
+
+       /**
+        * <p>
+        * Perform basic semantics checking of the extracted specification.
+        * </p>
+        * 
+        * @return
+        * @throws WrongAnnotationException
+        */
+       public void checkSemantics() throws WrongAnnotationException {
+               String errMsg = null;
+
+               // Assert that we have defined and only defined one global state
+               // annotation
+               if (globalConstruct == null) {
+                       errMsg = "Spec error: There should be one global state annotation.\n";
+                       throw new WrongAnnotationException(errMsg);
+               }
+
+               // Assert that the interface constructs have unique label name
+               HashMap<String, InterfaceConstruct> interfaceMap = new HashMap<String, InterfaceConstruct>();
+               for (File f : interfaceListMap.keySet()) {
+                       ArrayList<InterfaceConstruct> list = interfaceListMap.get(f);
+                       if (list != null) {
+                               for (InterfaceConstruct construct : list) {
+                                       InterfaceConstruct existingConstruct = interfaceMap
+                                                       .get(construct.getName());
+                                       if (existingConstruct != null) { // Error
+                                               errMsg = "Interface labels duplication with: \""
+                                                               + construct.getName() + "\" in File \""
+                                                               + existingConstruct.file.getName()
+                                                               + "\", Line " + existingConstruct.beginLineNum
+                                                               + ".";
+                                               WrongAnnotationException.err(construct.file,
+                                                               construct.beginLineNum, errMsg);
+                                       } else {
+                                               interfaceMap.put(construct.getName(), construct);
+                                       }
+                               }
+                       }
+               }
+
+               // Process ordering point labels
+               for (File file : OPListMap.keySet()) {
+                       ArrayList<OPConstruct> list = OPListMap.get(file);
+                       for (OPConstruct construct : list) {
+                               if (construct.type == OPType.OPCheck
+                                               || construct.type == OPType.PotentialOP) {
+                                       String label = construct.label;
+                                       OPLabelSet.add(label);
+                               }
+                       }
+               }
+
+       }
+
+       /**
+        * <p>
+        * This function applies on a String (a plain line of text) to check whether
+        * the current line is a C/C++ header include statement. If it is, it
+        * extracts the header file name and store it, and returns true; otherwise,
+        * it returns false.
+        * </p>
+        * 
+        * @param line
+        *            The line of text to be processed
+        * @return Returns true if the current line is a C/C++ header include
+        *         statement
+        */
+       public boolean extractHeaders(String line) {
+               // "^( |\t)*#include( |\t)+("|<)([a-zA-Z_0-9\-\.])+("|>)"
+               Pattern regexp = Pattern
+                               .compile("^( |\\t)*(#include)( |\\t)+(\"|<)([a-zA-Z_0-9\\-\\.]+)(\"|>)");
+               Matcher matcher = regexp.matcher(line);
+
+               // process the line.
+               if (matcher.find()) {
+                       String header = null;
+                       String braceSymbol = matcher.group(4);
+                       if (braceSymbol.equals("<"))
+                               header = "<" + matcher.group(5) + ">";
+                       else
+                               header = "\"" + matcher.group(5) + "\"";
+                       if (!SpecNaming.isPreIncludedHeader(header)) {
+                               headerFiles.add(header);
+                       }
+                       return true;
+               } else
+                       return false;
+       }
+
+       /**
+        * <p>
+        * A sub-routine to extract the construct from beginning till end. When
+        * called, we have already match the beginning of the construct. We will
+        * call this sub-routine when we extract the interface construct and the
+        * global state construct.
+        * </p>
+        * 
+        * <p>
+        * The side effect of this function is that the lineReader has just read the
+        * end of the construct, meaning that the caller can get the end line number
+        * by calling lineReader.getLineNumber().
+        * </p>
+        * 
+        * @param file
+        *            The file that we are processing
+        * @param lineReader
+        *            The LineNumberReader that we are using when processing the
+        *            current file.
+        * @param file
+        *            The file that we are processing
+        * @param curLine
+        *            The current line that we are processing. It should be the
+        *            beginning line of the annotation construct.
+        * @param beginLineNum
+        *            The beginning line number of the interface construct
+        *            annotation
+        * @return Returns the annotation string list of the current construct
+        * @throws WrongAnnotationException
+        */
+       private ArrayList<String> extractTillConstructEnd(File file,
+                       LineNumberReader lineReader, String curLine, int beginLineNum)
+                       throws WrongAnnotationException {
+               ArrayList<String> annotations = new ArrayList<String>();
+               annotations.add(curLine);
+               // System.out.println(curLine);
+               // Initial settings for matching lines
+               // "\*/\s*$"
+               Pattern regexpEnd = Pattern.compile("\\*/\\s*$");
+               Matcher matcher = regexpEnd.matcher(curLine);
+               if (matcher.find()) {
+                       // The beginning line is also the end line
+                       // In this case, we have already add the curLine
+                       return annotations;
+               } else {
+                       try {
+                               String line;
+                               while ((line = lineReader.readLine()) != null) {
+                                       // process the line.
+                                       // System.out.println(line);
+
+                                       matcher.reset(line); // reset the input
+                                       annotations.add(line);
+                                       if (matcher.find())
+                                               return annotations;
+                               }
+                               WrongAnnotationException
+                                               .err(file,
+                                                               beginLineNum,
+                                                               "The interface annotation should have the matching closing symbol closing \"*/\"");
+                       } catch (IOException e) {
+                               e.printStackTrace();
+                       }
+               }
+               return null;
+       }
+
+       /**
+        * <p>
+        * A sub-routine to extract the global construct. When called, we have
+        * already match the beginning of the construct.
+        * </p>
+        * 
+        * @param file
+        *            The file that we are processing
+        * @param lineReader
+        *            The LineNumberReader that we are using when processing the
+        *            current file.
+        * @param curLine
+        *            The current line that we are processing. It should be the
+        *            beginning line of the annotation construct.
+        * @param beginLineNum
+        *            The beginning line number of the interface construct
+        *            annotation
+        * @throws WrongAnnotationException
+        */
+       private void extractGlobalConstruct(File file, LineNumberReader lineReader,
+                       String curLine, int beginLineNum) throws WrongAnnotationException {
+               ArrayList<String> annotations = extractTillConstructEnd(file,
+                               lineReader, curLine, beginLineNum);
+               GlobalConstruct construct = new GlobalConstruct(file, beginLineNum,
+                               annotations);
+               if (globalConstruct != null) { // Check if we have seen a global state
+                                                                               // construct earlier
+                       File otherDefinitionFile = globalConstruct.file;
+                       int otherDefinitionLine = globalConstruct.beginLineNum;
+                       String errMsg = "Multiple definition of global state.\n"
+                                       + "\tAnother definition is in File \""
+                                       + otherDefinitionFile.getName() + "\" (Line "
+                                       + otherDefinitionLine + ").";
+                       WrongAnnotationException.err(file, beginLineNum, errMsg);
+               }
+               globalConstruct = construct;
+       }
+
+       /**
+        * @param file
+        *            The current file we are processing
+        * @param lineReader
+        *            Call this function when the lineReader will read the beginning
+        *            of the definition right away
+        * @param startingLine
+        *            The line that we should start processing
+        * @return The line number of the ending line of the interfae definition. If
+        *         returning -1, it means the curl symbols in the interface do not
+        *         match
+        * @throws WrongAnnotationException
+        */
+       private int findEndLineNumFunction(File file, LineNumberReader lineReader,
+                       String startingLine) throws WrongAnnotationException {
+               String line = startingLine;
+               // FIXME: We assume that in the string of the code, there does not exist
+               // the symbol '{' & '{'
+               try {
+                       boolean foundFirstCurl = false;
+                       int unmatchedCnt = 0;
+                       do {
+                               // process the line.
+                               // System.out.println(line);
+
+                               // Extract the one-liner construct first
+                               extractOneLineConstruct(file, lineReader.getLineNumber(), line);
+
+                               for (int i = 0; i < line.length(); i++) {
+                                       char ch = line.charAt(i);
+                                       if (ch == '{') {
+                                               foundFirstCurl = true;
+                                               unmatchedCnt++;
+                                       } else if (ch == '}') {
+                                               unmatchedCnt--;
+                                       }
+                                       // The current line is the end of the function
+                                       if (foundFirstCurl && unmatchedCnt == 0) {
+                                               int endLineNumFunction = lineReader.getLineNumber();
+                                               return endLineNumFunction;
+                                       }
+                               }
+                       } while ((line = lineReader.readLine()) != null);
+               } catch (IOException e) {
+                       e.printStackTrace();
+               }
+               // -1 means the curl symbols in the interface do not match
+               return -1;
+       }
+
+       /**
+        * <p>
+        * A sub-routine to extract the define construct. When called, we have
+        * already match the beginning of the construct, and we also need to find
+        * the ending line number of the anntotation.
+        * </p>
+        * 
+        * @param file
+        *            The file that we are processing
+        * @param lineReader
+        *            The LineNumberReader that we are using when processing the
+        *            current file.
+        * @param curLine
+        *            The current line that we are processing. It should be the
+        *            beginning line of the annotation construct.
+        * @param beginLineNum
+        *            The beginning line number of the interface construct
+        *            annotation
+        * @throws WrongAnnotationException
+        * @throws IOException
+        * @throws ParseException
+        */
+       private void extractDefineConstruct(File file, LineNumberReader lineReader,
+                       String curLine, int beginLineNum) throws WrongAnnotationException,
+                       IOException, ParseException {
+               ArrayList<String> annotations = extractTillConstructEnd(file,
+                               lineReader, curLine, beginLineNum);
+               int endLineNum = lineReader.getLineNumber();
+               DefineConstruct construct = new DefineConstruct(file, beginLineNum,
+                               endLineNum, annotations);
+               addDefineConstruct(construct);
+       }
+
+       /**
+        * <p>
+        * A sub-routine to extract the interface construct. When called, we have
+        * already match the beginning of the construct, and we also need to find
+        * the ending line number of the closing brace of the corresponding
+        * function.
+        * </p>
+        * 
+        * @param file
+        *            The file that we are processing
+        * @param lineReader
+        *            The LineNumberReader that we are using when processing the
+        *            current file.
+        * @param curLine
+        *            The current line that we are processing. It should be the
+        *            beginning line of the annotation construct.
+        * @param beginLineNum
+        *            The beginning line number of the interface construct
+        *            annotation
+        * @throws WrongAnnotationException
+        * @throws IOException
+        * @throws ParseException
+        */
+       private void extractInterfaceConstruct(File file,
+                       LineNumberReader lineReader, String curLine, int beginLineNum)
+                       throws WrongAnnotationException, IOException, ParseException {
+               ArrayList<String> annotations = extractTillConstructEnd(file,
+                               lineReader, curLine, beginLineNum);
+               int endLineNum = lineReader.getLineNumber();
+               InterfaceConstruct construct = new InterfaceConstruct(file,
+                               beginLineNum, endLineNum, annotations);
+               addInterfaceConstruct(construct);
+
+               // Process the corresponding interface function declaration header
+               String line = null;
+               int lineNum = -1;
+               String errMsg;
+               try {
+                       line = lineReader.readLine();
+                       lineNum = lineReader.getLineNumber();
+                       construct.processFunctionDeclaration(line);
+
+                       // Record those user-defined struct
+                       // RET
+                       String returnType = construct.getFunctionHeader().returnType;
+                       if (SpecUtils.isUserDefinedStruct(returnType))
+                               forwardClass.add(SpecUtils.getPlainType(returnType));
+                       // Arguments
+                       for (VariableDeclaration decl : construct.getFunctionHeader().args) {
+                               if (SpecUtils.isUserDefinedStruct(decl.type))
+                                       forwardClass.add(SpecUtils.getPlainType(decl.type));
+                       }
+
+               } catch (IOException e) {
+                       errMsg = "Spec error in file \""
+                                       + file.getName()
+                                       + "\", Line "
+                                       + lineNum
+                                       + " :\n\tThe function declaration should take only one line and have the correct syntax (follow the annotations immediately)\n";
+                       System.out.println(errMsg);
+                       throw e;
+               } catch (ParseException e) {
+                       errMsg = "Spec error in file \""
+                                       + file.getName()
+                                       + "\", Line "
+                                       + lineNum
+                                       + " :\n\tThe function declaration should take only one line and have the correct syntax (follow the annotations immediately)\n";
+                       System.out.println(errMsg);
+                       throw e;
+               }
+
+               // Now we find the end of the interface definition
+               int endLineNumFunction = findEndLineNumFunction(file, lineReader, line);
+               construct.setEndLineNumFunction(endLineNumFunction);
+               if (endLineNumFunction == -1) {
+                       WrongAnnotationException
+                                       .err(file, beginLineNum,
+                                                       "The interface definition does NOT have matching curls '}'");
+               }
+       }
+
+       /**
+        * <p>
+        * A sub-routine to extract the ordering point construct. When called, we
+        * have already match the beginning of the construct.
+        * </p>
+        * 
+        * @param file
+        *            The file that we are processing
+        * @param beginLineNum
+        *            The beginning line number of the interface construct
+        *            annotation
+        * @param curLine
+        *            The current line that we are processing. It should be the
+        *            beginning line of the annotation construct.
+        * @param type
+        *            The type of ordering point construct we are processing
+        * @throws WrongAnnotationException
+        */
+       private void extractOPConstruct(File file, int beginLineNum,
+                       String curLine, OPType type) throws WrongAnnotationException {
+               String condition = null;
+               String label = null;
+
+               // "(\(\s?(\w+)\s?\))?\s:\s?(.+)\*/\s?$"
+               Pattern regexp = Pattern
+                               .compile("(\\(\\s*(\\w+)\\s*\\))?\\s*:\\s*(.+)\\*/\\s*$");
+               Matcher matcher = regexp.matcher(curLine);
+               if (matcher.find()) {
+                       label = matcher.group(2);
+                       condition = matcher.group(3);
+               } else {
+                       WrongAnnotationException
+                                       .err(file,
+                                                       beginLineNum,
+                                                       "Wrong syntax for the ordering point construct. You might need a colon before the condition.");
+               }
+               OPConstruct op = new OPConstruct(file, beginLineNum, type, label,
+                               condition, curLine);
+               addOPConstruct(op);
+       }
+
+       /**
+        * <p>
+        * A sub-routine to extract the entry construct. When called, we have
+        * already match the beginning of the construct.
+        * </p>
+        * 
+        * @param file
+        *            The file that we are processing
+        * @param beginLineNum
+        *            The beginning line number of the interface construct
+        *            annotation
+        * @param curLine
+        *            Current line being processed
+        * @throws WrongAnnotationException
+        */
+       public void extractEntryConstruct(File file, int beginLineNum,
+                       String curLine) throws WrongAnnotationException {
+               addEntryConstruct(file, new EntryConstruct(file, beginLineNum, curLine));
+       }
+
+       /**
+        * <p>
+        * A sub-routine to extract those annotation constructs that take only one
+        * line --- Entry, OPDefine, PotentialOP, OPCheck, OPClear and OPClearDefin.
+        * </p>
+        * 
+        * @param file
+        *            The file that we are processing
+        * @param beginLineNum
+        *            The beginning line number of the interface construct
+        *            annotation
+        * @param curLine
+        *            The current line that we are processing. It should be the
+        *            beginning line of the annotation construct.
+        * @throws WrongAnnotationException
+        */
+       private void extractOneLineConstruct(File file, int beginLineNum,
+                       String curLine) throws WrongAnnotationException {
+               // "/\*\*\s*@(Entry|OPDefine|PotentialOP|OPCheck|OPClear|OPClearDefine)"
+               Pattern regexpBegin = Pattern.compile("/\\*\\*\\s*@(\\w+)");
+               Matcher matcher = regexpBegin.matcher(curLine);
+               matcher.reset(curLine);
+               if (matcher.find()) {
+                       String name = matcher.group(1);
+                       if (name.equals("Entry"))
+                               extractEntryConstruct(file, beginLineNum, curLine);
+                       else if (name.equals("OPDefine") || name.equals("PotentialOP")
+                                       || name.equals("OPCheck") || name.equals("OPClear")
+                                       || name.equals("OPClearDefine")
+                                       || name.equals("OPDefineUnattached")
+                                       || name.equals("OPClearDefineUnattached"))
+                               extractOPConstruct(file, beginLineNum, curLine,
+                                               OPType.valueOf(name));
+               }
+       }
+
+       /**
+        * <p>
+        * This function will process a given C/C++ file ( .h, .c or .cc). It will
+        * extract all the headers included in that file, and all the annotation
+        * constructs specified in that file. We then will store the information in
+        * the corresponding containers.
+        * </p>
+        * 
+        * <p>
+        * The basic idea is to read the file line by line, and then use regular
+        * expression to match the specific annotations or the header files.
+        * </p>
+        * 
+        * @param file
+        *            The file object of the corresponding file to be processed
+        * @throws WrongAnnotationException
+        * @throws ParseException
+        */
+       public void extractConstruct(File file) throws WrongAnnotationException,
+                       ParseException {
+               BufferedReader br = null;
+               LineNumberReader lineReader = null;
+               try {
+                       // Initial settings for processing the lines
+                       br = new BufferedReader(new FileReader(file));
+                       lineReader = new LineNumberReader(br);
+                       // "/\*\*\s*@(DeclareState|Interface)"
+                       Pattern regexpBegin = Pattern
+                                       .compile("/\\*\\*\\s*@(DeclareState|Interface|PreCondition|JustifyingPrecondition|Transition|JustifyingPostcondition|PostCondition|Define)");
+                       Matcher matcher = regexpBegin.matcher("");
+
+                       String line;
+                       while ((line = lineReader.readLine()) != null) {
+                               // Start to process the line
+
+                               // First try to process the line to see if it's a header file
+                               // include
+                               boolean succ = extractHeaders(line);
+                               if (succ) // It's a header line and we successfully extract it
+                                       continue;
+
+                               int beginLineNum = lineReader.getLineNumber();
+                               // Extract the one-liner construct first
+                               extractOneLineConstruct(file, beginLineNum, line);
+
+                               // Now we process the line to see if it's an annotation (State
+                               // or Interface)
+                               matcher.reset(line); // reset the input
+                               if (matcher.find()) { // Found the beginning line
+                                       // The matching annotation name
+                                       String constructName = matcher.group(1);
+
+                                       // Process each annotation accordingly
+                                       if (constructName.equals(SpecNaming.DeclareState)) {
+                                               extractGlobalConstruct(file, lineReader, line,
+                                                               beginLineNum);
+                                       } else if (constructName.equals(SpecNaming.Interface)
+                                                       || constructName.equals(SpecNaming.PreCondition)
+                                                       || constructName.equals(SpecNaming.JustifyingPrecondition)
+                                                       || constructName.equals(SpecNaming.Transition)
+                                                       || constructName.equals(SpecNaming.JustifyingPostcondition)
+                                                       || constructName.equals(SpecNaming.PostCondition)) {
+                                               extractInterfaceConstruct(file, lineReader, line,
+                                                               beginLineNum);
+                                       } else if (constructName.equals(SpecNaming.Define)) {
+                                               extractDefineConstruct(file, lineReader, line,
+                                                               beginLineNum);
+                                       } else {
+                                               WrongAnnotationException.err(file, beginLineNum,
+                                                               constructName
+                                                                               + " is not a supported annotation.");
+                                       }
+
+                               }
+                       }
+               } catch (FileNotFoundException e) {
+                       e.printStackTrace();
+               } catch (IOException e) {
+                       e.printStackTrace();
+               } finally {
+                       try {
+                               lineReader.close();
+                       } catch (IOException e) {
+                               e.printStackTrace();
+                       }
+               }
+       }
+
+       /**
+        * <p>
+        * Given a list of files, it scans each file and add found SpecConstrcut to
+        * the _constructs list.
+        * </p>
+        * 
+        * @param files
+        *            The list of files that needs to be processed. In general, this
+        *            list only need to contain those that have specification
+        *            annotations
+        * @throws WrongAnnotationException
+        * @throws ParseException
+        */
+       public void extract(File[] files) throws WrongAnnotationException,
+                       ParseException {
+               for (int i = 0; i < files.length; i++)
+                       extract(files[i]);
+
+               // Check basic specification semantics
+               checkSemantics();
+       }
+
+       public void extract(ArrayList<File> files) throws WrongAnnotationException,
+                       ParseException {
+               for (int i = 0; i < files.size(); i++)
+                       extract(files.get(i));
+
+               // Check basic specification semantics
+               checkSemantics();
+       }
+
+       /**
+        * <p>
+        * Extract the specification annotations and header files in the current
+        * file. This function should generally be called by extractFiles.
+        * </p>
+        * 
+        * @param files
+        *            The list of files that needs to be processed. In general, this
+        *            list only need to contain those that have specification
+        *            annotations
+        * @throws WrongAnnotationException
+        * @throws ParseException
+        */
+       public void extract(File file) throws WrongAnnotationException,
+                       ParseException {
+               extractConstruct(file);
+       }
+}
diff --git a/cdsspec-compiler/src/edu/uci/eecs/specExtraction/SpecNaming.java b/cdsspec-compiler/src/edu/uci/eecs/specExtraction/SpecNaming.java
new file mode 100644 (file)
index 0000000..9f1c5dd
--- /dev/null
@@ -0,0 +1,223 @@
+package edu.uci.eecs.specExtraction;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+
+/**
+ * <p>
+ * This class contains most of the constant strings that we will be using
+ * throughout the whole annotation extraction and code generation process.
+ * </p>
+ * 
+ * @author Peizhao Ou
+ * 
+ */
+public class SpecNaming {
+
+       // Specification annotation naming
+
+       // Global construct
+       public static final String DeclareState = "DeclareState";
+       public static final String InitalState = "Initial";
+       public static final String CopyState = "Copy";
+       public static final String ClearState = "Clear";
+       public static final String FinalState = "Final";
+       public static final String PrintState = "Print";
+       public static final String Commutativity = "Commutativity";
+       
+       // Define construct
+       public static final String Define = "Define";
+
+       // Interface construct
+       public static final String Interface = "Interface";
+       public static final String Transition = "Transition";
+       public static final String PreCondition = "PreCondition";
+       public static final String JustifyingPrecondition = "JustifyingPrecondition";
+       public static final String SideEffect = "SideEffect";
+       public static final String JustifyingPostcondition = "JustifyingPostcondition";
+       public static final String PostCondition = "PostCondition";
+       public static final String PrintValue = "Print";
+
+       public static final String PrintStateType = "PRINT_STATE";
+       public static final String PrintValueType = "PRINT_VALUE";
+       public static final String TransitionType = "TRANSITION";
+       public static final String PreConditionType = "PRE_CONDITION";
+       public static final String JustifyingPreconditionType = "JUSTIFYING_PRECONDITION";
+       public static final String SideEffectType = "SIDE_EFFECT";
+       public static final String JustifyingPostconditionType = "JUSTIFYING_POSTCONDITION";
+       public static final String PostConditionType = "POST_CONDITION";
+
+       // Ordering point construct
+       public static final String OPDefine = "OPDefine";
+       public static final String PotentialOP = "PotentialOP";
+       public static final String OPCheck = "OPCheck";
+       public static final String OPClear = "OPClear";
+       public static final String OPClearDefine = "OPClearDefine";
+       // Entry construct
+       public static final String Entry = "Entry";
+
+       // Generated header file name
+       public static final String CDSSpecGeneratedName = "cdsspec-generated";
+       public static final String CDSSpecGeneratedHeader = "\""
+                       + CDSSpecGeneratedName + ".h\"";
+       // Generated hedaer file comment
+       public static final String CDSSpecGeneratedHeaderComment = "This is a header file auto-generated by CDSSpec compiler; together, CDSSpec\n"
+                       + "compiler should have generated the accompanying implementation file that\n"
+                       + "implements the some functions declared in this file. In order to instrument\n"
+                       + "your benchmark for CDSSpec checker to check, you should include this header\n"
+                       + "file in every file you use an CDSSpec annotation. Note that it should be\n"
+                       + "placed in the end of all other header files. Currently we require a C++\n"
+                       + "compiler that supports C++11.";
+
+       // Generated CPP file name
+       public static final String CDSSpecGeneratedCPP = "cdsspec-generated.cc";
+       // Generated CPP file comment
+       public static final String CDSSpecGeneratedCPPComment = "This is an implementation file auto-generated by CDSSpec compiler to\n"
+                       + "instrument your benchmark for CDSSpec checker to check. Currently we require\n"
+                       + "a C++ compiler that supports C++11.";
+
+       // Pre-included header files
+       public static final HashSet<String> includedHeaders;
+       public static final ArrayList<String> includedHeadersList;
+
+       public static final String ATOMIC = "<atomic>";
+       public static final String THREADS = "<threads.h>";
+       public static final String STDATOMIC = "<stdatomic.h>";
+       public static final String STDLIB = "<stdlib.h>";
+       public static final String STDIO = "<stdio.h>";
+
+       public static final String MODELTYPES = "<modeltypes.h>";
+       public static final String CDSANNOTATE = "<cdsannotate.h>";
+       public static final String MYMEMORY = "\"mymemory.h\"";
+       public static final String MODELASSERT = "\"model-assert.h\"";
+       public static final String LIBRACE = "\"librace.h\"";
+       public static final String SPECANNOTATION = "\"specannotation.h\"";
+       public static final String SPEC_COMMON = "\"spec_common.h\"";
+       public static final String CDSSPEC = "\"cdsspec.h\"";
+       public static final String METHODCALL = "\"methodcall.h\"";
+       
+       // Header files to include in the cdsspec-generated.h
+       public static final String SPECANNOTATION_API = "\"specannotation-api.h\"";
+       
+       // Header files to include in the cdsspec-generated.cc
+       // <cdsannotate.h>
+       // "spec_common.h"
+       // "methodcall.h"
+       // "cdsspec.h"
+       // "specannotation.h"
+
+       static {
+               // Initialize the header set and list
+               includedHeaders = new HashSet<String>();
+               includedHeadersList = new ArrayList<String>();
+
+               // Add each header to the set
+               includedHeadersList.add(ATOMIC);
+               includedHeadersList.add(THREADS);
+               includedHeadersList.add(STDATOMIC);
+               includedHeadersList.add(STDLIB);
+               includedHeadersList.add(STDIO);
+
+               includedHeadersList.add(MODELTYPES);
+               includedHeadersList.add(CDSANNOTATE);
+               includedHeadersList.add(MYMEMORY);
+               includedHeadersList.add(MODELASSERT);
+               includedHeadersList.add(LIBRACE);
+               includedHeadersList.add(SPECANNOTATION);
+               includedHeadersList.add(SPEC_COMMON);
+               includedHeadersList.add(METHODCALL);
+               includedHeadersList.add(CDSSPEC);
+
+               // Add files to list
+               for (String header : includedHeadersList) {
+                       includedHeaders.add(header);
+               }
+       }
+
+       public static boolean isPreIncludedHeader(String header) {
+               return includedHeaders.contains(header)
+                               || header.equals(CDSSpecGeneratedHeader);
+       }
+
+       // Some CDSSpec keywords and function names
+       public static final String NewSize = "NEW_SIZE";
+       public static final String New = "NEW";
+       // Some CDSSpec types
+       public static final String CString = "CSTR";
+       public static final String EmptyCString = "_EMPTY";
+       public static final String NullFunc = "NULL_FUNC";
+
+       public static final String StateStruct = "StateStruct";
+       public static final String Method = "Method";
+       public static final String MethodValueField = "value";
+       public static final String CommutativityRule = "CommutativityRule";
+       public static final String StateFunctions = "StateFunctions";
+       public static final String NamedFunction = "NamedFunction";
+
+       public static final String SPEC_ANALYSIS = "SPEC_ANALYSIS";
+       // Spec annotations
+       public static final String AnnoInit = "AnnoInit";
+       public static final String AnnoTypeInit = "INIT";
+       public static final String AnnoInterfaceInfo = "AnnoInterfaceInfo";
+       public static final String CAnnoInterfaceInfo = "CAnnoInterfaceInfo";
+       public static final String SpecAnnotation = "SpecAnnotation";
+
+       // Some CDSSpec state functions
+       public static final String InitialFunc = "_Initial";
+       public static final String CopyFunc = "_Copy";
+       public static final String FinalFunc = "_Final";
+       public static final String PrintStateFunc = "_PrintState";
+
+       // Functions for instrumenting annotation
+       public static final String CreateInitAnnoFunc = "_createInitAnnotation";
+       public static final String CreateInterfaceBeginAnnoFunc = "_createInterfaceBeginAnnotation";
+       public static final String SetInterfaceBeginAnnoValueFunc = "_setInterfaceBeginAnnotationValue";
+       public static final String CreateInterfaceEndAnnoFunc = "_createInterfaceEndAnnotation";
+       public static final String CreateOPDefineAnnoFunc = "_createOPDefineAnnotation";
+       public static final String CreateOPDefineUnattachedFunc = "_createOPDefineUnattached";
+       public static final String CreateOPClearDefineUnattachedFunc = "_createOPClearDefineUnattached";
+       public static final String CreatePotentialOPAnnoFunc = "_createPotentialOPAnnotation";
+       public static final String CreateOPCheckAnnoFunc = "_createOPCheckAnnotation";
+       public static final String CreateOPClearAnnoFunc = "_createOPClearAnnotation";
+       public static final String CreateOPClearDefineAnnoFunc = "_createOPClearDefineAnnotation";
+
+       // Other CDSSpec functions
+       public static final String AddInterfaceFunctions = "addInterfaceFunctions";
+       public static final String CDSAnnotateFunc = "cdsannotate";
+       public static final String PRINT = "PRINT";
+       public static final String PrintContainer = "printContainer";
+       public static final String PrintMap = "printMap";
+
+       // Special instances
+       public static final String Method1 = "_M";
+       public static final String Method2 = "_exec";
+       public static final String StateInst = "state";
+       public static final String OldStateInst = "OLD";
+       public static final String NewStateInst = "NEW";
+       // Specification types and macros
+       public static final String C_RET = "C_RET";
+       public static final String S_RET = "S_RET";
+       public static final String InterfaceValueInst = "__value";
+       
+       // The fake ordering point operation
+       public static final String FakeOP = "_FAKE_OP_";
+       
+       // The wrapper prefix that we want to attach to the function name
+       public static final String WrapperPrefix = "Wrapper";
+
+       public static final String CommutativityRuleInst = "commuteRules";
+       public static final String CommutativityRuleSizeInst = "CommuteRuleSize";
+       public static final String StateFunctionsInst = "stateFuncs";
+       public static final String AnnoInitInst = "init";
+       public static final String AnnoInterfaceInfoInst = "info";
+
+       public static String AppendStr(String original) {
+               return "_" + original + "_str";
+       }
+
+       public static String CheckCommutativity(int ruleNum) {
+               return "_checkCommutativity" + ruleNum;
+       }
+
+}
diff --git a/cdsspec-compiler/src/edu/uci/eecs/specExtraction/SpecUtils.java b/cdsspec-compiler/src/edu/uci/eecs/specExtraction/SpecUtils.java
new file mode 100644 (file)
index 0000000..b8d0479
--- /dev/null
@@ -0,0 +1,319 @@
+package edu.uci.eecs.specExtraction;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * <p>
+ * This class contains a list of static utility functions for extracting
+ * specification annotations more conveniently.
+ * </p>
+ * 
+ * @author Peizhao Ou
+ * 
+ */
+public class SpecUtils {
+
+       /**
+        * <p>
+        * This inner class defines a primitive --- a sub-annotation. For example,
+        * the "@DeclareState" in the global state is one primitive. We record the
+        * beginning line number of that primitive, the name of the primitive and a
+        * list of lines that belong to that primitive.
+        * </p>
+        * 
+        * @author Peizhao Ou
+        * 
+        */
+       public static class Primitive {
+               public final int beginLineNum;
+               public final String name;
+               public final ArrayList<String> contents;
+
+               public Primitive(String name, int beginLineNum) {
+                       this.name = name;
+                       this.beginLineNum = beginLineNum;
+                       contents = new ArrayList<String>();
+               }
+
+               public void addLine(String line) {
+                       contents.add(line);
+               }
+
+               public String toString() {
+                       return "@" + name + ":\n" + contents;
+               }
+       };
+
+       /**
+        * <p>
+        * This is a customized wrap of integer so that we can use integer type as
+        * if they were in a C/C++ pass-by-reference fashion. It basically wraps an
+        * int primitive to allow read, write and increment its internal int value.
+        * </p>
+        * 
+        * @author Peizhao Ou
+        * 
+        */
+       public static class IntObj {
+               private int value;
+
+               public IntObj(int value) {
+                       this.value = value;
+               }
+
+               public void setVal(int value) {
+                       this.value = value;
+               }
+
+               public int getVal() {
+                       return this.value;
+               }
+
+               public void dec() {
+                       this.value--;
+               }
+
+               public void inc() {
+                       this.value++;
+               }
+
+               public String toString() {
+                       return Integer.toString(value);
+               }
+       }
+
+       // A regular expression pattern that matches "@WORD:"
+       public static final Pattern regexpPrimitive = Pattern.compile("@(\\w+):");
+       // The matcher for the primitive regular expression
+       public static final Matcher matcherPrimitive = regexpPrimitive.matcher("");
+
+       // Match code after colon: ":" + Code + "$"
+       public static final Pattern regexpCode = Pattern.compile(":(.*)$");
+       public static final Matcher matcherCode = regexpCode.matcher("");
+
+       // Match a valid word: "^\w+$"
+       public static final Pattern regexpWord = Pattern.compile("^\\w+$");
+       public static final Matcher matcherWord = regexpWord.matcher("");
+
+       /**
+        * <p>
+        * This function will look for the first line that contains a primitive from
+        * the "curIdx", and then extracts all the non-empty lines of that primitive
+        * until it gets to the end of the list or the beginning of the next
+        * primitive. It returns a list of the actual code for that primitive. When
+        * we are done with the function call, the curIdx either points to the next
+        * primitive or the end of the annotation list.
+        * </p>
+        * 
+        * @param file
+        *            The file begin processing
+        * @param beginLineNum
+        *            The beginning line number of the first annotation lines
+        * @param annotations
+        *            The list of annotations
+        * @param curIdx
+        *            The current index (the index of the line that we are
+        *            processing). We will update the current index after calling
+        *            this function. Keep in mind that this is a customized wrap of
+        *            integer so that we can use it as if it is a C/C++ reference
+        * @return The primitive starting from the curIdx till either the end of the
+        *         annotations or the beginning line of the next primitive
+        * @throws WrongAnnotationException
+        */
+       public static Primitive extractPrimitive(File file, int beginLineNum,
+                       ArrayList<String> annotations, IntObj curIdx)
+                       throws WrongAnnotationException {
+               if (curIdx.getVal() == annotations.size()) // The current index points
+                                                                                                       // to the end
+                       // of the list
+                       return null;
+
+               String line = null;
+               int curLineNum = -1;
+               Primitive primitive = null;
+               // Find the first primitive
+               for (; curIdx.getVal() < annotations.size(); curIdx.inc()) {
+                       line = annotations.get(curIdx.getVal());
+                       curLineNum = curIdx.getVal() + beginLineNum;
+                       matcherPrimitive.reset(line);
+                       if (matcherPrimitive.find()) {
+                               String name = matcherPrimitive.group(1);
+                               primitive = new Primitive(name, curLineNum);
+                               break;
+                       }
+               }
+               // Assert that we must have found one primitive
+               if (primitive == null) {
+                       WrongAnnotationException
+                                       .err(file, curLineNum,
+                                                       "Something is wrong! We must have found one primitve here!\n");
+               }
+
+               // Process the current "primitive"
+               // Deal with the first special line. E.g. @DeclareState: int x;
+               String code = null;
+               matcherCode.reset(line);
+               if (matcherCode.find()) {
+                       code = matcherCode.group(1);
+                       String trimmedCode = trimSpace(trimTrailingCommentSymbol(code));
+                       if (!trimmedCode.equals("")) {
+                               primitive.addLine(trimmedCode);
+                       }
+               } else {
+                       WrongAnnotationException
+                                       .err(file, curLineNum,
+                                                       "The state annotation should have correct primitive syntax (sub-annotations)");
+               }
+
+               // Deal with other normal line. E.g. y = 1;
+               curIdx.inc();
+               ;
+               for (; curIdx.getVal() < annotations.size(); curIdx.inc()) {
+                       curLineNum = beginLineNum + curIdx.getVal();
+                       line = annotations.get(curIdx.getVal());
+                       matcherPrimitive.reset(line);
+                       if (!matcherPrimitive.find()) {
+                               // This is another line that we should add to the result
+                               code = trimSpace(trimTrailingCommentSymbol(line));
+                               if (!code.equals(""))
+                                       primitive.addLine(code);
+                       } else
+                               // We get to the end of the current primitive
+                               break;
+               }
+
+               if (primitive.contents.size() == 0) { // The content of the primitive is
+                                                                                               // empty
+                       WrongAnnotationException.warning(file, curLineNum, "Primitive "
+                                       + primitive.name + " is empty.");
+               }
+               return primitive;
+       }
+
+       /**
+        * 
+        * @param line
+        *            The line to be processed
+        * @return The string whose beginning and ending space have been trimmed
+        */
+       public static String trimSpace(String line) {
+               // "^\s*(.*?)\s*$"
+               Pattern regexp = Pattern.compile("^\\s*(.*?)\\s*$");
+               Matcher matcher = regexp.matcher(line);
+               if (matcher.find()) {
+                       return matcher.group(1);
+               } else {
+                       return line;
+               }
+       }
+
+       /**
+        * <p>
+        * It processed the line in a way that it removes the trailing C/C++ comment
+        * symbols "STAR SLASH"
+        * </p>
+        * 
+        * @param line
+        * @return
+        */
+       public static String trimTrailingCommentSymbol(String line) {
+               Pattern regexp = Pattern.compile("(.*?)\\s*(\\*/)?\\s*$");
+               Matcher matcher = regexp.matcher(line);
+               if (matcher.find()) {
+                       return matcher.group(1);
+               } else {
+                       return null;
+               }
+       }
+
+       public static boolean isUserDefinedStruct(String type) {
+               // FIXME: We only consider the type is either a one-level pointer or a
+               // struct
+               String bareType = trimSpace(type.replace('*', ' '));
+               return !bareType.equals("int") && !bareType.matches("unsigned\\s+int")
+                               && !bareType.equals("unsigned") && !bareType.equals("bool")
+                               && !bareType.equals("double") && !bareType.equals("float")
+                               && !bareType.equals("void");
+       }
+
+       public static String getPlainType(String type) {
+               // FIXME: We only consider the type is either a one-level pointer or a
+               // struct
+               String bareType = trimSpace(type.replace('*', ' '));
+               return bareType;
+       }
+
+       /**
+        * <p>
+        * This function will automatically generate the printing statements for
+        * supported types when given a type and a name of the declaration.
+        * </p>
+        * 
+        * @return The auto-generated state printing statements
+        */
+       public static Code generatePrintStatement(String type, String name) {
+               Code code = new Code();
+               // Primitive types
+               if (type.equals("int") || type.equals("unsigned")
+                               || type.equals("unsigned int") || type.equals("int unsigned")
+                               || type.equals("double") || type.equals("double")
+                               || type.equals("bool")) {
+                       // PRINT("\tx=%d\n", x);
+                       code.addLine(SpecNaming.PRINT + "(\"\\t" + name + "=%d\\n\", "
+                                       + name + ");");
+               } else if (type.equals("int *") || type.equals("unsigned *")
+                               || type.equals("unsigned int *")
+                               || type.equals("int unsigned *") || type.equals("double *")
+                               || type.equals("double *") || type.equals("bool *")) {
+                       // Supported pointer types for primitive types
+                       // PRINT("\t*x=%d\n", *x);
+                       code.addLine(SpecNaming.PRINT + "(\"\\t*" + name + "=%d\\n\", *"
+                                       + name + ");");
+               } else if (type.equals("IntList") || type.equals("IntSet")
+                               || type.equals("IntMap")) {
+                       // Supported types
+                       // PRINT("\tq: ");
+                       // printContainer(&q);
+                       // model_print("\n");
+                       code.addLine(SpecNaming.PRINT + "(\"\\t" + name + ": \");");
+                       if (type.equals("IntMap")) {
+                               code.addLine(SpecNaming.PrintMap + "(&" + name + ");");
+                       } else {
+                               code.addLine(SpecNaming.PrintContainer + "(&" + name + ");");
+                       }
+                       code.addLine(SpecNaming.PRINT + "(\"\\n\");");
+               } else if (type.equals("IntList *") || type.equals("IntSet *")
+                               || type.equals("IntMap *")) {
+                       // Supported pointer types
+                       // PRINT("\tq: ");
+                       // printContainer(q);
+                       // model_print("\n");
+                       code.addLine(SpecNaming.PRINT + "(\"\\t" + name + ": \");");
+                       if (type.equals("IntMap *")) {
+                               code.addLine(SpecNaming.PrintMap + "(" + name + ");");
+                       } else {
+                               code.addLine(SpecNaming.PrintContainer + "(" + name + ");");
+                       }
+                       code.addLine(SpecNaming.PRINT + "(\"\\n\");");
+               } else if (type.equals("void")) {
+                       // Just do nothing!
+               } else {
+                       if (type.endsWith("*")) { // If it's an obvious pointer (with a STAR)
+                               // Weak support pointer types (just print out the address)
+                               // PRINT("\tmutex=%p\n", mutex);
+                               code.addLine(SpecNaming.PRINT + "(\"\\t" + name + "=%p\\n\", "
+                                               + name + ");");
+                       } else {
+                               code.addLine("// We do not support auto-gen print-out for type: "
+                                               + type + ".");
+                       }
+                       
+               }
+
+               return code;
+       }
+
+}
diff --git a/cdsspec-compiler/src/edu/uci/eecs/specExtraction/VariableDeclaration.java b/cdsspec-compiler/src/edu/uci/eecs/specExtraction/VariableDeclaration.java
new file mode 100644 (file)
index 0000000..259be57
--- /dev/null
@@ -0,0 +1,45 @@
+package edu.uci.eecs.specExtraction;
+
+import java.io.File;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import edu.uci.eecs.utilParser.ParseException;
+import edu.uci.eecs.utilParser.UtilParser;
+
+/**
+ * <p>
+ * This class represents a variable declaration in C/C++, in which there exist a
+ * type and a name.
+ * </p>
+ * 
+ * @author Peizhao Ou
+ * 
+ */
+public class VariableDeclaration {
+       public final String type;
+       public final String name;
+
+       public VariableDeclaration(String type, String name) {
+               this.type = SpecUtils.trimSpace(type);
+               this.name = SpecUtils.trimSpace(name);
+       }
+
+       public VariableDeclaration(File file, int lineNum, String line)
+                       throws WrongAnnotationException {
+               VariableDeclaration decl = null;
+               try {
+                       decl = UtilParser.parseDeclaration(line);
+               } catch (ParseException e) {
+                       WrongAnnotationException.err(file, lineNum, "The declaration: \""
+                               + line + "\" has wrong syntax.");
+               } finally {
+                       type = decl == null ? null : decl.type;
+                       name = decl == null ? null : decl.name;
+               }
+       }
+
+       public String toString() {
+               return type + ": " + name;
+       }
+}
diff --git a/cdsspec-compiler/src/edu/uci/eecs/specExtraction/WrongAnnotationException.java b/cdsspec-compiler/src/edu/uci/eecs/specExtraction/WrongAnnotationException.java
new file mode 100644 (file)
index 0000000..f206082
--- /dev/null
@@ -0,0 +1,66 @@
+package edu.uci.eecs.specExtraction;
+
+import java.io.File;
+
+/**
+ * <p>
+ * This class is the main error processing exception in processing the
+ * annotations.
+ * </p>
+ * 
+ * @author Peizhao Ou
+ * 
+ */
+public class WrongAnnotationException extends Exception {
+       /**
+        * 
+        */
+       private static final long serialVersionUID = 1L;
+
+       public WrongAnnotationException(String msg) {
+               super(msg);
+       }
+
+       /**
+        * <p>
+        * This is a utility function for more conveniently generating specification
+        * error exceptions. We help locate the error by the line number in the
+        * processing file, and an associated error message.
+        * </p>
+        * 
+        * @param file
+        *            The file that we see the error
+        * @param line
+        *            The associated line number of the error
+        * @param msg
+        *            The error message printout
+        * @throws WrongAnnotationException
+        */
+       public static void err(File file, int line, String msg)
+                       throws WrongAnnotationException {
+               String errMsg = "Spec error in file \"" + file.getName() + "\", Line "
+                               + line + " :\n\t" + msg + "\n";
+               throw new WrongAnnotationException(errMsg);
+       }
+
+       /**
+        * <p>
+        * This is a utility function for more conveniently generating specification
+        * warning. We help locate the warning by the line number in the processing
+        * file, and an associated warning message.
+        * </p>
+        * 
+        * @param file
+        *            The file that we see the warning
+        * @param line
+        *            The associated line number of the warning
+        * @param msg
+        *            The warning message printout
+        * @throws WrongAnnotationException
+        */
+       public static void warning(File file, int line, String msg) {
+               String errMsg = "Spec WARNING in file \"" + file.getName()
+                               + "\", Line " + line + " :\n\t" + msg + "\n";
+               System.out.println(errMsg);
+       }
+}
index 7be72d72f8e0b56fc8f333ffe25489685b053f60..62c16f45250e55a693864fd17759b9673d0220d6 100644 (file)
--- a/common.h
+++ b/common.h
@@ -9,9 +9,8 @@
 #include "config.h"
 
 extern int model_out;
-extern int switch_alloc;
 
-#define model_print(fmt, ...) do { switch_alloc = 1; dprintf(model_out, fmt, ##__VA_ARGS__); switch_alloc = 0; } while (0)
+#define model_print(fmt, ...) do { dprintf(model_out, fmt, ##__VA_ARGS__); } while (0)
 
 #ifdef CONFIG_DEBUG
 #define DEBUG(fmt, ...) do { model_print("*** %15s:%-4d %25s() *** " fmt, __FILE__, __LINE__, __func__, ##__VA_ARGS__); } while (0)
index bc068dff1fb1e559b4aafb9b01881028c28b615a..46f7e7c16ccdc0a8260760dfccc7344227aa2d68 100644 (file)
--- a/common.mk
+++ b/common.mk
@@ -8,7 +8,9 @@ UNAME := $(shell uname)
 LIB_NAME := model
 LIB_SO := lib$(LIB_NAME).so
 
-CPPFLAGS += -Wall -g -O3
+CPPFLAGS += -Wall -O3 -g
+
+CFLAGS := $(CPPFLAGS)
 
 # Mac OSX options
 ifeq ($(UNAME), Darwin)
index 2a7e0dadd1e0918ac21b5f43dd4e3608935b8f18..eaf245dd17216169f5fd2cb9818b37a76ba6ea4f 100644 (file)
@@ -34,7 +34,6 @@ struct model_snapshot_members {
                too_many_reads(false),
                no_valid_reads(false),
                bad_synchronization(false),
-               bad_sc_read(false),
                asserted(false)
        { }
 
@@ -54,7 +53,6 @@ struct model_snapshot_members {
        bool no_valid_reads;
        /** @brief Incorrectly-ordered synchronization was made */
        bool bad_synchronization;
-       bool bad_sc_read;
        bool asserted;
 
        SNAPSHOTALLOC
@@ -204,13 +202,6 @@ void ModelExecution::set_bad_synchronization()
        priv->bad_synchronization = true;
 }
 
-/** @brief Alert the model-checker that an incorrectly-ordered
- * synchronization was made */
-void ModelExecution::set_bad_sc_read()
-{
-       priv->bad_sc_read = true;
-}
-
 bool ModelExecution::assert_bug(const char *msg)
 {
        priv->bugs.push_back(new bug_message(msg));
@@ -1315,12 +1306,6 @@ ModelAction * ModelExecution::check_current_action(ModelAction *curr)
                                if (rf) {
                                        if (r_modification_order(act, rf))
                                                updated = true;
-                                       if (act->is_seqcst()) {
-                                               ModelAction *last_sc_write = get_last_seq_cst_write(act);
-                                               if (last_sc_write != NULL && rf->happens_before(last_sc_write)) {
-                                                       set_bad_sc_read();
-                                               }
-                                       }
                                } else if (promise) {
                                        if (r_modification_order(act, promise))
                                                updated = true;
@@ -1400,8 +1385,6 @@ void ModelExecution::print_infeasibility(const char *prefix) const
                ptr += sprintf(ptr, "[no valid reads-from]");
        if (priv->bad_synchronization)
                ptr += sprintf(ptr, "[bad sw ordering]");
-       if (priv->bad_sc_read)
-               ptr += sprintf(ptr, "[bad sc read]");
        if (promises_expired())
                ptr += sprintf(ptr, "[promise expired]");
        if (promises.size() != 0)
@@ -1432,7 +1415,6 @@ bool ModelExecution::is_infeasible() const
                priv->no_valid_reads ||
                priv->too_many_reads ||
                priv->bad_synchronization ||
-               priv->bad_sc_read ||
                priv->hard_failed_promise ||
                promises_expired();
 }
@@ -1601,6 +1583,9 @@ bool ModelExecution::r_modification_order(ModelAction *curr, const rf_type *rf)
                action_list_t::reverse_iterator rit;
                for (rit = list->rbegin(); rit != list->rend(); rit++) {
                        ModelAction *act = *rit;
+                       // FIXME: The read from promise might read from an annotation
+                       if (act->get_type() == ATOMIC_ANNOTATION)
+                               continue;
 
                        /* Skip curr */
                        if (act == curr)
@@ -1634,6 +1619,12 @@ bool ModelExecution::r_modification_order(ModelAction *curr, const rf_type *rf)
                                }
                        }
 
+                       /* C++, Section 29.3 statement 3 (second subpoint) */
+                       if (curr->is_seqcst() && last_sc_write && act == last_sc_write) {
+                               added = mo_graph->addEdge(act, rf) || added;
+                               break;
+                       }
+
                        /*
                         * Include at most one act per-thread that "happens
                         * before" curr
@@ -1765,10 +1756,9 @@ bool ModelExecution::w_modification_order(ModelAction *curr, ModelVector<ModelAc
                                        added = mo_graph->addEdge(act, curr) || added;
                                else if (act->is_read()) {
                                        //if previous read accessed a null, just keep going
-                                       if (act->get_reads_from() == NULL) {
-                                               added = mo_graph->addEdge(act->get_reads_from_promise(), curr) || added;
-                                       } else
-                                               added = mo_graph->addEdge(act->get_reads_from(), curr) || added;
+                                       if (act->get_reads_from() == NULL)
+                                               continue;
+                                       added = mo_graph->addEdge(act->get_reads_from(), curr) || added;
                                }
                                break;
                        } else if (act->is_read() && !act->could_synchronize_with(curr) &&
index 9322f55b4c3e0de4ab37502e328d812bf479be68..fd117abf3970c8f6e3aa49e0a08ccc7120be520d 100644 (file)
@@ -117,11 +117,11 @@ public:
        action_list_t * get_action_trace() { return &action_trace; }
 
        CycleGraph * const get_mo_graph() { return mo_graph; }
+       
+       int get_execution_number() const;
 
        SNAPSHOTALLOC
 private:
-       int get_execution_number() const;
-
        ModelChecker *model;
 
        const model_params * const params;
@@ -134,7 +134,6 @@ private:
        bool mo_may_allow(const ModelAction *writer, const ModelAction *reader);
        bool promises_may_allow(const ModelAction *writer, const ModelAction *reader) const;
        void set_bad_synchronization();
-       void set_bad_sc_read();
        bool promises_expired() const;
        bool should_wake_up(const ModelAction *curr, const Thread *thread) const;
        void wake_up_sleeping_actions(ModelAction *curr);
index 4b5d1c28941246fe1c0a1e2dc1567e4bac22a81e..2d48989c147d051bd61d3a4d01fe0e2ba1bcf9ea 100644 (file)
@@ -26,15 +26,11 @@ void atomic_flag_clear_explicit
 void atomic_flag_clear( volatile atomic_flag* __a__ )
 { atomic_flag_clear_explicit( __a__, memory_order_seq_cst ); }
 
-void __atomic_flag_wait__( volatile atomic_flag* __a__ ) { 
-       while ( atomic_flag_test_and_set( __a__ ) )
-               ; 
-}
+void __atomic_flag_wait__( volatile atomic_flag* __a__ )
+{ while ( atomic_flag_test_and_set( __a__ ) ); }
 
 void __atomic_flag_wait_explicit__( volatile atomic_flag* __a__,
-                                    memory_order __x__ ) {
-       while ( atomic_flag_test_and_set_explicit( __a__, __x__ ))
-               ;
-}
+                                    memory_order __x__ )
+{ while ( atomic_flag_test_and_set_explicit( __a__, __x__ ) ); }
 
 }
index bb6e3d6e469c4b04b24015573bbca836d387b44c..b58486d676454f10ced09add01e206f54c82a419 100644 (file)
@@ -2,6 +2,13 @@
 #define CDS_ANNOTATE_H
 #include <stdint.h>
 
+//#ifdef __cplusplus
+//extern "C" {
+//#endif
 void cdsannotate(uint64_t analysistype, void *annotation);
+//#ifdef __cplusplus
+//}
+//#endif
+
 
 #endif
index b4273eee4a5984ce47c3b0ae922700fcad1f9e11..1b9ce6be97f9efdb23debaaa87c820406a65ccf2 100644 (file)
@@ -2330,28 +2330,23 @@ inline bool atomic_compare_exchange_strong
 inline void* atomic_fetch_add_explicit
 ( volatile atomic_address* __a__, ptrdiff_t __m__, memory_order __x__ )
 {
-       volatile __typeof__((__a__)->__f__)* __p__ = & ((__a__)->__f__);
-       __typeof__((__a__)->__f__) __old__=(__typeof__((__a__)->__f__)) model_rmwr_action((void *)__p__, __x__);
-       __typeof__((__a__)->__f__) __copy__= __old__;
-       __copy__ = (void *) (((char *)__copy__) + __m__);
-       model_rmw_action((void *)__p__, __x__, (uint64_t) __copy__);
-       return __old__;
-}
+       void* volatile* __p__ = &((__a__)->__f__);
+       void* __r__ = (void *) model_rmwr_action((void *)__p__, __x__);
+       model_rmw_action((void *)__p__, __x__, (uint64_t) ((char*)(*__p__) + __m__));
+  return __r__; }
 
- inline void* atomic_fetch_add
+inline void* atomic_fetch_add
 ( volatile atomic_address* __a__, ptrdiff_t __m__ )
 { return atomic_fetch_add_explicit( __a__, __m__, memory_order_seq_cst ); }
 
 
 inline void* atomic_fetch_sub_explicit
 ( volatile atomic_address* __a__, ptrdiff_t __m__, memory_order __x__ )
-{      volatile __typeof__((__a__)->__f__)* __p__ = & ((__a__)->__f__);
-       __typeof__((__a__)->__f__) __old__=(__typeof__((__a__)->__f__)) model_rmwr_action((void *)__p__, __x__);
-       __typeof__((__a__)->__f__) __copy__= __old__;
-       __copy__ = (void *) (((char *)__copy__) - __m__);
-       model_rmw_action((void *)__p__, __x__, (uint64_t) __copy__);
-       return __old__;
-}
+{
+       void* volatile* __p__ = &((__a__)->__f__);
+       void* __r__ = (void *) model_rmwr_action((void *)__p__, __x__);
+       model_rmw_action((void *)__p__, __x__, (uint64_t)((char*)(*__p__) - __m__));
+  return __r__; }
 
 inline void* atomic_fetch_sub
 ( volatile atomic_address* __a__, ptrdiff_t __m__ )
diff --git a/include/model_memory.h b/include/model_memory.h
new file mode 100644 (file)
index 0000000..bb5a001
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef _MODEL_MEMORY_H
+#define _MODEL_MEMORY_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void* snapshot_malloc(size_t size);
+void* snapshot_calloc(size_t count, size_t size);
+void snapshot_free(void *ptr);
+
+#define MODEL_MALLOC(x) snapshot_malloc((x))
+#define MODEL_CALLOC(x, y) snapshot_calloc((x), (y))
+#define MODEL_FREE(x) snapshot_free((x))
+
+#define CMODEL_MALLOC(x) snapshot_malloc((x))
+#define CMODEL_CALLOC(x, y) snapshot_calloc((x), (y))
+#define CMODEL_FREE(x) snapshot_free((x))
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+
+#endif
index d4d21984ea8a1ea37f5db767a1deffca56a05c21..a5038ffe8bd947391b2489311d0025ae45d572a6 100644 (file)
@@ -56,6 +56,38 @@ using std::atomic_ullong;
 using std::atomic_wchar_t;
 
 
+/****** More atomic types *****/
+using std::atomic_int_least8_t;
+using std::atomic_uint_least8_t;
+using std::atomic_int_least16_t;
+using std::atomic_uint_least16_t;
+using std::atomic_int_least32_t;
+using std::atomic_uint_least32_t;
+using std::atomic_int_least64_t;
+using std::atomic_uint_least64_t;
+
+using std::atomic_int_fast8_t;
+using std::atomic_uint_fast8_t;
+using std::atomic_int_fast16_t;
+using std::atomic_uint_fast16_t;
+using std::atomic_int_fast32_t;
+using std::atomic_uint_fast32_t;
+using std::atomic_int_fast64_t;
+using std::atomic_uint_fast64_t;
+
+using std::atomic_intptr_t;
+using std::atomic_uintptr_t;
+
+using std::atomic_ssize_t;
+using std::atomic_size_t;
+
+using std::atomic_ptrdiff_t;
+
+using std::atomic_intmax_t;
+using std::atomic_uintmax_t;
+
+
+
 using std::atomic;
 using std::memory_order;
 using std::memory_order_relaxed;
diff --git a/main.cc b/main.cc
index 502f499eff9cb2de956256bb6f24b84080e600e0..127ffd160ff8df930d30500b1944ec2a9b107b00 100644 (file)
--- a/main.cc
+++ b/main.cc
@@ -141,9 +141,9 @@ static void parse_options(struct model_params *params, int argc, char **argv)
                {"enabled", required_argument, NULL, 'e'},
                {"bound", required_argument, NULL, 'b'},
                {"verbose", optional_argument, NULL, 'v'},
-               {"uninitialized", required_argument, NULL, 'u'},
-               {"analysis", required_argument, NULL, 't'},
-               {"options", required_argument, NULL, 'o'},
+               {"uninitialized", optional_argument, NULL, 'u'},
+               {"analysis", optional_argument, NULL, 't'},
+               {"options", optional_argument, NULL, 'o'},
                {"maxexecutions", required_argument, NULL, 'x'},
                {0, 0, 0, 0} /* Terminator */
        };
@@ -231,8 +231,6 @@ static void install_trace_analyses(ModelExecution *execution)
                TraceAnalysis * ta=(*installedanalysis)[i];
                ta->setExecution(execution);
                model->add_trace_analysis(ta);
-               /** Call the installation event for each installed plugin */
-               ta->actionAtInstallation();
        }
 }
 
@@ -270,18 +268,6 @@ int main(int argc, char **argv)
        main_argc = argc;
        main_argv = argv;
 
-       /*
-        * If this printf statement is removed, CDSChecker will fail on an
-        * assert on some versions of glibc.  The first time printf is
-        * called, it allocated internal buffers.  We can't easily snapshot
-        * libc since we also use it.
-        */
-
-       printf("CDSChecker\n"
-                                "Copyright (c) 2013 Regents of the University of California. All rights reserved.\n"
-                                "Distributed under the GPLv2\n"
-                                "Written by Brian Norris and Brian Demsky\n\n");
-
        /* Configure output redirection for the model-checker */
        redirect_output();
 
index 3bac9039b4822475bb0226adcf4fd85cc8008ea1..8f0efcddd5e8f3ccfa027a7554f6a3d437c51f72 100644 (file)
--- a/model.cc
+++ b/model.cc
@@ -2,7 +2,6 @@
 #include <algorithm>
 #include <new>
 #include <stdarg.h>
-#include <string.h>
 
 #include "model.h"
 #include "action.h"
@@ -23,18 +22,14 @@ ModelChecker *model;
 ModelChecker::ModelChecker(struct model_params params) :
        /* Initialize default scheduler */
        params(params),
-       restart_flag(false),
-       exit_flag(false),
        scheduler(new Scheduler()),
        node_stack(new NodeStack()),
        execution(new ModelExecution(this, &this->params, scheduler, node_stack)),
        execution_number(1),
        diverge(NULL),
        earliest_diverge(NULL),
-       trace_analyses(),
-       inspect_plugin(NULL)
+       trace_analyses()
 {
-       memset(&stats,0,sizeof(struct execution_stats));
 }
 
 /** @brief Destructor */
@@ -303,9 +298,6 @@ bool ModelChecker::next_execution()
 
                checkDataRaces();
                run_trace_analyses();
-       } else if (inspect_plugin && !execution->is_complete_execution() &&
-               (execution->too_many_steps())) {
-                inspect_plugin->analyze(execution->get_action_trace());
        }
 
        record_stats();
@@ -319,14 +311,6 @@ bool ModelChecker::next_execution()
        if (complete)
                earliest_diverge = NULL;
 
-       if (restart_flag) {
-               do_restart();
-               return true;
-       }
-
-       if (exit_flag)
-               return false;
-
        if ((diverge = execution->get_next_backtrack()) == NULL)
                return false;
 
@@ -346,8 +330,10 @@ bool ModelChecker::next_execution()
 
 /** @brief Run trace analyses on complete trace */
 void ModelChecker::run_trace_analyses() {
+       IN_TRACE_ANALYSIS = true;
        for (unsigned int i = 0; i < trace_analyses.size(); i++)
                trace_analyses[i]->analyze(execution->get_action_trace());
+       IN_TRACE_ANALYSIS = false;
 }
 
 /**
@@ -400,9 +386,6 @@ uint64_t ModelChecker::switch_to_master(ModelAction *act)
        Thread *old = thread_current();
        scheduler->set_current_thread(NULL);
        ASSERT(!old->get_pending());
-       if (inspect_plugin != NULL) {
-               inspect_plugin->inspectModelAction(act);
-       }
        old->set_pending(act);
        if (Thread::swap(old, &system_context) < 0) {
                perror("swap threads");
@@ -432,35 +415,9 @@ bool ModelChecker::should_terminate_execution()
        return false;
 }
 
-/** @brief Exit ModelChecker upon returning to the run loop of the
- *     model checker. */
-void ModelChecker::exit_model_checker()
-{
-       exit_flag = true;
-}
-
-/** @brief Restart ModelChecker upon returning to the run loop of the
- *     model checker. */
-void ModelChecker::restart()
-{
-       restart_flag = true;
-}
-
-void ModelChecker::do_restart()
-{
-       restart_flag = false;
-       diverge = NULL;
-       earliest_diverge = NULL;
-       reset_to_initial_state();
-       node_stack->full_reset();
-       memset(&stats,0,sizeof(struct execution_stats));
-       execution_number = 1;
-}
-
 /** @brief Run ModelChecker for the user program */
 void ModelChecker::run()
 {
-       bool has_next;
        do {
                thrd_t user_thread;
                Thread *t = new Thread(execution->get_next_id(), &user_thread, &user_main_wrapper, NULL, NULL);
@@ -508,17 +465,7 @@ void ModelChecker::run()
                        t = execution->take_step(curr);
                } while (!should_terminate_execution());
 
-               has_next = next_execution();
-               if (inspect_plugin != NULL && !has_next) {
-                       inspect_plugin->actionAtModelCheckingFinish();
-                       // Check if the inpect plugin set the restart flag
-                       if (restart_flag) {
-                               model_print("******* Model-checking RESTART: *******\n");
-                               has_next = true;
-                               do_restart();
-                       }
-               }
-       } while (has_next);
+       } while (next_execution());
 
        execution->fixup_release_sequences();
 
diff --git a/model.h b/model.h
index 94483536cf4e7468346417c7d7ad87887ecaac9e..74cb4e1f29aaf2c649fce027fc9dd10c714eb562 100644 (file)
--- a/model.h
+++ b/model.h
@@ -47,15 +47,6 @@ public:
 
        void run();
 
-       /** Restart the model checker, intended for pluggins. */
-       void restart();
-
-       /** Exit the model checker, intended for pluggins. */
-       void exit_model_checker();
-
-       /** Check the exit_flag. */
-       bool get_exit_flag() const { return exit_flag; }
-
        /** @returns the context for the main model-checking system thread */
        ucontext_t * get_system_context() { return &system_context; }
 
@@ -75,15 +66,12 @@ public:
        void assert_user_bug(const char *msg);
 
        const model_params params;
-       void add_trace_analysis(TraceAnalysis *a) {     trace_analyses.push_back(a); }
-       void set_inspect_plugin(TraceAnalysis *a) {     inspect_plugin=a;       }
+       void add_trace_analysis(TraceAnalysis *a) {
+               trace_analyses.push_back(a);
+       }
+
        MEMALLOC
 private:
-       /** Flag indicates whether to restart the model checker. */
-       bool restart_flag;
-       /** Flag indicates whether to exit the model checker. */
-       bool exit_flag;
-
        /** The scheduler to use: tracks the running/ready Threads */
        Scheduler * const scheduler;
        NodeStack * const node_stack;
@@ -109,10 +97,6 @@ private:
 
        ModelVector<TraceAnalysis *> trace_analyses;
 
-       /** @bref Implement restart. */
-       void do_restart();
-       /** @bref Plugin that can inspect new actions. */
-       TraceAnalysis *inspect_plugin;
        /** @brief The cumulative execution stats */
        struct execution_stats stats;
        void record_stats();
index e8ec08050f5d8e5389c01e136fe1c0a27f374f13..8bb5b46900e42b7071df9bcb18e35f9a3b38225d 100644 (file)
 
 #define REQUESTS_BEFORE_ALLOC 1024
 
+bool IN_TRACE_ANALYSIS = false;
+
 size_t allocatedReqs[REQUESTS_BEFORE_ALLOC] = { 0 };
 int nextRequest = 0;
 int howManyFreed = 0;
-int switch_alloc = 0;
 #if !USE_MPROTECT_SNAPSHOT
 static mspace sStaticSpace = NULL;
 #endif
@@ -125,7 +126,7 @@ void model_free(void *ptr)
 /** Bootstrap allocation. Problem is that the dynamic linker calls require
  *  calloc to work and calloc requires the dynamic linker to work. */
 
-#define BOOTSTRAPBYTES 131072
+#define BOOTSTRAPBYTES 4096
 char bootstrapmemory[BOOTSTRAPBYTES];
 size_t offset = 0;
 
@@ -135,7 +136,7 @@ void * HandleEarlyAllocationRequest(size_t sz)
        sz = (sz + 7) & ~7;
 
        if (sz > (BOOTSTRAPBYTES-offset)) {
-               model_print("OUT OF BOOTSTRAP MEMORY.  Increase the size of BOOTSTRAPBYTES in mymemory.cc\n");
+               model_print("OUT OF BOOTSTRAP MEMORY\n");
                exit(EXIT_FAILURE);
        }
 
@@ -180,11 +181,8 @@ static void * user_malloc(size_t size)
 void *malloc(size_t size)
 {
        if (user_snapshot_space) {
-               if (switch_alloc) {
-                       return model_malloc(size);
-               }
                /* Only perform user allocations from user context */
-               ASSERT(!model || thread_current());
+               ASSERT(!model || thread_current() || IN_TRACE_ANALYSIS);
                return user_malloc(size);
        } else
                return HandleEarlyAllocationRequest(size);
@@ -193,12 +191,8 @@ void *malloc(size_t size)
 /** @brief Snapshotting free implementation for user programs */
 void free(void * ptr)
 {
-       if (!DontFree(ptr)) {
-               if (switch_alloc) {
-                       return model_free(ptr);
-               }
+       if (!DontFree(ptr))
                mspace_free(user_snapshot_space, ptr);
-       }
 }
 
 /** @brief Snapshotting realloc implementation for user programs */
index a62ab83b9ce5cbcd82999bc9463b2949ba7a0394..461f7d1e9c0c9293fc0f60f7541b1fa392a222d3 100644 (file)
                return p; \
        }
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern bool IN_TRACE_ANALYSIS;
+
 void *model_malloc(size_t size);
 void *model_calloc(size_t count, size_t size);
 void model_free(void *ptr);
 
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
 void * snapshot_malloc(size_t size);
 void * snapshot_calloc(size_t count, size_t size);
 void * snapshot_realloc(void *ptr, size_t size);
 void snapshot_free(void *ptr);
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
 
 void * Thread_malloc(size_t size);
 void Thread_free(void *ptr);
index bacd067dcb4b8277408e2efd5685fc27bac8e2da..e5f46875649ab9bac345728ee3ef8eabd061015d 100644 (file)
@@ -838,16 +838,6 @@ void NodeStack::pop_restofstack(int numAhead)
        node_list.back()->clear_backtracking();
 }
 
-/** Reset the node stack. */
-void NodeStack::full_reset() 
-{
-       for (unsigned int i = 0; i < node_list.size(); i++)
-               delete node_list[i];
-       node_list.clear();
-       reset_execution();
-       total_nodes = 1;
-}
-
 Node * NodeStack::get_head() const
 {
        if (node_list.empty() || head_idx < 0)
index 6ae96be8d508d9b598ae3bb3c396760fea6047da..f26100bad0e359459bf18263009028aa8a28f4e0 100644 (file)
@@ -198,7 +198,6 @@ public:
        Node * get_next() const;
        void reset_execution();
        void pop_restofstack(int numAhead);
-       void full_reset();
        int get_total_nodes() { return total_nodes; }
 
        void print() const;
index d5fd1cb3e0b6ff23815015bad429282d6f08bab5..c5b617bc7d64222617d10d0091b45f923bdaf806 100644 (file)
--- a/params.h
+++ b/params.h
@@ -14,7 +14,7 @@ struct model_params {
        unsigned int enabledcount;
        unsigned int bound;
        unsigned int uninitvalue;
-       int maxexecutions;
+       unsigned int maxexecutions;
 
        /** @brief Maximum number of future values that can be sent to the same
         *  read */
index 38493debc400ab95edb7d7a82f64eda055e0d2c3..f3852bb9469e62ba31c251b0b005d71801615a78 100644 (file)
@@ -1,6 +1,6 @@
 #include "plugins.h"
 #include "scanalysis.h"
-#include "scfence.h"
+#include "specanalysis.h"
 
 ModelVector<TraceAnalysis *> * registered_analysis;
 ModelVector<TraceAnalysis *> * installed_analysis;
@@ -9,7 +9,7 @@ void register_plugins() {
        registered_analysis=new ModelVector<TraceAnalysis *>();
        installed_analysis=new ModelVector<TraceAnalysis *>();
        registered_analysis->push_back(new SCAnalysis());
-       registered_analysis->push_back(new SCFence());
+       registered_analysis->push_back(new SPECAnalysis());
 }
 
 ModelVector<TraceAnalysis *> * getRegisteredTraceAnalysis() {
index 130dc3b16dfc83f09bc563a4a97089d7b82c5ac4..63408cbf1c06c4fe96fab70961930b01eba4c914 100644 (file)
@@ -35,7 +35,7 @@ void SCFence::setExecution(ModelExecution * execution) {
 }
 
 const char * SCFence::name() {
-       const char * name = "AUTOMO";
+       const char * name = "SCFENCE";
        return name;
 }
 
diff --git a/spec-analysis/.gitignore b/spec-analysis/.gitignore
new file mode 100644 (file)
index 0000000..e3b3c9f
--- /dev/null
@@ -0,0 +1,12 @@
+# generic types
+*.o
+*.swp
+*.swo
+*.so
+*~
+*.dot
+.*.d
+*.pdf
+
+# files in this directory
+/tags
diff --git a/spec-analysis/Makefile b/spec-analysis/Makefile
new file mode 100644 (file)
index 0000000..02c24e9
--- /dev/null
@@ -0,0 +1,7 @@
+# This make file is to be added by the Makefile at the main directory
+
+LOCAL_OBJS := specanalysis.o executiongraph.o specannotation.o methodcall.o
+
+SPEC_OBJS := $(LOCAL_OBJS:%=$(SPEC_DIR)/%)
+
+OBJECTS += $(SPEC_OBJS)
diff --git a/spec-analysis/cdsspec.h b/spec-analysis/cdsspec.h
new file mode 100644 (file)
index 0000000..db06189
--- /dev/null
@@ -0,0 +1,376 @@
+#ifndef _CDSSPEC_H
+#define _CDSSPEC_H
+
+#include <vector>
+#include <list>
+#include <string>
+#include <iterator>
+#include <algorithm>
+#include <set>
+#include <unordered_map>
+
+#include <functional>
+
+#include <stdarg.h>
+
+#include "mymemory.h"
+//#include "common.h"
+#include "methodcall.h"
+
+using namespace std;
+
+/** Macro for output (stole from common.h) */
+extern int model_out;
+#define PRINT(fmt, ...) do { dprintf(model_out, fmt, ##__VA_ARGS__); } while (0)
+
+/**
+       A special kind of integer that has been embedded with a universal tag (ID)
+*/
+typedef struct TagInt {
+       unsigned int tag;
+       int val;
+
+       TagInt(unsigned int tag, int val) : tag(tag), val(val) { }
+       
+       TagInt(int val) : tag(0), val(val) { }
+}TagInt;
+
+typedef SnapVector<int> IntVector;
+typedef SnapList<int> IntList;
+typedef SnapSet<int> IntSet;
+
+template<typename Key, typename Value>
+class Map: public unordered_map<Key, Value> {
+       public:
+       typedef unordered_map<Key, Value> map;
+
+       Map() : map() { }
+
+       Value get(Key key) {
+               return (*this)[key];
+       }
+
+       void put(Key key, Value value) {
+               (*this)[key] = value;
+       }
+
+       SNAPSHOTALLOC
+};
+
+class IntMap : public unordered_map<int, int> {
+       public:
+       typedef unordered_map<int, int> map;
+
+       IntMap() : map() { }
+
+       int get(int key) {
+               return (*this)[key];
+       }
+
+       void put(int key, int value) {
+               (*this)[key] = value;
+       }
+
+       SNAPSHOTALLOC
+};
+
+typedef SnapVector<double> DoubleVector;
+typedef SnapList<double> DoubleList;
+typedef SnapSet<double> DoubleSet;
+
+/********** Debugging functions **********/
+template<class Container>
+inline void printContainer(Container *container) {
+       if (!container || container->size() == 0)
+               PRINT("EMPTY");
+       for (auto it = container->begin(); it != container->end(); it++) {
+               int item = *it;
+               PRINT("%d ", item);
+       }
+}
+
+inline void printMap(IntMap *container) {
+       if (!container || container->size() == 0)
+               PRINT("EMPTY");
+       for (auto it = container->begin(); it != container->end(); it++) {
+               pair<int, int> item = *it;
+               PRINT("(%d, %d) ", item.first, item.second);
+       }
+}
+
+/********** More general specification-related types and operations **********/
+
+#define NewMethodSet new SnapSet<Method>
+
+#define CAT(a, b) CAT_HELPER(a, b) /* Concatenate two symbols for macros! */
+#define CAT_HELPER(a, b) a ## b
+#define X(name) CAT(__##name, __LINE__) /* unique variable */
+
+/**
+       This is a generic ForEach primitive for all the containers that support
+       using iterator to iterate.
+*/
+#define ForEach(item, container) \
+       auto X(_container) = (container); \
+       auto X(iter) = X(_container)->begin(); \
+       for (auto item = *X(iter); X(iter) != X(_container)->end(); item = ((++X(iter)) != \
+               X(_container)->end()) ? *X(iter) : 0)
+
+/**
+       This is a common macro that is used as a constant for the name of specific
+       variables. We basically have two usage scenario:
+       1. In Subset operation, we allow users to specify a condition to extract a
+       subset. In that condition expression, we provide NAME, RET(type), ARG(type,
+       field) and STATE(field) to access each item's (method call) information.
+       2. In general specification (in pre- & post- conditions and side effects),
+       we would automatically generate an assignment that assign the current
+       MethodCall* pointer to a variable namedd _M. With this, when we access the
+       state of the current method, we use STATE(field) (this is a reference
+       for read/write).
+*/
+#define ITEM _M
+#define _M ME
+
+#define S_RET __value->S_RET
+
+/**
+       This operation is specifically for Method set. For example, when we want to
+       construct an integer set from the state field "x" (which is an
+       integer) of the previous set of method calls (PREV), and the new set goes to
+       "readSet", we would call "MakeSet(int, PREV, readSet, STATE(x));". Then users
+       can use the "readSet" as an integer set (set<int>)
+*/
+#define MakeSet(type, oldset, newset, field) \
+       auto newset = new SnapSet<type>; \
+       ForEach (_M, oldset) \
+               newset->insert(field); \
+
+/**
+       We provide a more general subset operation that takes a plain boolean
+       expression on each item (access by the name "ITEM") of the set, and put it
+       into a new set if the boolean expression (Guard) on that item holds. This is
+       used as the second arguments of the Subset operation. An example to extract
+       a subset of positive elements on an IntSet "s" would be "Subset(s,
+       GeneralGuard(int, ITEM > 0))"
+*/
+#define GeneralGuard(type, expression)  std::function<bool(type)> \
+       ([&](type ITEM) -> bool { return (expression);}) \
+
+/**
+       This is a more specific guard designed for the Method (MethodCall*). It
+       basically wrap around the GeneralGuard with the type Method. An example to
+       extract the subset of method calls in the PREV set whose state "x" is
+       equal to "val" would be "Subset(PREV, Guard(STATE(x) == val))"
+*/
+#define Guard(expression) GeneralGuard(Method, expression)
+
+#define MostRecent(guard) mostRecent(_M, guard)
+
+/**
+       A general subset operation that takes a condition and returns all the item
+       for which the boolean guard holds.
+*/
+inline SnapSet<Method>* mostRecent(Method method, std::function<bool(MethodCall*)> condition) {
+       SnapSet<Method> *res = new SnapSet<Method>;
+       // A list of potential nodes that are most recent
+       MethodList *toCheckList = new MethodList;
+       MethodSet prev = method->prev;
+       if (prev->empty()) // method is START node
+               return res;
+       else {
+               ForEach (_M, prev)
+                       toCheckList->push_back(_M);
+       }
+       // Searching loop
+       while (!toCheckList->empty()) {
+               Method _M = toCheckList->front();
+               toCheckList->pop_front();
+               
+               if (condition(_M)) {
+                       bool recencyFlag = true;
+                       ForEach (m, res) {
+                               if (MethodCall::belong(_M->allNext, m)) {
+                                       recencyFlag = false;
+                                       break;
+                               }
+                       }
+                       if (recencyFlag)
+                               res->insert(_M);
+               }
+               else { // Not what we want, keep going up the graph 
+                       prev = _M->prev;
+                       if (!prev->empty()) {
+                               ForEach (_M, prev)
+                                       toCheckList->push_back(_M);
+                       }
+               }
+       }
+       return res;
+}
+
+
+/**
+       A general subset operation that takes a condition and returns all the item
+       for which the boolean guard holds.
+*/
+template <class T>
+inline SnapSet<T>* Subset(SnapSet<T> *original, std::function<bool(T)> condition) {
+       SnapSet<T> *res = new SnapSet<T>;
+       ForEach (_M, original) {
+               if (condition(_M))
+                       res->insert(_M);
+       }
+       return res;
+}
+
+/**
+       A general set operation that takes a condition and returns if there exists
+       any item for which the boolean guard holds.
+*/
+template <class T>
+inline bool HasItem(SnapSet<T> *original, std::function<bool(T)> condition) {
+       ForEach (_M, original) {
+               if (condition(_M))
+                       return true;
+       }
+       return false;
+}
+
+
+
+/**
+       A general sublist operation that takes a condition and returns all the item
+       for which the boolean guard holds in the same order as in the old list.
+*/
+template <class T>
+inline list<T>* Sublist(list<T> *original, std::function<bool(T)> condition) {
+       list<T> *res = new list<T>;
+       ForEach (_M, original) {
+               if (condition(_M))
+                       res->push_back(_M);
+       }
+       return res;
+}
+
+/**
+       A general subvector operation that takes a condition and returns all the item
+       for which the boolean guard holds in the same order as in the old vector.
+*/
+template <class T>
+inline vector<T>* Subvector(vector<T> *original, std::function<bool(T)> condition) {
+       vector<T> *res = new vector<T>;
+       ForEach (_M, original) {
+               if (condition(_M))
+                       res->push_back(_M);
+       }
+       return res;
+}
+
+/** General for set, list & vector */
+#define Size(container) ((container)->size())
+
+#define _BelongHelper(type) \
+       template<class T> \
+       inline bool Belong(type<T> *container, T item) { \
+               return std::find(container->begin(), \
+                       container->end(), item) != container->end(); \
+       }
+
+_BelongHelper(SnapSet)
+_BelongHelper(SnapVector)
+_BelongHelper(SnapList)
+
+/** General set operations */
+template<class T>
+inline SnapSet<T>* Intersect(SnapSet<T> *set1, SnapSet<T> *set2) {
+       SnapSet<T> *res = new SnapSet<T>;
+       ForEach (item, set1) {
+               if (Belong(set2, item))
+                       res->insert(item);
+       }
+       return res;
+}
+
+template<class T>
+inline SnapSet<T>* Union(SnapSet<T> *s1, SnapSet<T> *s2) {
+       SnapSet<T> *res = new SnapSet<T>(*s1);
+       ForEach (item, s2)
+               res->insert(item);
+       return res;
+}
+
+template<class T>
+inline SnapSet<T>* Subtract(SnapSet<T> *set1, SnapSet<T> *set2) {
+       SnapSet<T> *res = new SnapSet<T>;
+       ForEach (item, set1) {
+               if (!Belong(set2, item))
+                       res->insert(item);
+       }
+       return res;
+}
+
+template<class T>
+inline void Insert(SnapSet<T> *s, T item) { s->insert(item); }
+
+template<class T>
+inline void Insert(SnapSet<T> *s, SnapSet<T> *others) {
+       ForEach (item, others)
+               s->insert(item);
+}
+
+/*
+inline MethodSet MakeSet(int count, ...) {
+       va_list ap;
+       MethodSet res;
+
+       va_start (ap, count);
+       res = NewMethodSet;
+       for (int i = 0; i < count; i++) {
+               Method item = va_arg (ap, Method);
+               res->insert(item);
+       }
+       va_end (ap);
+       return res;
+}
+*/
+
+/********** Method call related operations **********/
+#define Id(method) method->id
+#define ID Id(_M)
+
+#define Name(method) method->name
+#define NAME Name(_M)
+
+#define StructName(type) __struct_ ## type ## __
+#define Value(method, type, field) ((StructName(type)*) method->value)->field
+#define Ret(method, type) Value(method, type, RET)
+#define CRet(method, type) Value(method, type, C_RET)
+#define Arg(method, type, arg) Value(method, type, arg)
+
+#define VALUE(type, field) Value(_M, type, field)
+#define RET(type) VALUE(type, RET)
+#define C_RET(type) VALUE(type, C_RET)
+#define ARG(type, arg) VALUE(type, arg)
+
+#define State(method, field) ((StateStruct*) method->state)->field
+#define STATE(field) State(_M, field)
+
+#define Prev(method) method->prev
+#define PREV _M->prev
+
+#define Next(method) method->next
+#define NEXT _M->next
+
+#define Concurrent(method) method->concurrent
+#define CONCURRENT  _M->concurrent
+
+#define AllPrev(method) method->allPrev
+#define ALLPREV _M->allPrev
+
+#define AllNext(method) method->allNext
+#define ALLNEXT _M->allNext 
+
+/***************************************************************************/
+/***************************************************************************/
+
+#endif
diff --git a/spec-analysis/executiongraph.cc b/spec-analysis/executiongraph.cc
new file mode 100644 (file)
index 0000000..fddd345
--- /dev/null
@@ -0,0 +1,1611 @@
+#include <algorithm>
+#include "executiongraph.h"
+#include "action.h"
+#include "cyclegraph.h"
+#include "threads-model.h"
+#include "clockvector.h"
+#include "execution.h"
+#include <sys/time.h>
+#include <assert.h>
+#include <iterator>
+#include "modeltypes.h"
+#include "model-assert.h"
+#include "time.h"
+
+/********************    PotentialOP    ********************/
+PotentialOP::PotentialOP(ModelAction *op, CSTR label) :
+       operation(op),
+       label(label)
+{
+
+}
+
+
+/********************    ExecutionGraph    ********************/
+/*********    ExecutionGraph (public functions)   **********/
+/**
+       Initialze the necessary fields 
+*/
+ExecutionGraph::ExecutionGraph(ModelExecution *e, bool allowCyclic) : execution(e), allowCyclic(allowCyclic) {
+       methodList = new MethodList;
+       randomHistory = NULL;
+
+       broken = false;
+       noOrderingPoint = false;
+       cyclic = false;
+       threadLists = new SnapVector<action_list_t*>;
+}
+
+void ExecutionGraph::buildGraph(action_list_t *actions) {
+       buildThreadLists(actions);
+       
+       // First process the initialization annotation
+       bool hasInitAnno = false;
+       action_list_t::iterator iter = actions->begin();
+       for (; iter != actions->end(); iter++) {
+               ModelAction *act = *iter;
+               SpecAnnotation *anno = getAnnotation(act);
+               if (!anno)
+                       continue;
+               // Deal with the Initialization annotation
+               if (anno->type == INIT) {
+                       hasInitAnno = true;
+                       AnnoInit *annoInit = (AnnoInit*) anno->annotation;
+                       processInitAnnotation(annoInit);
+                       break;
+               }
+       }
+       if (!hasInitAnno) {
+               model_print("There is no initialization annotation\n");
+               broken = true;
+               return;
+       }
+
+       // Process the nodes for method calls of each thread
+       buildNodesFromThreads();
+       // Establish the edges
+       buildEdges();
+}
+
+bool ExecutionGraph::isBroken() {
+       return broken;
+}
+
+bool ExecutionGraph::isNoOrderingPoint() {
+       return noOrderingPoint;
+}
+
+bool ExecutionGraph::hasCycle() {
+       if (cyclic)
+               return true;
+       if (randomHistory)
+               return false;
+       randomHistory = generateOneRandomHistory();
+       return cyclic;
+}
+
+void ExecutionGraph::resetBroken() {
+       broken = false;
+}
+
+bool ExecutionGraph::checkAdmissibility() {
+       MethodList::iterator iter1, iter2;
+       bool admissible = true;
+       for (iter1 = methodList->begin(); iter1 != methodList->end(); iter1++) {
+               Method m1 = *iter1;
+               iter1++;
+               iter2 = iter1;
+               iter1--;
+               for (; iter2 != methodList->end(); iter2++) {
+                       Method m2 = *iter2;
+                       if (isReachable(m1, m2) || isReachable(m2, m1))
+                               continue;
+                       
+                       /* Now we need to check whether we have a commutativity rule that
+             * says the two method calls should be ordered */
+                       bool commute = true;
+                       for (int i = 0; i < commuteRuleNum; i++) {
+                               CommutativityRule rule = *(commuteRules + i);
+                               /* Check whether condition is satisfied */
+                               if (!rule.isRightRule(m1, m2)) // Not this rule
+                                       continue;
+                               else
+                                       commute = rule.checkCondition(m1, m2);
+                               if (!commute) // The rule requires them to be ordered
+                                       break;
+                       }
+                       // We have a rule that require m1 and m2 to be ordered
+                       if (!commute) {
+                               admissible = false;
+                               model_print("These two nodes should not commute:\n");
+                               model_print("\t");
+                               ModelAction *begin1 = m1->begin;
+                               ModelAction *begin2 = m2->begin;
+                               int tid1 = id_to_int(begin1->get_tid());
+                               int tid2 = id_to_int(begin2->get_tid());
+                               model_print("%s_%d (T%d)", m1->name,
+                                       begin1->get_seq_number(), tid1);
+                               model_print(" <-> ");
+                               model_print("%s_%d (T%d)", m2->name,
+                                       begin2->get_seq_number(), tid2);
+                               model_print("\n");
+                       }
+               }
+       }
+
+       return admissible;
+}
+
+/** Checking cyclic graph specification */
+bool ExecutionGraph::checkCyclicGraphSpec(bool verbose) {
+       if (verbose) {
+               model_print("---- Start to check cyclic graph ----\n");
+       }
+
+       bool pass = false;
+       for (MethodList::iterator it = methodList->begin(); it != methodList->end();
+               it++) {
+               Method m = *it;
+               if (isFakeMethod(m))
+                       continue;
+
+               StateFunctions *funcs = NULL;
+               if (verbose) {
+                       m->print(false, false);
+                       model_print("\n");
+                       
+                       funcs = funcMap->get(m->name);
+                       ASSERT (funcs);
+                       UpdateState_t printValue = (UpdateState_t) funcs->print->function;
+                       if (printValue) {
+                               model_print("\t**********  Value Info  **********\n");
+                               (*printValue)(m);
+                       }
+               }
+
+               // Cyclic graph only supports @PreCondition
+               funcs = funcMap->get(m->name);
+               ASSERT (funcs);
+               CheckState_t preCondition = (CheckState_t)
+                       funcs->preCondition->function;
+
+               // @PreCondition of Mehtod m
+               if (preCondition) {
+                       pass = (*preCondition)(m, m);
+
+                       if (!pass) {
+                               model_print("PreCondition is not satisfied. Problematic method"
+                                       " is as follow: \n");
+                               m->print(true, true);
+                               if (verbose) {
+                                       model_print("---- Check cyclic graph END ----\n\n");
+                               }
+                               return false;
+                       }
+               }
+       }
+
+       if (!pass) {
+               // Print out the graph
+               model_print("Problmatic execution graph: \n");
+               print(true);
+       } else if (verbose) {
+               // Print out the graph in verbose
+               model_print("Execution graph: \n");
+               print(true);
+       }
+
+       if (verbose) {
+               model_print("---- Check cyclic graph END ----\n\n");
+       }
+       return true;
+}
+
+
+
+
+/** To check "num" random histories */
+bool ExecutionGraph::checkRandomHistories(int num, bool stopOnFail, bool verbose) {
+       ASSERT (!cyclic);
+       bool pass = true;
+       int i;
+       for (i = 0; i < num; i++) {
+               MethodList *history = generateOneRandomHistory();
+               pass &= checkStateSpec(history, verbose, i + 1);
+               if (!pass) {
+                       // Print out the graph
+                       model_print("Problmatic execution graph: \n");
+                       print();
+                       if (stopOnFail) { // Just stop on this
+                               // Recycle
+                               delete history;
+                               if (verbose)
+                                       model_print("We totally checked %d histories.\n", i + 1);
+                               return false;
+                       }
+               } else if (verbose) {
+                       // Print out the graph in verbose
+                       model_print("Execution graph: \n");
+                       print();
+               }
+               // Recycle
+               delete history;
+       }
+       
+       if (verbose)
+               model_print("We totally checked %d histories.\n", i);
+       return pass;
+}
+
+
+/**
+       To generate and check all possible histories.
+       
+       If stopOnFailure is true, we stop generating any history and end the
+       checking process. Verbose flag controls how the checking process is exposed. 
+*/
+bool ExecutionGraph::checkAllHistories(bool stopOnFailure, bool verbose) {
+       ASSERT (!cyclic);
+       MethodList *curList = new MethodList;
+       int numLiveNodes = methodList->size();
+       int historyIndex = 1;
+       if (verbose) {
+               // Print out the graph in verbose
+               print();
+       }
+       
+       // FIXME: make stopOnFailure always true
+       stopOnFailure = true;
+       bool pass = checkAllHistoriesHelper(curList, numLiveNodes, historyIndex,
+               stopOnFailure, verbose);
+       if (pass) {
+               for (MethodList::iterator it = methodList->begin(); it !=
+                       methodList->end(); it++) {
+                       Method m = *it;
+                       if (isFakeMethod(m))
+                               continue;
+                       if (!m->justified) {
+                               model_print("\t");
+                               m->print(false, false);
+                               model_print(": unjustified\n");
+                               pass = false;
+                               break;
+                       }
+               }
+       }
+
+       if (!pass && !verbose) {
+               // Print out the graph
+               print();
+       }
+       if (verbose)
+               model_print("We totally checked %d histories.\n", historyIndex - 1);
+       return pass;
+}
+
+
+/********** Several public printing functions (ExecutionGraph) **********/
+
+void ExecutionGraph::printOneHistory(MethodList *history, CSTR header) {
+       model_print("-------------    %s (exec #%d)   -------------\n", header,
+               execution->get_execution_number());
+       int idx = 1;
+       for (MethodList::iterator it = history->begin(); it != history->end(); it++) {
+               Method m = *it;
+               model_print("%d. ", idx++);
+               m->print(false);
+       }
+       model_print("-------------    %s (exec #%d) (end)    -------------\n",
+               header, execution->get_execution_number());
+}
+
+void ExecutionGraph::printAllHistories(MethodListVector *histories) {
+       model_print("-------------    All histories (exec #%d)    -------------\n",
+               execution->get_execution_number());
+       for (unsigned i = 0; i < histories->size(); i++) {
+               model_print("***********************    # %d    ***********************\n", i + 1);
+               MethodList *history = (*histories)[i];
+               int idx = 1;
+               for (MethodList::iterator it = history->begin(); it != history->end();
+                       it++) {
+                       Method m = *it;
+                       model_print("%d. ", idx++);
+                       m->print(false);
+               }
+               if (i != histories->size() - 1)
+                       model_print("\n");
+       }
+       model_print("-------------    All histories (exec #%d) (end) "
+               "-------------\n\n", execution->get_execution_number());
+}
+
+/**
+       By default we print only all the edges that are directly from this mehtod
+       call node. If passed allEdges == true, we will print all the edges that are
+       reachable (SC/hb after) the current node.
+*/
+void ExecutionGraph::print(bool allEdges) {
+       model_print("\n");
+       const char *extraStr = allEdges ? "All Edges" : "";
+       model_print("------------------  Execution Graph -- %s (exec #%d)"
+       "  ------------------\n", extraStr, execution->get_execution_number());
+       for (MethodList::iterator iter = methodList->begin(); iter !=
+               methodList->end(); iter++) {
+               Method m = *iter;
+               /* Print the info the this method */
+               m->print(false);
+               /* Print the info the edges directly from this node */
+               SnapSet<Method> *theSet = allEdges ? m->allNext : m->next;
+               for (SnapSet<Method>::iterator nextIter = theSet->begin(); nextIter !=
+                       theSet->end(); nextIter++) {
+                       Method next = *nextIter;
+                       model_print("\t--> ");
+                       next->print(false);
+               }
+       }
+       model_print("------------------  End Graph (exec #%d)"
+               "  ------------------\n", execution->get_execution_number());
+       model_print("\n");
+}
+
+/**
+       By default we print only all the edges that are directly to this mehtod
+       call node. If passed allEdges == true, we will print all the edges that are
+       reachable (SC/hb before) from the current node.
+       
+       Only for debugging!!
+*/
+void ExecutionGraph::PrintReverse(bool allEdges) {
+       model_print("\n");
+       const char *extraStr = allEdges ? "All Edges" : "";
+       model_print("------------------  Reverse Execution Graph -- %s (exec #%d)"
+       "  ------------------\n", extraStr, execution->get_execution_number());
+       for (MethodList::iterator iter = methodList->begin(); iter !=
+               methodList->end(); iter++) {
+               Method m = *iter;
+               /* Print the info the this method */
+               m->print(false);
+               /* Print the info the edges directly from this node */
+               SnapSet<Method> *theSet = allEdges ? m->allPrev : m->prev;
+               for (SnapSet<Method>::iterator prevIter = theSet->begin(); prevIter !=
+                       theSet->end(); prevIter++) {
+                       Method prev = *prevIter;
+                       model_print("\t--> ");
+                       prev->print(false);
+               }
+       }
+       model_print("------------------  End Reverse Graph (exec #%d)"
+               "  ------------------\n", execution->get_execution_number());
+       model_print("\n");
+}
+
+
+/********** Internal member functions (ExecutionGraph) **********/
+
+void ExecutionGraph::buildThreadLists(action_list_t *actions) {
+       int maxthreads = 0;
+       for (action_list_t::iterator it = actions->begin(); it != actions->end(); it++) {
+               ModelAction *act = *it;
+               int threadid = id_to_int(act->get_tid());
+               if (threadid == 0)
+                       continue;
+               if (threadid > maxthreads) {
+                       threadLists->resize(threadid + 1);
+                       maxthreads = threadid;
+               }
+               action_list_t *list = (*threadLists)[threadid];
+               if (!list) {
+                       list = new action_list_t;
+                       (*threadLists)[threadid] = list;
+               }
+               list->push_back(act);
+       }
+}
+
+/**
+       Outside of this function, we have already processed the INIT type of
+       annotation, and we focus on extracting all the method call nodes in the
+       current thread list. This routine basically iterates the list, finds the
+       INTERFACE_BEGIN annotation, call the function extractMethod(), and advance
+       the iterator. That is to say, we would only see INIT or INTERFACE_BEGIN
+       annotations; if not, the specification annotations are wrong (we mark the
+       graph is broken)
+*/
+void ExecutionGraph::buildNodesFromThread(action_list_t *actions) {
+       action_list_t::iterator iter = actions->begin();
+
+       // FIXME: Just for the purpose of debugging
+       //printActions(actions, "BuildNodesFromThread");
+       
+       // annoBegin == NULL means we are looking for the beginning annotation
+       while (iter != actions->end()) {
+               ModelAction *act = *iter;
+               SpecAnnotation *anno = getAnnotation(act);
+               if (!anno) { // Means this is not an annotation action
+                       iter++;
+                       continue;
+               }
+               if (anno->type == INTERFACE_BEGIN) { // Interface beginning anno
+                       Method m = extractMethod(actions, iter);
+                       if (m) {
+                               // Get a complete method call node and store it
+                               methodList->push_back(m);
+                       } else {
+                               broken = true;
+                               model_print("Error with constructing a complete node.\n");
+                               return;
+                       }
+               } else if (anno->type != INIT) {
+                       broken = true;
+                       model_print("Missing beginning annotation.\n");
+                       return;
+               } else { // This is an INIT annotation
+                       iter++;
+               }
+       }
+}
+
+void ExecutionGraph::buildNodesFromThreads() {
+       /* We start from the 1st real thread */
+       for (unsigned i = 1; i < threadLists->size(); i++) {
+               buildNodesFromThread((*threadLists)[i]);
+               if (broken) // Early exit when detecting errors
+                       return;
+       }
+}
+
+/**
+    Find the previous non-annotation model action (ordering point from the
+       current iterator
+*/
+ModelAction* ExecutionGraph::findPrevAction(action_list_t *actions, action_list_t::iterator 
+        iter) {
+       while (iter != actions->begin()) {
+               iter--;
+               ModelAction *res = *iter;
+               if (res->get_type() != ATOMIC_ANNOTATION)
+                       return res;
+       }
+       return NULL;
+}
+
+/** 
+       When called, the current iter points to a beginning annotation; when done,
+       the iter points to either the end of the list or the next INTERFACE_BEGIN
+       annotation. 
+*/
+Method ExecutionGraph::extractMethod(action_list_t *actions, action_list_t::iterator &iter) {
+       ModelAction *act = *iter;
+       SpecAnnotation *anno = getAnnotation(act);
+       ASSERT(anno && anno->type == INTERFACE_BEGIN);
+
+       // Partially initialize the commit point node with the already known fields
+       AnnoInterfaceInfo *info = (AnnoInterfaceInfo*) anno->annotation;
+       Method m = new MethodCall(info->name, info->value, act);
+
+       // Some declaration for potential ordering points and its check
+       CSTR label;
+       PotentialOP *potentialOP= NULL;
+       // A list of potential ordering points
+       PotentialOPList *popList = new PotentialOPList;
+       // Ordering point operation
+       ModelAction *op = NULL;
+       // Whether the potential ordering points were defined
+       bool hasAppeared = false;
+       
+       bool methodComplete = false;
+       int nestedLevel = 0;
+       for (iter++; iter != actions->end(); iter++) {
+               act = *iter;
+               SpecAnnotation *anno = getAnnotation(act);
+               if (!anno)
+                       continue;
+               // Now we are dealing with one annotation
+               switch (anno->type) {
+                       case POTENTIAL_OP:
+                               //model_print("POTENTIAL_OP\n");
+                               label = (CSTR) anno->annotation;
+                               op = findPrevAction(actions, iter);
+                               if (!op) {
+                                       model_print("Potential ordering point annotation should"
+                                               "follow an atomic operation.\n");
+                                       model_print("%s_%d\n", label,
+                                               act->get_seq_number());
+                                       broken = true;
+                                       return NULL;
+                               }
+                               potentialOP = new PotentialOP(op, label);
+                               popList->push_back(potentialOP);
+                               break;
+                       case OP_CHECK:
+                               //model_print("OP_CHECK\n");
+                               label = (CSTR) anno->annotation;
+                               // Check if corresponding potential ordering point has appeared.
+                               hasAppeared = false;
+                               // However, in the current version of spec, we take the most
+                               // recent one in the list as the commit point (so we use
+                               // reverse iterator)
+                               for (PotentialOPList::reverse_iterator popIter = popList->rbegin();
+                                       popIter != popList->rend(); popIter++) {
+                                       potentialOP = *popIter;
+                                       if (label == potentialOP->label) {
+                                               m->addOrderingPoint(potentialOP->operation);
+                                               hasAppeared = true;
+                                               break; // Done when find the "first" PCP
+                                       }
+                               }
+                               if (!hasAppeared) {
+                                       model_print("Ordering point check annotation should"
+                                               "have previous potential ordering point.\n");
+                                       model_print("%s_%d\n", label,
+                                               act->get_seq_number());
+                                       broken = true;
+                                       return NULL;
+                               }
+                               break;
+                       case OP_DEFINE:
+                               //model_print("CP_DEFINE_CHECK\n");
+                               op = findPrevAction(actions, iter);
+                               if (!op) {
+                                       model_print("Ordering point define should "
+                                               "follow an atomic operation.\n");
+                                       act->print();
+                                       broken = true;
+                                       return NULL;
+                               }
+                               m->addOrderingPoint(op);
+                               break;
+                       case OP_CLEAR: 
+                               //model_print("OP_CLEAR\n");
+                               // Reset everything
+                               // Clear the list of potential ordering points
+                               popList->clear();
+                               // Clear the previous list of commit points
+                               m->orderingPoints->clear();
+                               break;
+                       case OP_CLEAR_DEFINE: 
+                               //model_print("OP_CLEAR_DEFINE\n");
+                               // Reset everything
+                               popList->clear();
+                               m->orderingPoints->clear();
+                               // Define the ordering point
+                               op = findPrevAction(actions, iter);
+                               if (!op) {
+                                       model_print("Ordering point clear define should "
+                                               "follow an atomic operation.\n");
+                                       act->print();
+                                       broken = true;
+                                       return NULL;
+                               }
+                               m->addOrderingPoint(op);
+                               break;
+                       case INTERFACE_BEGIN:
+                               nestedLevel++;
+                               break;
+                       case INTERFACE_END:
+                               if (nestedLevel == 0) {
+                                       methodComplete = true;
+                               }
+                               else
+                                       nestedLevel--;
+                               break;
+                       default:
+                               model_print("Unknown type!! We should never get here.\n");
+                               ASSERT(false);
+                               return NULL;
+               }
+               if (methodComplete) // Get out of the loop when we have a complete node
+                       break;
+       }
+
+       ASSERT (iter == actions->end() || (getAnnotation(*iter) &&
+               getAnnotation(*iter)->type == INTERFACE_END));
+       if (iter != actions->end())
+               iter++;
+
+       delete popList;
+       // XXX: We just allow methods to have no specified ordering points. In that
+       // case, the method is concurrent with every other method call
+       if (m->orderingPoints->size() == 0) {
+               noOrderingPoint = true;
+               return m;
+       } else {
+               // Get a complete method call
+               return m;
+       }
+}
+
+/** 
+       A utility function to extract the actual annotation
+       pointer and return the actual annotation if this is an annotation action;
+       otherwise return NULL.
+*/
+SpecAnnotation* ExecutionGraph::getAnnotation(ModelAction *act) {
+       if (act->get_type() != ATOMIC_ANNOTATION)
+               return NULL;
+       if (act->get_value() != SPEC_ANALYSIS)
+               return NULL;
+       SpecAnnotation *anno = (SpecAnnotation*) act->get_location();
+       ASSERT (anno);
+       return anno;
+}
+
+void ExecutionGraph::processInitAnnotation(AnnoInit *annoInit) {
+       // Assign state initial (and copy) function
+       NamedFunction *func = annoInit->initial;
+       ASSERT (func && func->type == INITIAL);
+       initial= annoInit->initial;
+
+       func = annoInit->final;
+       ASSERT (func && func->type == FINAL);
+       final= annoInit->final;
+
+       func = annoInit->copy;
+       ASSERT (func && func->type == COPY);
+       copy= annoInit->copy;
+
+       func = annoInit->clear;
+       ASSERT (func && func->type == CLEAR);
+       clear= annoInit->clear;
+
+       func = annoInit->printState;
+       ASSERT (func && func->type == PRINT_STATE);
+       printState = annoInit->printState;
+
+       // Assign the function map (from interface name to state functions)
+       funcMap = annoInit->funcMap;
+
+       // Initialize the commutativity rules array and size
+       commuteRules = annoInit->commuteRules;
+       commuteRuleNum = annoInit->commuteRuleNum; 
+}
+
+/**
+       After building up the graph (both the nodes and egdes are correctly built),
+       we also call this function to initialize the most recent justified node of
+       each method node.
+
+       A justified method node of a method m is a method that is in the allPrev set
+       of m, and all other nodes in the allPrev set of m are either before or after
+       it. The most recent justified node is the most recent one in the hb/SC
+       order.
+*/
+void ExecutionGraph::initializeJustifiedNode() {
+       MethodList::iterator it = methodList->begin();
+       // Start from the second methods in the list --- skipping the START node
+       for (it++; it != methodList->end(); it++) {
+               Method m = *it;
+               // Walk all the way up, when we have multiple immediately previous
+               // choices, pick one and check if that node is a justified node --- its
+               // concurrent set should be disjoint with the whole set m->allPrev.  If
+               // not, keep going up; otherwise, that node is the most recent justified
+               // node
+               
+               MethodSet prev = NULL;
+               Method justified = m;
+               do {
+                       prev = justified->prev;
+                       // At the very least we should have the START nodes
+                       ASSERT (!prev->empty());
+                       
+                       // setIt points to the very beginning of allPrev set
+                       SnapSet<Method>::iterator setIt = prev->begin();
+                       justified = *setIt;
+                       // Check whether justified is really the justified node
+                       if (MethodCall::disjoint(justified->concurrent, m->allPrev))
+                               break;
+               } while (true);
+               
+               ASSERT (justified != m);
+               // Don't forget to set the method's field
+               m->justifiedMethod = justified;
+
+        // Ensure we reset the justified field to be false in the beginning
+        m->justified = false;
+       }
+}
+
+
+/**
+       This is a very important interal function to build the graph. When called,
+       we assume that we have a list of method nodes built (extracted from the raw
+       execution), and this routine is responsible for building the connection
+       edges between them to yield an execution graph for checking
+*/
+void ExecutionGraph::buildEdges() {
+
+       MethodList::iterator iter1, iter2;
+       // First build the allPrev and allNext set (don't care if they are right
+       // previous or right next first)
+       for (iter1 = methodList->begin(); iter1 != methodList->end(); iter1++) {
+               Method m1 = *iter1;
+               iter1++;
+               iter2 = iter1;
+               iter1--;
+               for (; iter2 != methodList->end(); iter2++) {
+                       Method m2 = *iter2;
+                       int val = conflict(m1, m2);
+                       if (val == 1) {
+                               m1->allNext->insert(m2);
+                               m2->allPrev->insert(m1);
+                       } else if (val == -1) {
+                               m2->allNext->insert(m1);
+                               m1->allPrev->insert(m2);
+                       } else if (val == SELF_CYCLE) {
+                               if (allowCyclic) {
+                                       // m1 -> m2
+                                       m1->allNext->insert(m2);
+                                       m2->allPrev->insert(m1);
+                                       // m2 -> m1
+                                       m2->allNext->insert(m1);
+                                       m1->allPrev->insert(m2);
+                               }
+                       }
+               }
+       }
+
+       // Initialize two special nodes (START & FINISH)
+       Method startMethod = new MethodCall(GRAPH_START);
+       Method finishMethod = new MethodCall(GRAPH_FINISH);
+       // Initialize startMethod and finishMethd
+       startMethod->allNext->insert(finishMethod);
+       finishMethod->allPrev->insert(startMethod);
+       for (MethodList::iterator iter = methodList->begin(); iter !=
+               methodList->end(); iter++) {
+               Method m = *iter;
+               startMethod->allNext->insert(m);
+               m->allPrev->insert(startMethod);
+               m->allNext->insert(finishMethod);
+               finishMethod->allPrev->insert(m);
+       }
+       // Push these two special nodes to the beginning & end of methodList
+       methodList->push_front(startMethod);
+       methodList->push_back(finishMethod);
+       
+       // Now build the prev, next and concurrent sets
+       for (MethodList::iterator iter = methodList->begin(); iter != methodList->end();
+               iter++) {
+               Method m = *iter;
+               // prev -- nodes in allPrev that are before none in allPrev
+               // next -- nodes in allNext that are after none in allNext (but we
+               // actually build this set together with building prev
+               SnapSet<Method>::iterator setIt;
+               for (setIt = m->allPrev->begin(); setIt != m->allPrev->end(); setIt++) {
+                       Method prevMethod = *setIt;
+                       if (MethodCall::disjoint(m->allPrev, prevMethod->allNext)) {
+                               m->prev->insert(prevMethod);
+                               prevMethod->next->insert(m);
+                       }
+               }
+               
+               // concurrent -- all other nodes besides MYSELF, allPrev and allNext
+               for (MethodList::iterator concurIter = methodList->begin(); concurIter !=
+                       methodList->end(); concurIter++) {
+                       Method concur = *concurIter;
+                       if (concur != m && !MethodCall::belong(m->allPrev, concur)
+                               && !MethodCall::belong(m->allNext, concur))
+                               m->concurrent->insert(concur);
+               }
+       }
+
+       if (!cyclic)
+               AssertEdges();
+       // Initialize the justified method of each method
+       if (!cyclic)
+               initializeJustifiedNode();
+}
+
+/**
+       This method call is used to check whether the edge sets of the nodes are
+       built correctly --- consistently. We should only use this routine after the
+       builiding of edges when debugging
+*/
+void ExecutionGraph::AssertEdges() {
+       // Assume there is no self-cycle in execution (ordering points are fine)
+       ASSERT (!cyclic);
+
+       MethodList::iterator it;
+       for (it = methodList->begin(); it != methodList->end(); it++) {
+               Method m = *it;
+               SnapSet<Method>::iterator setIt, setIt1;
+               int val = 0;
+
+               // Soundness of sets
+               // 1. allPrev is sound
+               for (setIt = m->allPrev->begin(); setIt != m->allPrev->end(); setIt++) {
+                       Method prevMethod = *setIt;
+                       val = conflict(prevMethod, m);
+                       ASSERT (val == 1);
+               }
+               // 2. allNext is sound
+               for (setIt = m->allNext->begin(); setIt != m->allNext->end(); setIt++) {
+                       Method nextMethod = *setIt;
+                       val = conflict(m, nextMethod);
+                       ASSERT (val == 1);
+               }
+               // 3. concurrent is sound
+               for (setIt = m->concurrent->begin(); setIt != m->concurrent->end(); setIt++) {
+                       Method concur = *setIt;
+                       val = conflict(m, concur);
+                       ASSERT (val == 0);
+               }
+               // 4. allPrev & allNext are complete
+               ASSERT (1 + m->allPrev->size() + m->allNext->size() + m->concurrent->size()
+                       == methodList->size());
+               // 5. prev is sound
+               for (setIt = m->prev->begin(); setIt != m->prev->end(); setIt++) {
+                       Method prev = *setIt;
+                       ASSERT (MethodCall::belong(m->allPrev, prev));
+                       for (setIt1 = m->allPrev->begin(); setIt1 != m->allPrev->end();
+                               setIt1++) {
+                               Method middle = *setIt1;
+                               if (middle == prev)
+                                       continue;
+                               val = conflict(prev, middle);
+                               // prev is before none
+                               ASSERT (val != 1);
+                       }
+               }
+               // 6. prev is complete 
+               for (setIt = m->allPrev->begin(); setIt != m->allPrev->end(); setIt++) {
+                       Method prev = *setIt;
+                       if (MethodCall::belong(m->prev, prev))
+                               continue;
+                       // Ensure none of other previous nodes should be in the prev set
+                       bool hasMiddle = false;
+                       for (setIt1 = m->allPrev->begin(); setIt1 != m->allPrev->end();
+                               setIt1++) {
+                               Method middle = *setIt1;
+                               if (middle == prev)
+                                       continue;
+                               val = conflict(prev, middle);
+                               if (val == 1)
+                                       hasMiddle = true;
+                       }
+                       ASSERT (hasMiddle);
+               }
+
+               // 7. next is sound
+               for (setIt = m->next->begin(); setIt != m->next->end(); setIt++) {
+                       Method next = *setIt;
+                       ASSERT (MethodCall::belong(m->allNext, next));
+                       for (setIt1 = m->allNext->begin(); setIt1 != m->allNext->end();
+                               setIt1++) {
+                               Method middle = *setIt1;
+                               if (middle == next)
+                                       continue;
+                               val = conflict(middle, next);
+                               // next is after none
+                               ASSERT (val != 1);
+                       }
+               }
+               // 8. next is complete 
+               for (setIt = m->allNext->begin(); setIt != m->allNext->end(); setIt++) {
+                       Method next = *setIt;
+                       if (MethodCall::belong(m->next, next))
+                               continue;
+                       // Ensure none of other next nodes should be in the next set
+                       bool hasMiddle = false;
+                       for (setIt1 = m->allNext->begin(); setIt1 != m->allNext->end();
+                               setIt1++) {
+                               Method middle = *setIt1;
+                               if (middle == next)
+                                       continue;
+                               val = conflict(middle, next);
+                               if (val == 1)
+                                       hasMiddle = true;
+                       }
+                       ASSERT (hasMiddle);
+               }
+       }
+}
+
+/**
+       The conflicting relation between two model actions by hb/SC. If act1 and
+       act2 commutes, it returns 0; Otherwise, if act1->act2, it returns 1; and if
+       act2->act1, it returns -1
+*/
+int ExecutionGraph::conflict(ModelAction *act1, ModelAction *act2) {
+       if (act1->happens_before(act2))
+               return 1;
+       else if (act2->happens_before(act1))
+               return -1;
+       
+       if (act1->is_seqcst() && act2->is_seqcst()) {
+               if (act1->get_seq_number() < act2->get_seq_number())
+                       return 1;
+               else
+                       return -1;
+       } else
+               return 0;
+}
+
+/**
+       If there is no conflict between the ordering points of m1 and m2, then it
+       returns 0; Otherwise, if m1->m2, it returns 1; and if m2->m1, it returns -1.
+       If some ordering points have inconsistent conflicting relation, we print out
+       an error message (Self-cycle) and set the broken flag and return
+*/
+int ExecutionGraph::conflict(Method m1, Method m2) {
+       ASSERT (m1 != m2);
+       
+       if (isStartMethod(m1))
+               return 1;
+       if (isFinishMethod(m2))
+               return 1;
+
+       action_list_t *OPs1= m1->orderingPoints;
+       action_list_t *OPs2= m2->orderingPoints;
+       // Method calls without ordering points are concurrent with any others
+       if (OPs1->empty() || OPs2->empty())
+               return 0;
+       int val = 0;
+       action_list_t::iterator iter1, iter2;
+       for (iter1 = OPs1->begin(); iter1 != OPs1->end(); iter1++) {
+               ModelAction *act1 = *iter1;
+               for (iter2 = OPs2->begin(); iter2 != OPs2->end(); iter2++) {
+                       ModelAction *act2 = *iter2;
+                       int res = conflict(act1, act2);
+                       if (res == 0) // Commuting actions
+                               continue;
+                       if (val == 0)
+                               val = res;
+                       else if (val != res) { // Self cycle
+                               cyclic = true;
+                               if (!allowCyclic) {
+                                       model_print("There is a self cycle between the following two "
+                                               "methods\n");
+                                       m1->print();
+                                       m2->print();
+                                       broken = true;
+                               }
+                               return SELF_CYCLE;
+                       }
+               }
+       }
+       return val;
+}
+
+/**
+       Whether m2 is before m2 in the execution graph
+*/
+bool ExecutionGraph::isReachable(Method m1, Method m2) {
+       return MethodCall::belong(m1->allNext, m2);
+}
+
+MethodVector* ExecutionGraph::getRootNodes() {
+       MethodVector *vec = new MethodVector;
+       for (MethodList::iterator it = methodList->begin(); it != methodList->end();
+               it++) {
+               Method m = *it;
+               if (!m->exist)
+                       continue;
+               MethodSet prevMethods = m->allPrev;
+               if (prevMethods->size() == 0) { // Fast check (naturally a root node)
+                       vec->push_back(m);
+                       continue;
+               }
+               
+               // Also a root when all previous nodes no longer exist
+               bool isRoot = true;
+               for (SnapSet<Method>::iterator setIt = prevMethods->begin(); setIt !=
+                       prevMethods->end(); setIt++) {
+                       Method prev = *setIt;
+                       if (prev->exist) { // It does have an incoming edge
+                               isRoot = false;
+                               break;
+                       }
+               }
+               // It does not have an incoming edge now
+               if (isRoot)
+                       vec->push_back(m);
+       }
+       return vec;
+}
+
+/** 
+       Collects the set of method call nodes that do NOT have any following nodes
+       (the tail of the graph)
+*/
+MethodVector* ExecutionGraph::getEndNodes() {
+       MethodVector *vec = new MethodVector;
+       for (MethodList::iterator it = methodList->begin(); it != methodList->end();
+               it++) {
+               Method m = *it;
+               if (m->next->size() == 0)
+                       vec->push_back(m);
+       }
+       return vec;
+}
+
+/**
+       This is a helper function for generating all the topological sortings of the
+       execution graph. The idea of this function is recursively do the following
+       process: logically mark whether a method call node is alive or not
+       (initially all are alive), find a list of nodes that are root nodes (that
+       have no incoming edges), continuously pick one node in that list, add it to the curList
+       (which stores one topological sorting), and then recursively call itself to
+       resolve the rest.
+       
+       Arguments:
+       curList -> It represents a temporal result of a specific topological
+               sorting; keep in mind that before calling this function, pass an empty
+               list. 
+       numLiveNodes -> The number of nodes that are logically alive (that have not
+               been selected and added in a specific topological sorting yet). We keep
+               such a number as an optimization since when numLinveNodes equals to 0,
+               we can backtrack. Initially it is the size of the method call list.
+       historyIndex -> The current history index. We should start with 1.
+       stopOnFailure -> Stop the checking once we see a failed history
+       verbose -> Whether the verbose mode is on
+*/
+bool ExecutionGraph::checkAllHistoriesHelper(MethodList *curList, int
+       &numLiveNodes, int &historyIndex, bool stopOnFailure, bool verbose) {
+       if (cyclic)
+               return false;
+       
+       bool satisfied = true;
+       if (numLiveNodes == 0) { // Found one sorting, and we can backtrack
+               // Don't forget to increase the history number
+               satisfied = checkStateSpec(curList, verbose, historyIndex++);
+               // Don't forget to recycle
+               delete curList;
+               return satisfied;
+       }
+
+       MethodVector *roots = getRootNodes();
+       // Cycle exists (no root nodes but still have live nodes
+       if (roots->size() == 0) {
+               model_print("There is a cycle in this graph so we cannot generate"
+                       " sequential histories\n");
+               cyclic = true;
+               return false;
+       }
+
+       for (unsigned i = 0; i < roots->size(); i++) {
+               Method m = (*roots)[i];
+               m->exist = false;
+               numLiveNodes--;
+               // Copy the whole current list and use that copy for the next recursive
+               // call (because we will need the same copy for other iterations at the
+               // same level of recursive calls)
+               MethodList *newList = new MethodList(*curList);
+               newList->push_back(m);
+               
+               bool oneSatisfied = checkAllHistoriesHelper(newList, numLiveNodes,
+                       historyIndex, stopOnFailure, verbose);
+               // Stop the checking once failure or cycle detected
+               if (!oneSatisfied && (cyclic || stopOnFailure)) {
+                       delete curList;
+                       delete roots;
+                       return false;
+               }
+               satisfied &= oneSatisfied;
+               // Recover
+               m->exist = true;
+               numLiveNodes++;
+       }
+       delete curList;
+       delete roots;
+       return satisfied;
+}
+
+/** To check one generated history */
+bool ExecutionGraph::checkHistory(MethodList *history, int historyIndex, bool
+       verbose) {
+       bool pass = checkStateSpec(history, verbose, historyIndex);
+       if (!pass) {
+               // Print out the graph
+               model_print("Problmatic execution graph: \n");
+               print();
+       } else if (verbose) {
+               // Print out the graph in verbose
+               model_print("Execution graph: \n");
+               print();
+       }
+       return pass;
+}
+
+/** Generate one random topological sorting */
+MethodList* ExecutionGraph::generateOneRandomHistory() {
+       MethodList *res = new MethodList;
+       int liveNodeNum = methodList->size();
+       generateOneRandomHistoryHelper(res, liveNodeNum);
+       if (cyclic) {
+               delete res;
+               return NULL;
+       }
+       // Reset the liveness of each method
+       for (MethodList::iterator it = methodList->begin(); it != methodList->end();
+       it++) {
+               Method m = *it;
+               m->exist = true;
+       }
+       return res;
+}
+
+/**
+       The helper function to generate one random topological sorting
+*/
+void ExecutionGraph::generateOneRandomHistoryHelper(MethodList
+       *curList, int &numLiveNodes) {
+       if (cyclic)
+               return;
+
+       if (numLiveNodes == 0) { // Found one sorting, and we can return 
+               // Don't forget to recycle
+               return;
+       }
+
+       MethodVector *roots = getRootNodes();
+       // Cycle exists (no root nodes but still have live nodes
+       if (roots->size() == 0) {
+               model_print("There is a cycle in this graph so we cannot generate"
+                       " sequential histories\n");
+               cyclic = true;
+               return;
+       }
+
+       srand (time(NULL));
+       int pick = rand() % roots->size();
+       Method m = (*roots)[pick];
+
+       m->exist = false;
+       numLiveNodes--;
+       curList->push_back(m);
+
+       delete roots;
+       generateOneRandomHistoryHelper(curList, numLiveNodes);
+}
+
+Method ExecutionGraph::getStartMethod() {
+       return methodList->front();
+}
+
+Method ExecutionGraph::getFinishMethod() {
+       return methodList->back();
+}
+
+/**
+       Print out the ordering points and dynamic calling info (return value &
+       arguments) of all the methods in the methodList
+*/
+void ExecutionGraph::printAllMethodInfo(bool verbose) {
+       model_print("------------------  Method Info (exec #%d)"
+               "  ------------------\n", execution->get_execution_number());
+       for (MethodList::iterator iter = methodList->begin(); iter !=
+               methodList->end(); iter++) {
+               Method m = *iter;
+               printMethodInfo(m, verbose);
+       }
+       model_print("------------------  End Info (exec #%d)"
+               "  ------------------\n\n", execution->get_execution_number());
+}
+
+/**
+       Print out the ordering points and dynamic calling info (return value &
+       arguments).
+*/
+void ExecutionGraph::printMethodInfo(Method m, bool verbose) {
+       StateFunctions *funcs = NULL;
+       m->print(verbose, true);
+
+       if (isFakeMethod(m))
+               return;
+       
+       funcs = funcMap->get(m->name);
+       ASSERT (funcs);
+       UpdateState_t printValue = (UpdateState_t) funcs->print->function;
+
+       model_print("\t**********  Value Info  **********\n");
+       if (printValue) {
+               (*printValue)(m);
+       } else {
+               model_print("\tNothing printed..\n");
+       }
+}
+
+
+/** Clear the states of the method call */
+void ExecutionGraph::clearStates() {
+       UpdateState_t clearFunc = (UpdateState_t) clear->function;
+       for (MethodList::iterator it = methodList->begin(); it != methodList->end();
+               it++) {
+               Method m = *it;
+               if (m->state) {
+                       (*clearFunc)(m);
+               }
+       }
+}
+
+
+/**
+       Checking the state specification (in sequential order)
+*/
+bool ExecutionGraph::checkStateSpec(MethodList *history, bool verbose, int
+       historyIndex) {
+       if (verbose) {
+               if (historyIndex > 0)
+                       model_print("---- Start to check history #%d ----\n", historyIndex);
+               else
+                       model_print("---- Start to check history ----\n");
+       }
+
+       // @Transition can also return a boolean. For example when a steal() and
+       // take() in the deque both gets the last element, then we can see a bug in
+       // the evaluating the list of @Transitions for a following operation.
+       bool satisfied = true;
+
+       // @Initial state (with a fake starting node)
+       Method startMethod = getStartMethod();
+       UpdateState_t initialFunc = (UpdateState_t) initial->function;
+       UpdateState_t printStateFunc = (UpdateState_t) printState->function;
+       UpdateState_t clearFunc = (UpdateState_t) clear->function;
+
+       // We execute the equivalent sequential data structure with the state of the
+       // startMethod node 
+       (*initialFunc)(startMethod);
+       if (verbose) {
+               startMethod->print(false, true);
+               model_print("\t@Initial on START\n");
+               if (printStateFunc) { // If user has defined the print-out function
+                       model_print("\t**********  State Info  **********\n");
+                       (*printStateFunc)(startMethod);
+               }
+       }
+       
+       StateFunctions *funcs = NULL;
+       /** Execute each method call in the history */
+       for (MethodList::iterator it = history->begin(); it != history->end();
+               it++) {
+               Method m = *it;
+               if (isFakeMethod(m))
+                       continue;
+       
+               StateTransition_t transition = NULL;
+               
+               if (verbose) {
+                       m->print(false, true);
+                       funcs = funcMap->get(m->name);
+                       ASSERT (funcs);
+                       UpdateState_t printValue = (UpdateState_t) funcs->print->function;
+                       if (printValue) {
+                               model_print("\t**********  Value Info  **********\n");
+                               (*printValue)(m);
+                       }
+               }
+
+               funcs = funcMap->get(m->name);
+               ASSERT (funcs);
+
+               CheckState_t preCondition = (CheckState_t)
+                       funcs->preCondition->function;
+               // @PreCondition of Mehtod m
+               if (preCondition) {
+                       satisfied = (*preCondition)(startMethod, m);
+
+                       if (!satisfied) {
+                               model_print("PreCondition is not satisfied. Problematic method"
+                                       " is as follow: \n");
+                               m->print(true, true);
+                               printOneHistory(history, "Failed History");
+                               if (verbose) {
+                                       if (historyIndex > 0)
+                                               model_print("---- Check history #%d END ----\n\n",
+                                                       historyIndex);
+                                       else
+                                               model_print("---- Check history END ----\n\n");
+                               }
+                               break;
+                       }
+               }
+
+               // After checking the PreCondition, we run the transition on the
+               // startMethod node to update its state
+               transition = (StateTransition_t) funcs->transition->function;
+               // @Transition on the state of startMethod
+               satisfied = (*transition)(startMethod, m);
+               if (!satisfied) { // Error in evaluating @Transition
+                       model_print("Transition returns false. Problematic method"
+                               " is as follow: \n");
+                       m->print(true, true);
+                       printOneHistory(history, "Failed History");
+                       if (verbose) {
+                               if (historyIndex > 0)
+                                       model_print("---- Check history #%d END ----\n\n",
+                                               historyIndex);
+                               else
+                                       model_print("---- Check history END ----\n\n");
+                       }
+                       break;
+               }
+
+               if (verbose) {
+                       model_print("\t@Transition on itself\n");
+                       if (printStateFunc) {
+                               model_print("\t**********  State Info  **********\n");
+                               (*printStateFunc)(startMethod);
+                       }
+               }
+               
+               // @PostCondition of Mehtod m
+               CheckState_t postCondition = (CheckState_t)
+                       funcs->postCondition->function;
+               if (postCondition) {
+                       satisfied = (*postCondition)(startMethod, m);
+
+                       if (!satisfied) {
+                               model_print("PostCondition is not satisfied. Problematic method"
+                                       " is as follow: \n");
+                               m->print(true, true);
+                               printOneHistory(history, "Failed History");
+                               if (verbose) {
+                                       if (historyIndex > 0)
+                                               model_print("---- Check history #%d END ----\n\n",
+                                                       historyIndex);
+                                       else
+                                               model_print("---- Check history END ----\n\n");
+                               }
+                               break;
+                       }
+               }
+       }
+
+       // Clear out the states created when checking
+       (*clearFunc)(startMethod);
+
+       if (satisfied && verbose) {
+               printOneHistory(history, "Passed History");
+               // Print the history in verbose mode
+               if (historyIndex > 0)
+                       model_print("---- Check history #%d END ----\n\n", historyIndex);
+               else
+                       model_print("---- Check history END ----\n\n");
+       }
+       
+    if (verbose) {
+               if (historyIndex > 0)
+                       model_print("---- Start to check justifying subhistory #%d ----\n", historyIndex);
+               else
+                       model_print("---- Start to check justifying subhistory ----\n");
+
+       }
+       for (MethodList::iterator it = history->begin(); it != history->end();
+               it++) {
+               Method m = *it;
+               if (isFakeMethod(m))
+                       continue;
+               // Check justifying subhistory
+               if (!m->justified) {
+                       funcs = funcMap->get(m->name);
+                       CheckState_t justifyingPrecondition = (CheckState_t)
+                               funcs->justifyingPrecondition->function;
+                       CheckState_t justifyingPostcondition = (CheckState_t)
+                               funcs->justifyingPostcondition->function;
+            if (!justifyingPrecondition && !justifyingPostcondition ) {
+                // No need to check justifying conditions
+                m->justified = true;
+                if (verbose) {
+                    model_print("\tMethod call  ");
+                    m->print(false, false);
+                    model_print(": automatically justified.\n");
+                }
+            } else {
+                bool justified = checkJustifyingSubhistory(history, m, verbose, historyIndex);
+                if (justified) {
+                    // Set the "justified" flag --- no need to check again for cur
+                    m->justified = true;
+                    if (verbose) {
+                        model_print("\tMethod call  ");
+                        m->print(false, false);
+                        model_print(": is justified\n");
+                    }
+                } else {
+                    if (verbose) {
+                        model_print("\tMethod call  ");
+                        m->print(false, false);
+                        model_print(": has NOT been justified yet\n");
+                    }
+                }
+            }
+               } else {
+            if (verbose) {
+                model_print("\tMethod call  ");
+                m->print(false, false);
+                model_print(": is justified\n");
+            }
+        }
+       }
+    if (verbose) {
+               if (historyIndex > 0)
+                       model_print("---- Start to check justifying subhistory #%d END ----\n\n", historyIndex);
+               else
+                       model_print("---- Start to check justifying subhistory # END ----\n\n");
+
+       }
+
+       return satisfied;
+}
+
+bool ExecutionGraph::checkJustifyingSubhistory(MethodList *history, Method
+       cur, bool verbose, int historyIndex) {
+       if (verbose) {
+        model_print("\tMethod call  ");
+               cur->print(false, false);
+               model_print(": is being justified\n");
+       }
+
+       // @Transition can also return a boolean. For example when a steal() and
+       // take() in the deque both gets the last element, then we can see a bug in
+       // the evaluating the list of @Transitions for a following operation.
+       bool satisfied = true;
+
+       // @Initial state (with a fake starting node)
+       Method startMethod = getStartMethod();
+       UpdateState_t initialFunc = (UpdateState_t) initial->function;
+       UpdateState_t printStateFunc = (UpdateState_t) printState->function;
+       UpdateState_t printVauleFunc = NULL;
+       UpdateState_t clearFunc = (UpdateState_t) clear->function;
+
+       // We execute the equivalent sequential data structure with the state of the
+       // current method call
+       (*initialFunc)(cur);
+       if (verbose) {
+               startMethod->print(false, true);
+               model_print("\t@Initial on ");
+               cur->print(false, true);
+               if (printStateFunc) { // If user has defined the print-out function
+                       model_print("\t**********  State Info  **********\n");
+                       (*printStateFunc)(cur);
+               }
+       }
+       
+       StateFunctions *funcs = NULL;
+    StateTransition_t transition = NULL;
+       /** Execute each method call in the justifying subhistory till cur */
+       for (MethodList::iterator it = history->begin(); it != history->end(); it++) {
+               Method m = *it;
+               if (m == cur)
+                       break;
+               if (isFakeMethod(m))
+                       continue;
+               
+               // Ignore method calls that are not in my justifying subhistory
+               if (!MethodCall::belong(cur->allPrev, m))
+                       continue;
+
+               
+               if (verbose) {
+                       m->print(false, true);
+                       funcs = funcMap->get(m->name);
+                       ASSERT (funcs);
+                       UpdateState_t printValue = (UpdateState_t) funcs->print->function;
+                       if (printValue) {
+                               model_print("\t**********  Value Info  **********\n");
+                               (*printValue)(m);
+                       }
+               }
+
+               funcs = funcMap->get(m->name);
+               ASSERT (funcs);
+        transition = (StateTransition_t)
+            funcs->transition->function;
+
+               // In checking justifying behaviors, we don't check precondition &
+        // postcondition for other method calls
+        
+               // @Transition on the state of the "cur" method call 
+               satisfied = (*transition)(cur, m);
+               if (!satisfied) { // Error in evaluating @Transition
+                       if (verbose) {
+                               model_print("\tFailed @Transition before\n");
+                       }
+            // Clear out the states created when checking
+            (*clearFunc)(startMethod);
+                       return false;
+               } else {
+            if (verbose) {
+                model_print("\t@Transition on itself\n");
+                if (printStateFunc) {
+                    model_print("\t**********  State Info  **********\n");
+                    (*printStateFunc)(startMethod);
+                }
+            }
+        }
+       }
+
+    // For justifying subhistory, we only check the @JustifyingPrecondition &
+    // @JustifyingPostcondition for the last method call (the one we are
+    // checking)
+
+    // First check the @JustifyingPrecondition
+       funcs = funcMap->get(cur->name);
+       if (satisfied) {
+               // Check the justifying preondition on cur
+               CheckState_t justifyingPrecondition = (CheckState_t)
+                       funcs->justifyingPrecondition->function;
+               if (justifyingPrecondition) {
+                   // @JustifyingPrecondition of Mehtod cur
+                   satisfied = (*justifyingPrecondition)(cur, cur);
+        }
+               if (!satisfied) {
+                       if (verbose) {
+                model_print("\tFailed @JustifyingPrecondition\n");
+                       }
+            // Clear out the states created when checking
+            (*clearFunc)(startMethod);
+            return false;
+        }
+       }
+
+    // Then execute the @Transition
+    transition = (CheckState_t) funcs->transition->function;
+    // @Transition on the state of the "cur" method call 
+    satisfied = (*transition)(cur, cur);
+    if (!satisfied) { // Error in evaluating @Transition
+        if (verbose) {
+            model_print("\tFailed @Transition on itself\n");
+        }
+        // Clear out the states created when checking
+        (*clearFunc)(startMethod);
+        return false;
+    }
+    if (verbose) {
+        model_print("\t@Transition on itself\n");
+        if (printStateFunc) {
+            model_print("\t**********  State Info  **********\n");
+            (*printStateFunc)(startMethod);
+        }
+    }
+
+    // Finally check the @JustifyingPostcondition
+       if (satisfied) {
+               // Check the justifying preondition on cur
+               funcs = funcMap->get(cur->name);
+               CheckState_t justifyingPostcondition = (CheckState_t)
+                       funcs->justifyingPostcondition->function;
+               if (justifyingPostcondition) {
+            // @JustifyingPostcondition of Mehtod cur
+            satisfied = (*justifyingPostcondition)(cur, cur);
+        }
+       }
+
+       // Clear out the states created when checking
+       (*clearFunc)(startMethod);
+       return satisfied;
+}
+
+
+/**
+       To take a list of actions and print it out in a nicer way
+*/
+void ExecutionGraph::printActions(action_list_t *actions, const char *header) {
+       model_print("%s\n", header);
+       model_print("---------- Thread List (Begin) ---------\n");
+       for (action_list_t::iterator it = actions->begin(); it != actions->end();
+               it++) {
+               ModelAction *act = *it;
+               SpecAnnotation *anno = getAnnotation(act);
+               if (anno) {
+                       model_print("%s -> ", specAnnoType2Str(anno->type));
+               }
+               act->print();
+       }
+       model_print("---------- Thread List (End) ---------\n");
+}
+
+void ExecutionGraph::printOneSubhistory(MethodList *history, Method cur, CSTR header) {
+       model_print("-------------    %s (exec #%d)   -------------\n", header,
+               execution->get_execution_number());
+       int idx = 1;
+       for (MethodList::iterator it = history->begin(); it != history->end(); it++) {
+               Method m = *it;
+               if (!MethodCall::belong(cur->allPrev, m))
+                       continue;
+               model_print("%d. ", idx++);
+               m->print(false);
+       }
+       model_print("-------------    %s (exec #%d) (end)    -------------\n",
+               header, execution->get_execution_number());
+}
+
diff --git a/spec-analysis/executiongraph.h b/spec-analysis/executiongraph.h
new file mode 100644 (file)
index 0000000..870fd60
--- /dev/null
@@ -0,0 +1,338 @@
+#ifndef _EXECUTIONGRAPH_H
+#define _EXECUTIONGRAPH_H
+
+#include <stack>
+
+#include "hashtable.h"
+#include "specannotation.h"
+#include "mymemory.h"
+#include "modeltypes.h"
+#include "action.h"
+#include "common.h"
+#include "execution.h"
+
+#include "methodcall.h"
+#include "specannotation.h"
+
+
+const int SELF_CYCLE = 0xfffe;
+
+/**
+       Record the a potential commit point information, including the potential
+       commit point label number and the corresponding operation
+*/
+typedef struct PotentialOP {
+       ModelAction *operation;
+       CSTR label;
+
+       PotentialOP(ModelAction *op, CSTR name);
+
+       SNAPSHOTALLOC
+} PotentialOP;
+
+class Graph;
+
+
+typedef SnapList<PotentialOP*> PotentialOPList;
+
+/**
+       This represents the execution graph at the method call level. Each node is a
+       MethodCall type that has the runtime info (return value & arguments) and the
+       state info the method call. The edges in this graph are the hb/SC edges
+       dereived from the ordering points of the method call. Those edges
+       information are stoed in the PREV and NEXT set of MethodCall struct.
+*/
+class ExecutionGraph {
+       public:
+       ExecutionGraph(ModelExecution *e, bool allowCyclic);
+
+       /********** Public class interface for the core checking engine **********/
+       /**
+               Build the graph for an execution. It should returns true when the graph
+               is correctly built
+       */
+       void buildGraph(action_list_t *actions);
+
+       /** Check whether this is a broken execution */
+       bool isBroken();
+
+       /** Check whether this is an execution that has method calls without
+        * ordering points */
+       bool isNoOrderingPoint();
+
+       /**
+               Check whether this is a cyclic execution graph, meaning that the graph
+               has an cycle derived from the ordering points' hb/SC relation
+       */
+       bool hasCycle();
+
+       /** Reset the internal graph "broken" state to okay again */
+       void resetBroken();
+
+       /** Check whether the execution is admmisible */
+       bool checkAdmissibility();
+
+       /** Checking cyclic graph specification */
+       bool checkCyclicGraphSpec(bool verbose);
+
+       /** Check whether a number of random history is correct */
+       bool checkRandomHistories(int num = 1, bool stopOnFail = true, bool verbose = false);
+
+       /** Check whether all histories are correct */
+       bool checkAllHistories(bool stopOnFailure = true, bool verbose = false);
+       
+       /********** A few public printing functions for DEBUGGING **********/
+
+       /**
+               Print out the ordering points and dynamic calling info (return value &
+               arguments) of all the methods in the methodList
+       */
+       void printAllMethodInfo(bool verbose);
+
+       /** Print a random sorting */
+       void printOneHistory(MethodList *list, CSTR header = "A random history");
+
+       /** Print all the possible sortings */
+       void printAllHistories(MethodListVector *sortings);
+
+       /** Print out the graph for the purpose of debugging */
+       void print(bool allEdges = false);
+
+       /**
+               Print out the graph in reverse order (with previous edges) for the
+               purpose of debugging
+       */
+       void PrintReverse(bool allEdges);
+
+       SNAPSHOTALLOC
+
+       private:
+       /** The corresponding execution */
+       ModelExecution *execution;
+
+       /** All the threads each in a separate list of actions */
+       SnapVector<action_list_t*> *threadLists;
+
+       /** A plain list of all method calls (Method) in this execution */
+       MethodList *methodList;
+
+       /**
+               A list that represents some random history. The reason we have this here
+               is that before checking anything, we have to check graph acyclicity, and
+               that requires us to check whether we can generate a topological sorting.
+               Therefore, when we check it, we store that random result here.
+       */
+       MethodList *randomHistory;
+
+       /** Whether this is a broken graph */
+       bool broken;
+
+       /** Whether this graph has method calls that have no ordering points */
+       bool noOrderingPoint;
+
+       /** Whether there is a cycle in the graph */
+       bool cyclic;
+
+       /** Whether users expect us to check cyclic graph */
+       bool allowCyclic;
+
+
+       /** The state initialization function */
+       NamedFunction *initial;
+
+       /** FIXME: The final check function; we might delete this */
+       NamedFunction *final;
+
+       /** The state copy function */
+       NamedFunction *copy;
+
+       /** The state clear function */
+       NamedFunction *clear;
+
+       /** The state print-out function */
+       NamedFunction *printState;
+
+       /** The map from interface label name to the set of spec functions */
+       StateFuncMap *funcMap;
+
+       /** The commutativity rule array and its size */
+       CommutativityRule *commuteRules;
+       int commuteRuleNum;
+       
+       /********** Internal member functions **********/
+
+       /**
+               Simply build a vector of lists of thread actions. Such info will be very
+               useful for later constructing the execution graph
+       */
+       void buildThreadLists(action_list_t *actions);
+
+       /** Build the nodes from a thread list */
+       void buildNodesFromThread(action_list_t *actions);
+
+       /** Build the nodes from all the thread lists */
+       void buildNodesFromThreads();
+
+
+       /**
+               Find the previous non-annotation model action (ordering point from the
+               current iterator
+       */
+       ModelAction* findPrevAction(action_list_t *actions, action_list_t::iterator
+               iter);
+
+       /**
+               Extract a MethodCall node starting from the current iterator, and the
+               iter iterator will be advanced to the next INTERFACE_BEGIN annotation.
+               When called, the iter must point to an INTERFACE_BEGIN annotation
+       */
+       Method extractMethod(action_list_t *actions, action_list_t::iterator &iter);
+
+       /**
+               Process the initialization annotation block to initialize the
+               commutativity rule info and the checking function info 
+       */
+       void processInitAnnotation(AnnoInit *annoInit);
+
+       /** 
+               A utility function to extract the actual annotation
+               pointer and return the actual annotation if this is an annotation action;
+               otherwise return NULL.
+       */
+       SpecAnnotation* getAnnotation(ModelAction *act);
+
+       /**
+               After building up the graph (both the nodes and egdes are correctly
+               built), we also call this function to initialize the most recent
+               justified node of each method node.
+
+               A justified method node of a method m is a method that is in the allPrev
+               set of m, and all other nodes in the allPrev set of m are either before
+               or after it. The most recent justified node is the most recent one in
+               the hb/SC order.
+       */
+       void initializeJustifiedNode();
+
+       /**
+               After extracting the MethodCall info for each method call, we use this
+               function to build the edges (a few different sets of edges that
+               represent the edge of the execution graph (PREV, NEXT & CONCURRENT...)
+       */
+       void buildEdges();
+
+       /**
+               This method call is used to check whether the edge sets of the nodes are
+               built correctly --- consistently. We should only use this routine after the
+               builiding of edges when debugging
+       */
+       void AssertEdges();
+
+       /**
+               The conflicting relation between two model actions by hb/SC. If act1 and
+               act2 commutes, it returns 0; Otherwise, if act1->act2, it returns 1; and
+               if act2->act1, it returns -1
+       */
+       int conflict(ModelAction *act1, ModelAction *act2);
+       
+       /**
+               If there is no conflict between the ordering points of m1 and m2, then
+               it returns 0; Otherwise, if m1->m2, it returns 1; and if m2->m1, it
+               returns -1.  If some ordering points have inconsistent conflicting
+               relation, we print out an error message (Self-cycle) and set the broken
+               flag and return
+       */
+       int conflict(Method m1, Method m2);
+
+       /**
+               Check whether m1 is before m2 in hb/SC; Reachability <=> m1 -hb/SC-> m2.
+               We need to call this method when checking admissibility properties
+       */
+       bool isReachable(Method m1, Method m2);
+
+       /**
+               Find the list of nodes that do not have any incoming edges (root nodes).
+               Be careful that when generating histories, this function will also
+               consider whether a method node logicall exists.
+       */
+       MethodVector* getRootNodes();
+
+       /**
+               Find the list of nodes that do not have any outgoing edges (end nodes)
+       */
+       MethodVector* getEndNodes();
+
+       /**
+               A helper function for generating and check all sequential histories. Before calling this function, initialize an empty
+               MethodList , and pass it as curList. Also pass the size of the method
+               list as the numLiveNodes.
+
+               If you only want to stop the checking process when finding one failed
+               history, pass true to stopOnFailure.
+       */
+       bool checkAllHistoriesHelper(MethodList *curList, int &numLiveNodes, int
+       &historyNum, bool stopOnFailure, bool verbose);
+
+
+       /** Check whether a specific history is correct */
+       bool checkHistory(MethodList *history, int historyIndex, bool verbose = false);
+
+       /** Generate one random topological sorting */
+       MethodList* generateOneRandomHistory();
+
+       /**
+               The helper function to generate one random topological sorting
+       */
+       void generateOneRandomHistoryHelper(MethodList
+               *curList, int &numLiveNodes);
+
+       /** Return the fake nodes -- START & END */
+       Method getStartMethod();
+       Method getFinishMethod();
+       
+       /** Whether method call node m is a fake node */
+       inline bool isFakeMethod(Method m) {
+               return isStartMethod(m) || isFinishMethod(m);
+       }
+
+       /** Whether method call node m is a starting node */
+       inline bool isStartMethod(Method m) {
+               return m->name == GRAPH_START;
+       }
+
+       /** Whether method call node m is a finish node */
+       inline bool isFinishMethod(Method m) {
+               return m->name == GRAPH_FINISH;
+       }
+
+       /**
+               Print out the ordering points and dynamic calling info (return value &
+               arguments).
+       */
+       void printMethodInfo(Method m, bool verbose);
+
+       /** Clear the states of the method call */
+       void clearStates();
+
+       /** 
+               Check the state specifications (PreCondition & PostCondition & state
+               transition and evaluation) based on the graph (called after
+               admissibility check). The verbose option controls whether we print a
+               detailed list of checking functions that we have called
+       */
+       bool checkStateSpec(MethodList *history, bool verbose, int historyNum);
+
+       /**
+               Check the justifying subhistory with respect to history of m.
+       */
+       bool checkJustifyingSubhistory(MethodList *subhistory, Method cur,
+               bool verbose, int historyIndex);
+
+       /** Print a problematic thread list */
+       void printActions(action_list_t *actions, const char *header = "The problematic thread list:");
+
+       /** Print one jusifying subhistory of method call cur */
+       void printOneSubhistory(MethodList *history, Method cur,
+               CSTR header);
+};
+
+#endif
diff --git a/spec-analysis/include/specannotation-api.h b/spec-analysis/include/specannotation-api.h
new file mode 100644 (file)
index 0000000..aee4196
--- /dev/null
@@ -0,0 +1,38 @@
+#ifndef _SPECANNOTATION_API_H
+#define _SPECANNOTATION_API_H
+
+#define NEW_SIZE(type, size) (type*) malloc(size)
+#define NEW(type) NEW_SIZE(type, sizeof(type))
+
+struct MethodCall;
+typedef struct MethodCall *Method;
+typedef const char *CSTR;
+
+struct AnnoInterfaceInfo;
+typedef struct AnnoInterfaceInfo AnnoInterfaceInfo;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct AnnoInterfaceInfo* _createInterfaceBeginAnnotation(CSTR name);
+
+void _setInterfaceBeginAnnotationValue(struct AnnoInterfaceInfo *info, void *value);
+
+void _createInterfaceEndAnnotation(CSTR name);
+
+void _createOPDefineAnnotation();
+
+void _createPotentialOPAnnotation(CSTR label);
+
+void _createOPCheckAnnotation(CSTR label);
+
+void _createOPClearAnnotation();
+
+void _createOPClearDefineAnnotation();
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif
diff --git a/spec-analysis/methodcall.cc b/spec-analysis/methodcall.cc
new file mode 100644 (file)
index 0000000..84c35ba
--- /dev/null
@@ -0,0 +1,125 @@
+#include <algorithm>
+#include "common.h"
+#include "threads-model.h"
+#include "methodcall.h"
+#include "spec_common.h"
+
+CSTR GRAPH_START = "START_NODE";
+CSTR GRAPH_FINISH = "FINISH_NODE";
+
+const unsigned int METHOD_ID_MAX = 0xffffffff;
+const unsigned int METHOD_ID_MIN = 0;
+
+MethodCall::MethodCall(CSTR name, void *value, ModelAction *begin) :
+       name(name), value(value), prev(new SnapSet<Method>), next(new
+       SnapSet<Method>), concurrent(new SnapSet<Method>), justifiedMethod(NULL),
+       justified(false), end(NULL), orderingPoints(new action_list_t), allPrev(new
+       SnapSet<Method>), allNext(new SnapSet<Method>), exist(true) {
+       if (name == GRAPH_START) {
+               this->begin = NULL;
+               id = METHOD_ID_MIN;
+               tid = 1; // Considered to be the main thread
+       } else if (name == GRAPH_FINISH) {
+               this->begin = NULL;
+               id = METHOD_ID_MAX;
+               tid = 1; // Considered to be the main thread
+       } else {
+               this->begin = begin;
+               ASSERT (begin);
+               id = begin->get_seq_number();
+               tid = id_to_int(begin->get_tid());
+       }
+}
+       
+void MethodCall::addPrev(Method m) { prev->insert(m); }
+
+void MethodCall::addNext(Method m) { next->insert(m); }
+       
+void MethodCall::addConcurrent(Method m) { concurrent->insert(m); }
+
+void MethodCall::addOrderingPoint(ModelAction *act) {
+       bool hasIt = orderingPoints->end() != std::find(orderingPoints->begin(),
+               orderingPoints->end(), act);
+       if (!hasIt)
+               orderingPoints->push_back(act);
+}
+
+
+bool MethodCall::before(Method another) {
+       return belong(allNext, another);
+}
+
+bool MethodCall::belong(MethodSet s, Method m) {
+       return s->end() != std::find(s->begin(), s->end(), m);
+}
+
+bool MethodCall::identical(MethodSet s1, MethodSet s2) {
+       if (s1->size() != s2->size())
+               return false;
+       SnapSet<Method>::iterator it;
+       for (it = s1->begin(); it != s1->end(); it++) {
+               Method m1 = *it;
+               if (belong(s2, m1))
+                       return false;
+       }
+       return true;
+}
+
+/**
+       Put the union of src and dest to dest.
+*/
+void MethodCall::Union(MethodSet dest, MethodSet src) {
+       SnapSet<Method>::iterator it;
+       for (it = src->begin(); it != src->end(); it++) {
+               Method m = *it;
+               dest->insert(m);
+       }
+}
+
+MethodSet MethodCall::intersection(MethodSet s1, MethodSet s2) {
+       MethodSet res = new SnapSet<Method>;
+       SnapSet<Method>::iterator it;
+       for (it = s1->begin(); it != s1->end(); it++) {
+               Method m = *it;
+               if (belong(s2, m))
+                       res->insert(m);
+       }
+       return res;
+}
+
+bool MethodCall::disjoint(MethodSet s1, MethodSet s2) {
+       SnapSet<Method>::iterator it;
+       for (it = s1->begin(); it != s1->end(); it++) {
+               Method m = *it;
+               if (belong(s2, m))
+                       return false;
+       }
+       return true;
+}
+
+void MethodCall::print(bool printOP, bool breakAtEnd) {
+       if (name == GRAPH_START) {
+               model_print("%s", GRAPH_START);
+               if (breakAtEnd)
+                       model_print("\n");
+               return;
+       }
+       if (name == GRAPH_FINISH) {
+               model_print("%s", GRAPH_FINISH);
+               if (breakAtEnd)
+                       model_print("\n");
+               return;
+       }
+       model_print("%u.%s(T%d)", id, name, id_to_int(begin->get_tid()));
+       if (breakAtEnd)
+               model_print("\n");
+       if (!printOP)
+               return;
+       int i = 1;
+       for (action_list_t::iterator it = orderingPoints->begin(); it !=
+               orderingPoints->end(); it++) {
+               ModelAction *op = *it;
+               model_print("\t-> %d. ", i++);
+               op->print();
+       }
+}
diff --git a/spec-analysis/methodcall.h b/spec-analysis/methodcall.h
new file mode 100644 (file)
index 0000000..a88b651
--- /dev/null
@@ -0,0 +1,114 @@
+#ifndef _METHODCALL_H
+#define _METHODCALL_H
+
+#include "stl-model.h"
+#include "action.h"
+#include "spec_common.h"
+
+class MethodCall;
+
+typedef MethodCall *Method;
+typedef SnapSet<Method> *MethodSet;
+typedef SnapList<ModelAction *> action_list_t;
+
+typedef SnapList<Method> MethodList;
+typedef SnapVector<Method> MethodVector;
+typedef SnapVector<MethodList*> MethodListVector;
+
+/**
+       This is the core class on which the whole checking process will be
+       executing. With the original execution (with the raw annotation
+       information), we construct an execution graph whose nodes represent method
+       calls, and whose edges represent the hb/SC relation between the ordering
+       points of method calls. In that graph, the MethodCall class acts as the node
+       that contains the core information for checking --- the name of the
+       interface, the value (return value and arguments), the state of the current
+       method call, and a set of previous, next and concurrent method calls.
+
+       Plus, this class contains extra info about the ordering points, a set of all
+       method calls that are hb/SC before me (for evaluating the state), and also
+       some other helping internal member variable for generating checking schemes.
+*/
+class MethodCall {
+       public:
+       unsigned int id; // The method call id (the seq_num of the begin action)
+       int tid; // The thread id
+       CSTR name; // The interface label name
+       void *value; // The pointer that points to the struct that have the return
+                                // value and the arguments
+       void *state; // The pointer that points to the struct that represents
+                                         // the state
+       MethodSet prev; // Method calls that are hb right before me
+       MethodSet next; // Method calls that are hb right after me
+       MethodSet concurrent; // Method calls that are concurrent with me
+
+       Method justifiedMethod; // The method before me and is not concurrent with
+                                                       // any other mehtods in my allPrev set
+
+       /** 
+               This indicates if the non-deterministic behaviors of this method call
+               has been justified by any of its justifying subhistory. If so, we do not
+               need to check on its justifying subhistory. Initially it is false.
+       */
+       bool justified; 
+
+       MethodCall(CSTR name, void *value = NULL, ModelAction *begin = NULL);
+       
+       void addPrev(Method m);
+
+       void addNext(Method m);
+       
+       void addConcurrent(Method m);
+
+       void addOrderingPoint(ModelAction *act);
+
+       bool before(Method another);
+
+       static bool belong(MethodSet s, Method m);
+
+       static bool identical(MethodSet s1, MethodSet s2);
+
+       /** Put the union of src and dest to dest */
+       static void Union(MethodSet dest, MethodSet src);
+
+       static MethodSet intersection(MethodSet s1, MethodSet s2);
+
+       static bool disjoint(MethodSet s1, MethodSet s2);
+
+       /**
+               Print the method all name with the seq_num of the begin annotation and
+               its thread id.
+       
+               printOP == true -> Add each line with the ordering point operation's
+               print()
+
+               breakAtEnd == true -> Add a line break at the end of the print;
+               otherwise, the print will be a string without line breaker when printOP
+               is false.
+       */
+       void print(bool printOP = true, bool breakAtEnd = true);
+       
+       /**
+               FIXME: The end action is not really used or necessary here, maybe we
+               should clean this
+       */
+       ModelAction *begin;
+       ModelAction *end;
+       action_list_t *orderingPoints;
+       
+       /**
+               Keep a set of all methods that are hb/SC before&after me to calculate my
+               state
+       */
+       MethodSet allPrev;
+       MethodSet allNext;
+
+       /** Logically exist (for generating all possible topological sortings) */
+       bool exist;
+
+       SNAPSHOTALLOC
+};
+
+
+
+#endif
diff --git a/spec-analysis/spec_common.h b/spec-analysis/spec_common.h
new file mode 100644 (file)
index 0000000..b8c3a46
--- /dev/null
@@ -0,0 +1,47 @@
+#ifndef _SPEC_COMMON_H
+#define _SPEC_COMMON_H
+
+#include <set>
+#include <stdlib.h>
+#include "mymemory.h"
+
+/** Comment this out if you don't want unnecessary debugging printing out */
+#define CDSSPEC_DEBUG
+
+#ifdef CDSSPEC_DEBUG
+#define debug_print(fmt, ...) do { dprintf(model_out, fmt, ##__VA_ARGS__); } while (0)
+#else
+#define debug_print(fmt, ...) do { } while (0)
+#endif
+
+#define SPEC_ANALYSIS 1
+
+/** Null function pointer */
+#define NULL_FUNC NULL
+
+#define NEW_SIZE(type, size) (type*) malloc(size)
+#define NEW(type) NEW_SIZE(type, sizeof(type))
+
+#define EQ(str1, str2) (strcmp(str1, str2) == 0)
+
+extern const unsigned int METHOD_ID_MAX;
+extern const unsigned int METHOD_ID_MIN;
+
+typedef const char *CSTR;
+
+extern CSTR GRAPH_START;
+extern CSTR GRAPH_FINISH;
+
+/** Define a snapshotting set for CDSChecker backend analysis */
+template<typename _Tp>
+class SnapSet : public std::set<_Tp, std::less<_Tp>, SnapshotAlloc<_Tp> >
+{   
+       public:
+       typedef std::set<_Tp, std::less<_Tp>, SnapshotAlloc<_Tp> > set;
+        
+       SnapSet() : set() { }
+
+       SNAPSHOTALLOC
+};
+
+#endif
diff --git a/spec-analysis/specanalysis.cc b/spec-analysis/specanalysis.cc
new file mode 100644 (file)
index 0000000..e5a1f2c
--- /dev/null
@@ -0,0 +1,226 @@
+#include "specanalysis.h"
+#include "action.h"
+#include "cyclegraph.h"
+#include "threads-model.h"
+#include "clockvector.h"
+#include "execution.h"
+#include <sys/time.h>
+#include <assert.h>
+#include "modeltypes.h"
+#include "executiongraph.h"
+
+
+SPECAnalysis::SPECAnalysis()
+{
+       execution = NULL;
+       stats = (struct spec_stats*) model_calloc(1, sizeof(struct spec_stats));
+       print_always = false;
+       print_inadmissible = true;
+       quiet = false;
+       checkCyclic = false;
+       stopOnFail = false;
+       checkRandomNum = 0;
+}
+
+SPECAnalysis::~SPECAnalysis() {
+}
+
+void SPECAnalysis::setExecution(ModelExecution * execution) {
+       this->execution = execution;
+}
+
+const char * SPECAnalysis::name() {
+       const char * name = "SPEC";
+       return name;
+}
+
+void SPECAnalysis::finish() {
+       model_print("\n");
+       model_print(">>>>>>>> SPECAnalysis finished <<<<<<<<\n");
+
+       model_print("Total execution checked: %d\n", stats->bugfreeCnt);
+       model_print("Detected by CDSChecker: %d\n", stats->buggyCnt);
+       model_print("Broken graph: %d\n", stats->brokenCnt);
+       model_print("Cyclic graph: %d\n", stats->cyclicCnt);
+       model_print("Inadmissible executions: %d\n", stats->inadmissibilityCnt);
+       model_print("Failed executions: %d\n", stats->failedCnt);
+
+       if (stats->cyclicCnt > 0 && checkCyclic) {
+               model_print("Warning: You have cycle in your execution graphs.\n");
+       }
+
+       if (stats->failedCnt == 0) {
+               model_print("Yay! All executions have passed the specification.\n");
+               if (stats->brokenCnt > 0)
+                       model_print("However! You have executions with a broken graph.\n");
+               if (stats->cyclicCnt > 0) {
+                       model_print("Warning: You have cyclic execution graphs!\n");
+                       if (checkCyclic) {
+                               model_print("Make sure that's what you expect.\n");
+                       }
+               }
+               if (stats->inadmissibilityCnt > 0)
+                       model_print("However! You have inadmissible executions.\n");
+               if (stats->noOrderingPointCnt > 0 && print_always)
+                       model_print("You have execution graphs that have no ordering points.\n");
+
+       }
+}
+
+bool SPECAnalysis::isCheckRandomHistories(char *opt, int &num) {
+       char *p = opt;
+       bool res = false;
+       if (*p == 'c') {
+               p++;
+               if (*p == 'h') {
+                       p++;
+                       if (*p == 'e') {
+                               p++;
+                               if (*p == 'c') {
+                                       p++;
+                                       if (*p == 'k') {
+                                               res = true;
+                                               p++;
+                                       }
+                               }
+                       }
+               }
+       }
+       if (res) {
+               // p now should point to '-'
+               if (*p == '-') {
+                       p++;
+                       num = atoi(p);
+                       if (num > 0)
+                               return true;
+               }
+               return false;
+       }
+       return res;
+}
+
+bool SPECAnalysis::option(char * opt) {
+       if (strcmp(opt, "verbose")==0) {
+               print_always=true;
+               return false;
+       } else if (strcmp(opt, "no-admissible")==0) {
+               print_inadmissible = false;
+               return false;
+       } else if (strcmp(opt, "quiet")==0) {
+               quiet = true;
+               return false;
+       } else if (strcmp(opt, "check-cyclic") == 0) {
+               checkCyclic = true;
+               return false;
+       } else if (strcmp(opt, "stop-on-fail")==0) {
+               stopOnFail = true;
+               return false;
+       } else if (isCheckRandomHistories(opt, checkRandomNum)) {
+               return false;
+       } else if (strcmp(opt, "help") != 0) {
+               model_print("Unrecognized option: %s\n", opt);
+       } 
+
+       model_print("SPEC Analysis options\n"
+               "By default SPEC outputs the graphs of those failed execution\n"
+               "verbose -- print graphs of any traces\n"
+               "quiet -- do not print out graphs\n"
+               "inadmissible-quiet -- print the inadmissible\n"
+               "check-one -- only check one random possible topological"
+                       "sortings (check all possible by default)\n"
+       );
+       model_print("\n");
+       
+       return true;
+}
+
+void SPECAnalysis::analyze(action_list_t *actions) {
+       /* Count the number traces */
+       stats->traceCnt++;
+       if (execution->have_bug_reports()) {
+               /* Count the number traces */
+               stats->buggyCnt++;
+               return;
+       }
+
+       /* Count the number bug-free traces */
+       stats->bugfreeCnt++;
+
+       // FIXME: Make checkCyclic false by default
+       ExecutionGraph *graph = new ExecutionGraph(execution, checkCyclic);
+       graph->buildGraph(actions);
+       if (graph->isBroken()) {
+               stats->brokenCnt++;
+               if (print_always && !quiet) { // By default not printing
+                       model_print("Execution #%d has a broken graph.\n\n",
+                               execution->get_execution_number());
+               }
+               return;
+       }
+
+       if (print_always) {
+               model_print("------------------  Checking execution #%d"
+                       "  ------------------\n", execution->get_execution_number());
+       }
+       
+       // Count how many executions that have no-ordering-point method calls
+       if (graph->isNoOrderingPoint()) {
+               stats->noOrderingPointCnt++;
+       }
+
+       if (!graph->checkAdmissibility()) {
+               /* One more inadmissible trace */
+               stats->inadmissibilityCnt++;
+               if (print_inadmissible && !quiet) {
+                       model_print("Execution #%d is NOT admissible\n",
+                               execution->get_execution_number());
+                       graph->print();
+                       if (print_always)
+                               graph->printAllMethodInfo(true);
+               }
+               return;
+       }
+
+       bool pass = false;
+       if (graph->hasCycle()) {
+               /* One more trace with a cycle */
+               stats->cyclicCnt++;
+               if (!checkCyclic) {
+                       if (!quiet)
+                               graph->print();
+                       if (print_always && !quiet) { // By default not printing
+                               model_print("Execution #%d has a cyclic graph.\n\n",
+                                       execution->get_execution_number());
+                       }
+               } else {
+                       if (print_always && !quiet) {
+                               model_print("Checking cyclic execution #%d...\n",
+                                       execution->get_execution_number());
+                       }
+                       pass = graph->checkCyclicGraphSpec(print_always && !quiet);
+               }
+       } else if (checkRandomNum > 0) { // Only a few random histories
+               if (print_always && !quiet)
+                       model_print("Check %d random histories...\n", checkRandomNum);
+               pass = graph->checkRandomHistories(checkRandomNum, true, print_always && !quiet);
+       } else { // Check all histories 
+               if (print_always && !quiet)
+                       model_print("Check all histories...\n");
+               pass = graph->checkAllHistories(true, print_always && !quiet);
+       }
+
+       if (!pass) {
+               /* One more failed trace */
+               stats->failedCnt++;
+               model_print("Execution #%d failed.\n\n",
+                       execution->get_execution_number());
+       } else {
+               /* One more passing trace */
+               stats->passCnt++;
+
+               if (print_always && !quiet) { // By default not printing
+                       model_print("Execution #%d passed.\n\n",
+                               execution->get_execution_number());
+               }
+       }
+}
diff --git a/spec-analysis/specanalysis.h b/spec-analysis/specanalysis.h
new file mode 100644 (file)
index 0000000..1c77156
--- /dev/null
@@ -0,0 +1,77 @@
+#ifndef _SPECANALYSIS_H
+#define _SPECANALYSIS_H
+
+#include <stack>
+
+#include "traceanalysis.h"
+#include "mymemory.h"
+#include "modeltypes.h"
+#include "action.h"
+
+struct spec_stats {
+       /** The number of traces that have passed the checking */
+       unsigned passCnt;
+
+       /** The number of inadmissible traces */
+       unsigned inadmissibilityCnt;
+       
+       /** The number of all checked traces */
+       unsigned traceCnt;
+
+       /** The number of traces with a cyclic graph */
+       unsigned cyclicCnt;
+
+       /** The number of traces with broken graphs */
+       unsigned brokenCnt;
+
+       /** The number of traces with graphs that has no ordering points */
+       unsigned noOrderingPointCnt;
+
+       /** The number of traces that failed */
+       unsigned failedCnt;
+       
+       /** The number of buggy and bug-free traces (by CDSChecker) */
+       unsigned buggyCnt;
+       unsigned bugfreeCnt;
+};
+
+class SPECAnalysis : public TraceAnalysis {
+ public:
+       SPECAnalysis();
+       ~SPECAnalysis();
+
+       virtual void setExecution(ModelExecution * execution);
+       virtual void analyze(action_list_t *actions);
+       virtual const char * name();
+       virtual bool option(char *);
+       virtual void finish();
+
+       /** Some stats */
+       spec_stats *stats;
+
+       SNAPSHOTALLOC
+ private:
+       /** The execution */
+       ModelExecution *execution;
+
+       /** A few useful options */
+       /* Print out the graphs of all executions */
+       bool print_always;
+       /* Print out the graphs of the inadmissible traces */
+       bool print_inadmissible;
+       /* Never print out the graphs of any traces */
+       bool quiet;
+       /* Whether we still want to check cyclic executions */
+       bool checkCyclic;
+       /* Stop checking when seeing one failed history */
+       bool stopOnFail;
+       /* The number of random histories to be checked; If 0, we check all possible
+        * histories */
+       int checkRandomNum;
+       
+       /** Whether this is a "check-12" like option */
+       bool isCheckRandomHistories(char *opt, int &num);
+};
+
+
+#endif
diff --git a/spec-analysis/specannotation.cc b/spec-analysis/specannotation.cc
new file mode 100644 (file)
index 0000000..84a9795
--- /dev/null
@@ -0,0 +1,96 @@
+#include <algorithm> 
+#include "specannotation.h"
+#include "cdsannotate.h"
+
+/**********    Annotations    **********/
+
+SpecAnnotation::SpecAnnotation(SpecAnnoType type, const void *anno) : type(type),
+       annotation(anno) { }
+               
+
+CommutativityRule::CommutativityRule(CSTR method1, CSTR method2, CSTR rule,
+       CheckCommutativity_t condition) : method1(method1),
+       method2(method2), rule(rule), condition(condition) {}
+
+bool CommutativityRule::isRightRule(Method m1, Method m2) {
+       return (m1->name == method1 && m2->name == method2) ||
+               (m1->name == method2 && m2->name == method1);
+}
+       
+bool CommutativityRule::checkCondition(Method m1, Method m2) {
+       if (m1->name == method1 && m2->name == method2)
+               return (*condition)(m1, m2);
+       else if (m1->name == method2 && m2->name == method1)
+               return (*condition)(m2, m1);
+       else // The checking should only be called on the right rule
+               ASSERT(false);
+               return false;
+}
+
+NamedFunction::NamedFunction(CSTR name, CheckFunctionType type, void *function) : name(name),
+       type(type), function(function) { }
+
+StateFunctions::StateFunctions(NamedFunction *transition, NamedFunction
+       *preCondition, NamedFunction * justifyingPrecondition,
+    NamedFunction *justifyingPostcondition,
+       NamedFunction *postCondition, NamedFunction *print) : transition(transition),
+       preCondition(preCondition), justifyingPrecondition(justifyingPrecondition),
+    justifyingPostcondition(justifyingPostcondition),
+       postCondition(postCondition), print(print) { }
+
+
+AnnoInit::AnnoInit(NamedFunction *initial, NamedFunction *final, NamedFunction
+       *copy, NamedFunction *clear, NamedFunction *printState, CommutativityRule
+       *commuteRules, int ruleNum) : initial(initial), final(final), copy(copy),
+       clear(clear), printState(printState), commuteRules(commuteRules),
+       commuteRuleNum(ruleNum)
+{
+       funcMap = new StateFuncMap;
+}
+       
+
+void AnnoInit::addInterfaceFunctions(CSTR name, StateFunctions *funcs) {
+       funcMap->put(name, funcs);
+}
+
+AnnoInterfaceInfo::AnnoInterfaceInfo(CSTR name) : name(name), value(NULL) { }
+
+
+/**********    Universal functions for rewriting the program    **********/
+
+AnnoInterfaceInfo* _createInterfaceBeginAnnotation(CSTR name) {
+       AnnoInterfaceInfo *info = new AnnoInterfaceInfo(name);
+       // Create and instrument with the INTERFACE_BEGIN annotation
+       cdsannotate(SPEC_ANALYSIS, new SpecAnnotation(INTERFACE_BEGIN, info));
+       return info;
+}
+
+void _createInterfaceEndAnnotation(CSTR name) {
+       // Create and instrument with the INTERFACE_END annotation
+       cdsannotate(SPEC_ANALYSIS, new SpecAnnotation(INTERFACE_END, (void*) name));
+}
+
+
+void _setInterfaceBeginAnnotationValue(AnnoInterfaceInfo *info, void *value) {
+       info->value = value;
+}
+
+void _createOPDefineAnnotation() {
+       cdsannotate(SPEC_ANALYSIS, new SpecAnnotation(OP_DEFINE, NULL));
+}
+
+void _createPotentialOPAnnotation(CSTR label) {
+       cdsannotate(SPEC_ANALYSIS, new SpecAnnotation(POTENTIAL_OP, label));
+}
+
+void _createOPCheckAnnotation(CSTR label) {
+       cdsannotate(SPEC_ANALYSIS, new SpecAnnotation(OP_CHECK, label));
+}
+
+void _createOPClearAnnotation() {
+       cdsannotate(SPEC_ANALYSIS, new SpecAnnotation(OP_CLEAR, NULL));
+}
+
+void _createOPClearDefineAnnotation() {
+       cdsannotate(SPEC_ANALYSIS, new SpecAnnotation(OP_CLEAR_DEFINE, NULL));
+}
diff --git a/spec-analysis/specannotation.h b/spec-analysis/specannotation.h
new file mode 100644 (file)
index 0000000..5ab80ef
--- /dev/null
@@ -0,0 +1,230 @@
+#ifndef _SPECANNOTATION_H
+#define _SPECANNOTATION_H
+
+#include "modeltypes.h"
+#include "model-assert.h"
+#include "methodcall.h"
+#include "action.h"
+#include "spec_common.h"
+#include "hashtable.h"
+
+using namespace std;
+
+/** 
+       We can only pass a void* pointer from the real program execution to the
+       checking engine, so we need to wrap the key information into that pointer.
+       We use the SpecAnntotation struct to represent that info. Different types
+       here mean different annotations.
+
+       FIXME: Currently we actually do not need to have the INTERFACE_END types. We
+       basically wrap the MethodCall* pointer of the method call in the
+       INTERFACE_BEGIN type of annotation.
+*/
+typedef enum SpecAnnoType {
+       INIT, POTENTIAL_OP, OP_DEFINE, OP_CHECK, OP_CLEAR, OP_CLEAR_DEFINE,
+       INTERFACE_BEGIN, INTERFACE_END
+} SpecAnnoType;
+
+inline CSTR specAnnoType2Str(SpecAnnoType type) {
+       switch (type) {
+               case INIT:
+                       return "INIT";
+               case POTENTIAL_OP:
+                       return "POTENTIAL_OP";
+               case OP_DEFINE:
+                       return "OP_DEFINE";
+               case OP_CHECK:
+                       return "OP_CHECK";
+               case OP_CLEAR:
+                       return "OP_CLEAR";
+               case OP_CLEAR_DEFINE:
+                       return "OP_CLEAR_DEFINE";
+               case INTERFACE_BEGIN:
+                       return "INTERFACE_BEGIN";
+               case INTERFACE_END:
+                       return "INTERFACE_END";
+               default:
+                       return "UNKNOWN_TYPE";
+       }
+}
+
+typedef
+struct SpecAnnotation {
+       SpecAnnoType type;
+       const void *annotation;
+
+       SpecAnnotation(SpecAnnoType type, const void *anno);
+
+} SpecAnnotation;
+
+typedef bool (*CheckCommutativity_t)(Method, Method);
+/**
+       The first method is the target (to update its state), and the second method
+       is the method that should be executed (to access its method call info (ret
+       & args)
+*/
+typedef bool (*StateTransition_t)(Method, Method);
+typedef bool (*CheckState_t)(Method, Method);
+typedef void (*UpdateState_t)(Method);
+// Copy the second state to the first state
+typedef void (*CopyState_t)(Method, Method);
+
+/**
+       This struct contains a commutativity rule: two method calls represented by
+       two unique integers and a function that takes two "info" pointers (with the
+       return value and the arguments) and returns a boolean to represent whether
+       the two method calls are commutable.
+*/
+typedef
+struct CommutativityRule {
+       CSTR method1;
+       CSTR method2;
+
+       /** The plain text of the rule (debugging purpose) */
+       CSTR rule;
+       CheckCommutativity_t condition;
+
+       CommutativityRule(CSTR method1, CSTR method2, CSTR rule,
+               CheckCommutativity_t condition);
+
+       bool isRightRule(Method m1, Method m2);
+       
+       bool checkCondition(Method m1, Method m2);
+
+} CommutativityRule;
+
+typedef enum CheckFunctionType {
+    INITIAL, COPY, CLEAR, FINAL, PRINT_STATE, TRANSITION, PRE_CONDITION,
+    JUSTIFYING_PRECONDITION, SIDE_EFFECT, JUSTIFYING_POSTCONDITION,
+    POST_CONDITION, PRINT_VALUE
+} CheckFunctionType;
+
+typedef struct NamedFunction {
+       CSTR name;
+       CheckFunctionType type;
+       void *function;
+
+       /**
+               StateTransition_t transition;
+               CheckState_t preCondition;
+               CheckState_t postCondition;
+       */
+       NamedFunction(CSTR name, CheckFunctionType type, void *function);
+} NamedFunction;
+
+typedef
+struct StateFunctions {
+       NamedFunction *transition;
+       NamedFunction *preCondition;
+       NamedFunction *justifyingPrecondition;
+       NamedFunction *justifyingPostcondition;
+       NamedFunction *postCondition;
+       NamedFunction *print;
+
+       StateFunctions(NamedFunction *transition, NamedFunction *preCondition,
+               NamedFunction *justifyingPrecondition,
+        NamedFunction *justifyingPostcondition,
+        NamedFunction *postCondition, NamedFunction *print);
+
+} StateFunctions;
+
+/** A map from a constant c-string to its set of checking functions */
+typedef HashTable<CSTR, StateFunctions*, uintptr_t, 4, malloc, calloc, free > StateFuncMap;
+
+typedef
+struct AnnoInit {
+       /**
+               For the initialization of a state; We actually assume there are two
+               special nodes --- INITIAL & FINAL. They actually have a special
+               MethodCall class representing these two nodes, and their interface name
+               would be INITIAL and FINAL. For the initial function, we actually also
+               use it as the state copy function when evaluating the state of other
+               method calls
+
+               UpdateState_t --> initial
+       */
+       NamedFunction *initial;
+
+       /**
+               TODO: Currently we just have this "final" field, which was supposed to
+               be a final checking function after all method call nodes have been
+               executed on the graph. However, before we think it through, this might
+               potentially be a violation of composability
+
+               CheckState_t --> final;
+       */
+       NamedFunction *final;
+       
+       /**
+               For copying out an existing state from a previous method call
+
+               CopyState_t --> copy 
+       */
+       NamedFunction *copy;
+
+       /**
+               For clearing out an existing state object
+
+               UpdateState_t --> delete 
+       */
+       NamedFunction *clear;
+
+       
+       /**
+               For printing out the state 
+
+               UpdateState_t --> printState
+       */
+       NamedFunction *printState;
+
+       /** For the state functions. We can conveniently access to the set of state
+        *  functions with a hashmap */
+       StateFuncMap *funcMap;
+       
+       /** For commutativity rules */
+       CommutativityRule *commuteRules;
+       int commuteRuleNum;
+
+       AnnoInit(NamedFunction *initial, NamedFunction *final, NamedFunction *copy,
+               NamedFunction *clear, NamedFunction *printState, CommutativityRule
+               *commuteRules, int ruleNum);
+                       
+       void addInterfaceFunctions(CSTR name, StateFunctions *funcs);
+
+} AnnoInit;
+
+typedef
+struct AnnoInterfaceInfo {
+       CSTR name;
+       void *value;
+
+       AnnoInterfaceInfo(CSTR name); 
+} AnnoInterfaceInfo;
+
+/**********    Universal functions for rewriting the program    **********/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+AnnoInterfaceInfo* _createInterfaceBeginAnnotation(CSTR name);
+
+void _createInterfaceEndAnnotation(CSTR name);
+
+void _setInterfaceBeginAnnotationValue(AnnoInterfaceInfo *info, void *value);
+
+void _createOPDefineAnnotation();
+
+void _createPotentialOPAnnotation(CSTR label);
+
+void _createOPCheckAnnotation(CSTR label);
+
+void _createOPClearAnnotation();
+
+void _createOPClearDefineAnnotation();
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif
diff --git a/test-cdsspec/Makefile b/test-cdsspec/Makefile
new file mode 100644 (file)
index 0000000..e875ad3
--- /dev/null
@@ -0,0 +1,19 @@
+DIRS := ms-queue linuxrwlocks mcs-lock \
+       chase-lev-deque-bugfix ticket-lock seqlock read-copy-update \
+       concurrent-hashmap spsc-bugfix mpmc-queue
+
+.PHONY: $(DIRS)
+
+all: $(DIRS)
+
+clean: $(DIRS:%=clean-%)
+cleanse: $(DIRS:%=cleanse-%)
+
+$(DIRS):
+       $(MAKE) -C $@
+
+clean-%:
+       -$(MAKE) -C $* clean
+
+cleanse-%: 
+       -$(MAKE) -C $* cleanse
diff --git a/test-cdsspec/benchmarks.mk b/test-cdsspec/benchmarks.mk
new file mode 100644 (file)
index 0000000..0a160ff
--- /dev/null
@@ -0,0 +1,41 @@
+# A few common Makefile items
+
+CC = gcc
+CXX = g++
+
+UNAME = $(shell uname)
+
+LIB_NAME = model
+LIB_SO = lib$(LIB_NAME).so
+
+BASE = ../..
+INCLUDE = -I$(BASE) -I$(BASE)/include -I../include -I$(BASE)/spec-analysis/include
+
+# C preprocessor flags
+CPPFLAGS += $(INCLUDE) -O3 -g
+
+# C++ compiler flags
+CXXFLAGS += $(CPPFLAGS)
+
+# C compiler flags
+CFLAGS += $(CPPFLAGS)
+
+# Linker flags
+LDFLAGS += -L$(BASE) -l$(LIB_NAME) -rdynamic
+
+# Mac OSX options
+ifeq ($(UNAME), Darwin)
+MACFLAGS = -D_XOPEN_SOURCE -DMAC
+CPPFLAGS += $(MACFLAGS)
+CXXFLAGS += $(MACFLAGS)
+CFLAGS += $(MACFLAGS)
+LDFLAGS += $(MACFLAGS)
+endif
+
+
+CDSSPEC_NAME = cdsspec-generated
+CDSSPEC = $(CDSSPEC_NAME).o
+
+$(CDSSPEC): $(CDSSPEC_NAME).cc
+       $(CXX) -MMD -MF .$@.d -o $@ -fPIC -c $< $(CXXFLAGS) -I$(BASE)/spec-analysis -std=c++11 $(LDFLAGS)
+
diff --git a/test-cdsspec/chase-lev-deque-bugfix/Makefile b/test-cdsspec/chase-lev-deque-bugfix/Makefile
new file mode 100644 (file)
index 0000000..8d24681
--- /dev/null
@@ -0,0 +1,24 @@
+BENCH := deque
+
+TESTS := main testcase1 testcase2 testcase3
+
+all: $(TESTS)
+
+# Should include it after "all"; otherwise it will only make cdsspec-generated.o
+include ../benchmarks.mk
+
+%.o : %.c 
+       $(CC) -fPIC -c -MMD -MF .$@.d -o $@ $< $(CPPFLAGS) $(LDFLAGS)
+
+$(TESTS): % : %.o $(BENCH).o $(CDSSPEC)
+       $(CXX) -o $@ $^ $(CPPFLAGS) $(LDFLAGS)
+
+-include .*.d
+
+clean:
+       rm -rf $(TESTS) *.o .*.d *.dSYM
+
+cleanse: clean 
+       rm -rf *.c *.cc *.h
+
+.PHONY: clean all cleanse
diff --git a/test-cdsspec/cleanse.sh b/test-cdsspec/cleanse.sh
new file mode 100755 (executable)
index 0000000..f98ed91
--- /dev/null
@@ -0,0 +1,12 @@
+#!/bin/bash
+#
+
+BENCHS=(ms-queue linuxrwlocks mcs-lock chase-lev-deque-bugfix \ 
+    ticket-lock seqlock read-copy-update concurrent-hashmap spsc-bugfix \
+    mpmc-queue)
+
+for i in ${BENCHS[*]}; do
+    echo "Cleansing $i..."
+    echo "rm -rf $i/*.c $i/*.cc $i/*.h $i/*.o $i/main $i/testcase* $i/.*.d"
+    rm -rf $i/*.c $i/*.cc $i/*.h $i/*.o $i/main $i/testcase* $i/.*.d
+done
diff --git a/test-cdsspec/concurrent-hashmap/Makefile b/test-cdsspec/concurrent-hashmap/Makefile
new file mode 100644 (file)
index 0000000..7a71c5f
--- /dev/null
@@ -0,0 +1,24 @@
+BENCH := hashmap
+
+TESTS := main testcase1 testcase2
+
+all: $(TESTS)
+
+# Should include it after "all"; otherwise it will only make cdsspec-generated.o
+include ../benchmarks.mk
+
+%.o : %.cc 
+       $(CXX) -fPIC -c -MMD -MF .$@.d -o $@ $< $(CXXFLAGS) $(LDFLAGS)
+
+$(TESTS) : % : %.o $(BENCH).o $(CDSSPEC)
+       $(CXX) -MMD -MF .$@.d -o $@ $^ $(CXXFLAGS) $(LDFLAGS)
+
+-include .*.d
+
+clean:
+       rm -rf $(TESTS) *.o .*.d *.dSYM
+
+cleanse: clean 
+       rm -rf *.c *.cc *.h
+
+.PHONY: clean all cleanse
diff --git a/test-cdsspec/include/unrelacy.h b/test-cdsspec/include/unrelacy.h
new file mode 100644 (file)
index 0000000..c6369e0
--- /dev/null
@@ -0,0 +1,103 @@
+#ifndef __UNRELACY_H__
+#define __UNRELACY_H__
+
+#include <stdatomic.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <mutex>
+#include <condition_variable>
+
+#include <model-assert.h>
+#include <librace.h>
+
+#define $
+#ifndef ASSRT
+#define ASSERT(expr) MODEL_ASSERT(expr)
+#endif
+#define RL_ASSERT(expr) MODEL_ASSERT(expr)
+
+#define RL_NEW new
+#define RL_DELETE(expr) delete expr
+
+#define mo_seqcst memory_order_seq_cst
+#define mo_release memory_order_release
+#define mo_acquire memory_order_acquire
+#define mo_acq_rel memory_order_acq_rel
+#define mo_relaxed memory_order_relaxed
+
+#define seq_cst memory_order_seq_cst
+#define release memory_order_release
+#define acquire memory_order_acquire
+#define acq_rel memory_order_acq_rel
+#define relaxed memory_order_relaxed
+
+namespace rl {
+
+       /* This 'useless' struct is declared just so we can use partial template
+        * specialization in our store and load functions. */
+       template <typename T, size_t n>
+       struct useless {
+               static void store(void *addr, T val);
+               static T load(const void *addr);
+       };
+
+       template <typename T>
+       struct useless<T, 1> {
+               static void store(void *addr, T val) { store_8(addr, (uint8_t)val); }
+               static T load(const void *addr) { return (T)load_8(addr); }
+       };
+
+       template <typename T>
+       struct useless<T, 2> {
+               static void store(void *addr, T val) { store_16(addr, (uint16_t)val); }
+               static T load(const void *addr) { return (T)load_16(addr); }
+       };
+
+       template <typename T>
+       struct useless<T, 4> {
+               static void store(void *addr, T val) { store_32(addr, (uint32_t)val); }
+               static T load(const void *addr) { return (T)load_32(addr); }
+       };
+
+       template <typename T>
+       struct useless<T, 8> {
+               static void store(void *addr, T val) { store_64(addr, (uint64_t)val); }
+               static T load(const void *addr) { return (T)load_64(addr); }
+       };
+
+       template <typename T>
+       struct var {
+               var() { useless<T, sizeof(T)>::store(&value, 0); }
+               var(T v) { useless<T, sizeof(T)>::store(&value, v); }
+               var(var const& r) {
+                       value = r.value;
+               }
+               ~var() { }
+
+               void operator = (T v) { useless<T, sizeof(T)>::store(&value, v); }
+               T operator () () { return useless<T, sizeof(T)>::load(&value); }
+               void operator += (T v) {
+                       useless<T, sizeof(T)>::store(&value,
+                                       useless<T, sizeof(T)>::load(&value) + v);
+               }
+               bool operator == (const struct var<T> v) const { return useless<T, sizeof(T)>::load(&value) == useless<T, sizeof(T)>::load(&v.value); }
+
+               T value;
+       };
+
+       class backoff_t
+       {
+        public:
+               typedef int debug_info_param;
+               void yield(debug_info_param info) { }
+               void yield() { }
+       };
+
+
+       typedef backoff_t backoff;
+       typedef backoff_t linear_backoff;
+       typedef backoff_t exp_backoff;
+
+}
+
+#endif /* __UNRELACY_H__ */
diff --git a/test-cdsspec/linuxrwlocks/Makefile b/test-cdsspec/linuxrwlocks/Makefile
new file mode 100644 (file)
index 0000000..1686ff9
--- /dev/null
@@ -0,0 +1,24 @@
+BENCH := linuxrwlocks
+
+TESTS := main testcase1 testcase2 testcase3
+
+all: $(TESTS) 
+
+# Should include it after "all"; otherwise it will only make cdsspec-generated.o 
+include ../benchmarks.mk
+
+%.o : %.c 
+       $(CC) -fPIC -c -MMD -MF .$@.d -o $@ $< $(CPPFLAGS) $(LDFLAGS)
+
+$(TESTS): % : %.o $(BENCH).o $(CDSSPEC)
+       $(CXX) -o $@ $^ $(CPPFLAGS) $(LDFLAGS)
+
+-include .*.d
+
+clean:
+       rm -rf $(TESTS) *.o .*.d *.dSYM
+
+cleanse: clean 
+       rm -rf *.c *.cc *.h
+
+.PHONY: clean all cleanse
diff --git a/test-cdsspec/mcs-lock/Makefile b/test-cdsspec/mcs-lock/Makefile
new file mode 100644 (file)
index 0000000..cf21474
--- /dev/null
@@ -0,0 +1,24 @@
+BENCH := mcs-lock
+
+TESTS := main testcase
+
+all: $(TESTS)
+
+# Should include it after "all"; otherwise it will only make cdsspec-generated.o
+include ../benchmarks.mk
+
+%.o : %.cc 
+       $(CXX) -fPIC -c -MMD -MF .$@.d -o $@ $< $(CXXFLAGS) $(LDFLAGS)
+
+$(TESTS) : % : %.o $(BENCH).o $(CDSSPEC)
+       $(CXX) -MMD -MF .$@.d -o $@ $^ $(CXXFLAGS) $(LDFLAGS)
+
+-include .*.d
+
+clean:
+       rm -rf $(TESTS) *.o .*.d *.dSYM
+
+cleanse: clean 
+       rm -rf *.c *.cc *.h
+
+.PHONY: clean all cleanse
diff --git a/test-cdsspec/mpmc-queue/Makefile b/test-cdsspec/mpmc-queue/Makefile
new file mode 100644 (file)
index 0000000..23255e1
--- /dev/null
@@ -0,0 +1,24 @@
+BENCH := mpmc-queue
+
+TESTS := main testcase1 testcase2
+
+all: $(TESTS)
+
+# Should include it after "all"; otherwise it will only make cdsspec-generated.o
+include ../benchmarks.mk
+
+%.o : %.cc 
+       $(CXX) -fPIC -c -MMD -MF .$@.d -o $@ $< $(CXXFLAGS) $(LDFLAGS)
+
+$(TESTS) : % : %.o $(BENCH).o $(CDSSPEC)
+       $(CXX) -MMD -MF .$@.d -o $@ $^ $(CXXFLAGS) $(LDFLAGS)
+
+-include .*.d
+
+clean:
+       rm -rf $(TESTS) *.o .*.d *.dSYM
+
+cleanse: clean 
+       rm -rf *.c *.cc *.h
+
+.PHONY: clean all cleanse
diff --git a/test-cdsspec/ms-queue/.gitignore b/test-cdsspec/ms-queue/.gitignore
new file mode 100644 (file)
index 0000000..71e596d
--- /dev/null
@@ -0,0 +1,8 @@
+main
+testcase1
+testcase2
+testcase3
+testcase4
+*.dSYM/
+*.o
+.*.d
diff --git a/test-cdsspec/ms-queue/Makefile b/test-cdsspec/ms-queue/Makefile
new file mode 100644 (file)
index 0000000..84558a4
--- /dev/null
@@ -0,0 +1,24 @@
+BENCH := queue
+
+TESTS := main testcase1 testcase2 testcase3 testcase4
+
+all: $(TESTS)
+
+# Should include it after "all"; otherwise it will only make cdsspec-generated.o
+include ../benchmarks.mk
+
+%.o : %.c 
+       $(CC) -fPIC -c -MMD -MF .$@.d -o $@ $< $(CPPFLAGS) $(LDFLAGS)
+
+$(TESTS): % : %.o $(BENCH).o $(CDSSPEC)
+       $(CXX) -o $@ $^ $(CPPFLAGS) $(LDFLAGS)
+
+-include .*.d
+
+clean:
+       rm -rf $(TESTS) *.o .*.d *.dSYM
+
+cleanse: clean 
+       rm -rf *.c *.cc *.h
+
+.PHONY: clean all cleanse
diff --git a/test-cdsspec/performance.sh b/test-cdsspec/performance.sh
new file mode 100755 (executable)
index 0000000..a9d3313
--- /dev/null
@@ -0,0 +1,20 @@
+#!/bin/bash
+#
+
+if [[ $# -gt 0 ]]; then
+       BENCHS=($1)
+else
+       BENCHS=(ms-queue linuxrwlocks mcs-lock chase-lev-deque-bugfix \ 
+               ticket-lock seqlock read-copy-update concurrent-hashmap spsc-bugfix \
+               mpmc-queue)
+fi
+
+echo ${BENCHS[*]}
+for i in ${BENCHS[*]}; do
+       if [ -e "$i/main" ]; then
+               echo "----------    Start to run the main for $i    ----------"
+               time ./run.sh $i/main -m2 -y -u3 -tSPEC
+       else
+               echo "No main for $i."
+       fi
+done
diff --git a/test-cdsspec/read-copy-update/Makefile b/test-cdsspec/read-copy-update/Makefile
new file mode 100644 (file)
index 0000000..402a91c
--- /dev/null
@@ -0,0 +1,24 @@
+BENCH := rcu
+
+TESTS := main testcase
+
+all: $(TESTS)
+
+# Should include it after "all"; otherwise it will only make cdsspec-generated.o
+include ../benchmarks.mk
+
+%.o : %.cc 
+       $(CXX) -fPIC -c -MMD -MF .$@.d -o $@ $< $(CXXFLAGS) $(LDFLAGS)
+
+$(TESTS) : % : %.o $(BENCH).o $(CDSSPEC)
+       $(CXX) -MMD -MF .$@.d -o $@ $^ $(CXXFLAGS) $(LDFLAGS)
+
+-include .*.d
+
+clean:
+       rm -rf $(TESTS) *.o .*.d *.dSYM
+
+cleanse: clean 
+       rm -rf *.c *.cc *.h
+
+.PHONY: clean all cleanse
diff --git a/test-cdsspec/run-all.sh b/test-cdsspec/run-all.sh
new file mode 100755 (executable)
index 0000000..76c59e6
--- /dev/null
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+
+BENCHS=(ms-queue linuxrwlocks mcs-lock chase-lev-deque-bugfix treiber-stack
+       ticket-lock seqlock read-copy-update concurrent-hashmap spsc-bugfix mpmc-queue)
+
+echo ${BENCHS[*]}
+for i in ${BENCHS[*]}; do
+       echo "----------    Start to run $i    ----------"
+       tests=$(ls $i/testcase[1-9])
+       if [ -e "$i/main" ]; then
+               tests=($tests "$i/main")
+       fi
+       if [ -e "$i/testcase" ]; then
+               tests=($tests "$i/testcase")
+       fi
+
+       for j in ${tests[*]}; do
+               ./run.sh $j -m2 -y -u3 -tSPEC
+       done
+done
diff --git a/test-cdsspec/run.sh b/test-cdsspec/run.sh
new file mode 100755 (executable)
index 0000000..7f554e7
--- /dev/null
@@ -0,0 +1,28 @@
+#!/bin/sh
+#
+# Runs a simple test (default: ./barrier/barrier)
+# Syntax:
+#  ./run.sh [test program] [OPTIONS]
+#  ./run.sh [OPTIONS]
+#  ./run.sh [gdb [test program]]
+#
+# If you include a 'gdb' argument, the your program will be launched with gdb.
+# You can also supply a test program argument to run something besides the
+# default program.
+#
+
+# Get the directory in which this script is located
+BINDIR="${0%/*}"
+
+BIN=${BINDIR}/barrier/barrier
+PREFIX=
+
+export LD_LIBRARY_PATH=${BINDIR}/..
+# For Mac OSX
+export DYLD_LIBRARY_PATH=${BINDIR}/..
+
+[ $# -gt 0 ] && [ "$1" = "gdb" ] && PREFIX=gdb && shift
+[ $# -gt 0 ] && [ -e "$1" ] && BIN="$1" && shift
+
+set -xe
+$PREFIX $BIN $@
diff --git a/test-cdsspec/seqlock/Makefile b/test-cdsspec/seqlock/Makefile
new file mode 100644 (file)
index 0000000..5126b4d
--- /dev/null
@@ -0,0 +1,24 @@
+BENCH := seqlock
+
+TESTS := main testcase1 testcase2
+
+all: $(TESTS)
+
+# Should include it after "all"; otherwise it will only make cdsspec-generated.o
+include ../benchmarks.mk
+
+%.o : %.cc 
+       $(CXX) -fPIC -c -MMD -MF .$@.d -o $@ $< $(CXXFLAGS) $(LDFLAGS)
+
+$(TESTS) : % : %.o $(BENCH).o $(CDSSPEC)
+       $(CXX) -MMD -MF .$@.d -o $@ $^ $(CXXFLAGS) $(LDFLAGS)
+
+-include .*.d
+
+clean:
+       rm -rf $(TESTS) *.o .*.d *.dSYM
+
+cleanse: clean 
+       rm -rf *.c *.cc *.h
+
+.PHONY: clean all cleanse
diff --git a/test-cdsspec/spsc-bugfix/Makefile b/test-cdsspec/spsc-bugfix/Makefile
new file mode 100644 (file)
index 0000000..cf60b94
--- /dev/null
@@ -0,0 +1,24 @@
+BENCH := queue
+
+TESTS := main testcase1
+
+all: $(TESTS)
+
+# Should include it after "all"; otherwise it will only make cdsspec-generated.o
+include ../benchmarks.mk
+
+%.o : %.cc 
+       $(CXX) -fPIC -c -MMD -MF .$@.d -o $@ $< $(CXXFLAGS) $(LDFLAGS)
+
+$(TESTS) : % : %.o $(BENCH).o $(CDSSPEC)
+       $(CXX) -MMD -MF .$@.d -o $@ $^ $(CXXFLAGS) $(LDFLAGS)
+
+-include .*.d
+
+clean:
+       rm -rf $(TESTS) *.o .*.d *.dSYM
+
+cleanse: clean 
+       rm -rf *.c *.cc *.h
+
+.PHONY: clean all cleanse
diff --git a/test-cdsspec/ticket-lock/Makefile b/test-cdsspec/ticket-lock/Makefile
new file mode 100644 (file)
index 0000000..ac461a1
--- /dev/null
@@ -0,0 +1,24 @@
+BENCH := lock
+
+TESTS := main testcase1
+
+all: $(TESTS) 
+
+# Should include it after "all"; otherwise it will only make cdsspec-generated.o 
+include ../benchmarks.mk
+
+%.o : %.c 
+       $(CC) -fPIC -c -MMD -MF .$@.d -o $@ $< $(CPPFLAGS) $(LDFLAGS)
+
+$(TESTS): % : %.o $(BENCH).o $(CDSSPEC)
+       $(CXX) -o $@ $^ $(CPPFLAGS) $(LDFLAGS)
+
+-include .*.d
+
+clean:
+       rm -rf $(TESTS) *.o .*.d *.dSYM
+
+cleanse: clean 
+       rm -rf *.c *.cc *.h
+
+.PHONY: clean all cleanse
index 9d7acb0894b7db264e5b4bd4e90a61cff6be0a27..8f19b465b13b7c6c6e7c6fcca05e4d3804956dc4 100644 (file)
@@ -11,13 +11,14 @@ include $(DIR)/Makefile
 DEPS := $(join $(addsuffix ., $(dir $(OBJECTS))), $(addsuffix .d, $(notdir $(OBJECTS))))
 
 CPPFLAGS += -I$(BASE) -I$(BASE)/include
+CFLAGS += -I$(BASE) -I$(BASE)/include
 
 all: $(OBJECTS)
 
 -include $(DEPS)
 
 %.o: %.c
-       $(CC) -MMD -MF $(@D)/.$(@F).d -o $@ $< $(CPPFLAGS) -L$(BASE) -l$(LIB_NAME)
+       $(CC) -MMD -MF $(@D)/.$(@F).d -o $@ $< $(CFLAGS) -L$(BASE) -l$(LIB_NAME)
 
 %.o: %.cc
        $(CXX) -MMD -MF $(@D)/.$(@F).d -o $@ $< $(CPPFLAGS) -L$(BASE) -l$(LIB_NAME)
diff --git a/test/iriw.cc b/test/iriw.cc
deleted file mode 100644 (file)
index fddbf1a..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-/**
- * @file iriw.cc
- * @brief Independent read and independent write test
- */
-
-#include <atomic>
-#include <threads.h>
-#include <stdio.h>
-
-#include "wildcard.h"
-#include "model-assert.h"
-
-using namespace std;
-
-atomic_int x, y;
-int r1, r2, r3, r4; /* "local" variables */
-
-static void a(void *obj)
-{
-       x.store(1, memory_order_seq_cst);
-}
-
-static void b(void *obj)
-{
-       y.store(1, memory_order_seq_cst);
-}
-
-static void c(void *obj)
-{
-       r1 = x.load(memory_order_acquire);
-       r2 = y.load(memory_order_seq_cst);
-}
-
-static void d(void *obj)
-{
-       r3 = y.load(memory_order_acquire);
-       r4 = x.load(memory_order_seq_cst);
-}
-
-
-int user_main(int argc, char **argv)
-{
-       thrd_t t1, t2, t3, t4;
-
-       atomic_init(&x, 0);
-       atomic_init(&y, 0);
-
-       printf("Main thread: creating 4 threads\n");
-       thrd_create(&t1, (thrd_start_t)&a, NULL);
-       thrd_create(&t2, (thrd_start_t)&b, NULL);
-       thrd_create(&t3, (thrd_start_t)&c, NULL);
-       thrd_create(&t4, (thrd_start_t)&d, NULL);
-
-       thrd_join(t1);
-       thrd_join(t2);
-       thrd_join(t3);
-       thrd_join(t4);
-       printf("Main thread is finished\n");
-
-       /*
-        * This condition should not be hit if the execution is SC */
-       bool sc = (r1 == 1 && r2 == 0 && r3 == 1 && r4 == 0);
-       printf("r1 = %d, r2 = %d, r3 = %d and r4 = %d\n", r1, r2, r3, r4);
-       MODEL_ASSERT(!sc);
-       return 0;
-}
diff --git a/test/iriw_wildcard.cc b/test/iriw_wildcard.cc
deleted file mode 100644 (file)
index 5c52455..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-/**
- * @file iriw.cc
- * @brief Independent read and independent write test
- */
-
-#include <atomic>
-#include <threads.h>
-#include <stdio.h>
-
-#include "wildcard.h"
-#include "model-assert.h"
-
-using namespace std;
-
-atomic_int x, y;
-int r1, r2, r3, r4; /* "local" variables */
-
-static void a(void *obj)
-{
-       x.store(1, wildcard(1));
-}
-
-static void b(void *obj)
-{
-       y.store(1, wildcard(2));
-}
-
-static void c(void *obj)
-{
-       r1 = x.load(wildcard(3));
-       r2 = y.load(wildcard(4));
-}
-
-static void d(void *obj)
-{
-       r3 = y.load(wildcard(5));
-       r4 = x.load(wildcard(6));
-}
-
-
-int user_main(int argc, char **argv)
-{
-       thrd_t t1, t2, t3, t4;
-
-       atomic_init(&x, 0);
-       atomic_init(&y, 0);
-
-       printf("Main thread: creating 4 threads\n");
-       thrd_create(&t1, (thrd_start_t)&a, NULL);
-       thrd_create(&t2, (thrd_start_t)&b, NULL);
-       thrd_create(&t3, (thrd_start_t)&c, NULL);
-       thrd_create(&t4, (thrd_start_t)&d, NULL);
-
-       thrd_join(t1);
-       thrd_join(t2);
-       thrd_join(t3);
-       thrd_join(t4);
-       printf("Main thread is finished\n");
-
-       /*
-        * This condition should not be hit if the execution is SC */
-       bool sc = (r1 == 1 && r2 == 0 && r3 == 1 && r4 == 0);
-       //MODEL_ASSERT(!sc);
-
-       return 0;
-}
index a06af84636978f1bbd31f960c0c2368d79fc609a..a0bc02970aa9ff71c6e8e1a04f6565d52b6db43a 100644 (file)
 /** Allocate a stack for a new thread. */
 static void * stack_allocate(size_t size)
 {
-       return Thread_malloc(size);
+       return snapshot_malloc(size);
 }
 
 /** Free a stack for a terminated thread. */
 static void stack_free(void *stack)
 {
-       Thread_free(stack);
+       snapshot_free(stack);
 }
 
 /**
index d363150ab3c72e2c3efcd46a2b8dd7d88dd970a8..df3356ad50d422c08a3a2ba7d09234ccec394f5f 100644 (file)
@@ -2,7 +2,6 @@
 #define TRACE_ANALYSIS_H
 #include "model.h"
 
-
 class TraceAnalysis {
  public:
        /** setExecution is called once after installation with a reference to
@@ -31,20 +30,6 @@ class TraceAnalysis {
 
        virtual void finish() = 0;
 
-       /** This method is used to inspect the normal/abnormal model
-        * action. */
-       virtual void inspectModelAction(ModelAction *act) {}
-
-       /** This method will be called by when a plugin is installed by the
-        * model checker. */
-       virtual void actionAtInstallation() {}
-
-       /** This method will be called when the model checker finishes the
-        * executions; With this method, the model checker can alter the
-        * state of the plugin and then the plugin can choose whether or not
-        * restart the model checker. */
-       virtual void actionAtModelCheckingFinish() {}
-
        SNAPSHOTALLOC
 };
 #endif