diff --git a/src/main/resources/runtime/runtime.h b/src/main/resources/runtime/runtime.h index 308e464..c50e74f 100644 --- a/src/main/resources/runtime/runtime.h +++ b/src/main/resources/runtime/runtime.h @@ -43,8 +43,9 @@ int numSccs = 0; struct FreeCell *freeList = NULL; /** For dropping objects that never get assigned anywhere */ -void drop(Common *obj, void (*decrRC)(void *)) { - obj->rc ++; +void drop(Common *obj, void (*decrRC)(void *)) +{ + obj->rc++; decrRC(obj); } @@ -135,25 +136,39 @@ void collectFreeList() void processAllPCRs() { - for (int scc = 0; scc < numSccs; scc ++) + for (int scc = 0; scc < numSccs; scc++) { - markGrayAllPCRs(pcrBuckets[scc]); - scanAllPCRs(pcrBuckets[scc]); + for (struct PCR *curr = pcrBuckets[scc]; curr != NULL; curr = curr->next) + { + curr->markGray(curr->obj); + } + for (struct PCR *curr = pcrBuckets[scc]; curr != NULL; curr = curr->next) + { + curr->scan(curr->obj); + } if (freeList != NULL) { fprintf(stderr, "Free list should be null\n"); exit(1); } - collectWhiteAllPCRs(pcrBuckets[scc]); + struct PCR *curr = pcrBuckets[scc]; + while (curr != NULL) + { + curr->collectWhite(curr->obj); + struct PCR *next = curr->next; + free(curr); + curr = next; + } pcrBuckets[scc] = NULL; collectFreeList(); } } // From https://stackoverflow.com/a/14783909/11882002 -static inline u_int64_t rdtscp() { - u_int64_t rax,rdx; +static inline u_int64_t rdtscp() +{ + u_int64_t rax, rdx; u_int32_t aux; - asm volatile ( "rdtscp\n" : "=a" (rax), "=d" (rdx), "=c" (aux) : : ); + asm volatile("rdtscp\n" : "=a"(rax), "=d"(rdx), "=c"(aux) : :); return (rdx << 32) + rax; } diff --git a/src/main/scala/fred/AST.scala b/src/main/scala/fred/AST.scala index 109cdb2..1047853 100644 --- a/src/main/scala/fred/AST.scala +++ b/src/main/scala/fred/AST.scala @@ -1,9 +1,6 @@ package fred -case class Span(start: Int, end: Int) { - override def toString = - if (start == -1 && end == -1) "(:)" else s"($start:$end)" -} +case class Span(start: Int, end: Int) object Span { @@ -11,9 +8,7 @@ object Span { def synth = Span(-1, -1) } -case class Spanned[T](value: T, span: Span) { - override def toString: String = value.toString -} +case class Spanned[T](value: T, span: Span) case class ParsedFile(typeDefs: List[TypeDef], fns: List[FnDef]) diff --git a/src/main/scala/fred/Compiler.scala b/src/main/scala/fred/Compiler.scala index 2a05578..58d5e67 100644 --- a/src/main/scala/fred/Compiler.scala +++ b/src/main/scala/fred/Compiler.scala @@ -76,9 +76,10 @@ object Compiler { .getResourceAsStream(RuntimeHeader) val io = ProcessIO( in => { - in.write(runtimeHeader.readAllBytes()) + in.write(generated.getBytes()) + // in.write(runtimeHeader.readAllBytes()) // TODO removing #include runtime.h is a horrendous hack - in.write(generated.replaceAll("#include \"runtime.h\"", "").getBytes()) + // in.write(generated.replaceAll("#include \"runtime.h\"", "").getBytes()) in.close() }, out => print(String(out.readAllBytes())), @@ -88,9 +89,16 @@ object Compiler { val extraIncludes = if (settings.includeMemcheck) "-I /usr/include/valgrind" else "" - assert(s"gcc $extraIncludes -o $outExe -x c -".run(io).exitValue() == 0) + assert(s"gcc -g -I ${includesFolder()} $extraIncludes -o $outExe -x c -".run(io).exitValue() == 0) File(outExe).setExecutable(true) runtimeHeader.close() } + + /** Path to the folder with header files to include */ + private def includesFolder(): String = { + val runtimeFile = this.getClass().getClassLoader() + .getResource(RuntimeHeader).toURI() + java.nio.file.Paths.get(runtimeFile).getParent().toString() + } } diff --git a/src/test/scala/fred/FuzzTests.scala b/src/test/scala/fred/FuzzTests.scala index 9ade8f6..1eda832 100644 --- a/src/test/scala/fred/FuzzTests.scala +++ b/src/test/scala/fred/FuzzTests.scala @@ -8,6 +8,8 @@ import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks import org.scalacheck.Gen import org.scalatest.tagobjects.Slow import org.scalacheck.Shrink +import org.scalacheck.Gen.Parameters +import org.scalacheck.rng.Seed import fred.Compiler.Settings import fred.GenUtil.{GenStmt, GeneratedProgram} @@ -60,6 +62,272 @@ class FuzzTests } } + val gen = GeneratedProgram( + List( + TypeDef( + Spanned("OptT0", Span.synth), + List( + EnumCase( + Spanned("SomeT0", Span.synth), + List(FieldDef(false, Spanned("value", Span.synth), TypeRef("T0", Span.synth), Span.synth)), + Span.synth + ), + EnumCase(Spanned("NoneT0", Span.synth), List(), Span.synth) + ), + Span.synth + ), + TypeDef( + Spanned("OptT1", Span.synth), + List( + EnumCase( + Spanned("SomeT1", Span.synth), + List(FieldDef(false, Spanned("value", Span.synth), TypeRef("T1", Span.synth), Span.synth)), + Span.synth + ), + EnumCase(Spanned("NoneT1", Span.synth), List(), Span.synth) + ), + Span.synth + ), + TypeDef( + Spanned("OptT2", Span.synth), + List( + EnumCase( + Spanned("SomeT2", Span.synth), + List(FieldDef(false, Spanned("value", Span.synth), TypeRef("T2", Span.synth), Span.synth)), + Span.synth + ), + EnumCase(Spanned("NoneT2", Span.synth), List(), Span.synth) + ), + Span.synth + ), + TypeDef( + Spanned("T2", Span.synth), + List(EnumCase( + Spanned("T2", Span.synth), + List( + FieldDef(false, Spanned("f3", Span.synth), TypeRef("T1", Span.synth), Span.synth), + FieldDef(true, Spanned("f1", Span.synth), TypeRef("OptT2", Span.synth), Span.synth), + FieldDef(true, Spanned("f6", Span.synth), TypeRef("OptT2", Span.synth), Span.synth), + FieldDef(true, Spanned("f10", Span.synth), TypeRef("OptT2", Span.synth), Span.synth), + FieldDef(true, Spanned("f4", Span.synth), TypeRef("OptT0", Span.synth), Span.synth), + FieldDef(true, Spanned("f2", Span.synth), TypeRef("OptT2", Span.synth), Span.synth), + FieldDef(false, Spanned("f0", Span.synth), TypeRef("T1", Span.synth), Span.synth), + FieldDef(true, Spanned("f11", Span.synth), TypeRef("OptT2", Span.synth), Span.synth), + FieldDef(true, Spanned("f7", Span.synth), TypeRef("OptT0", Span.synth), Span.synth), + FieldDef(true, Spanned("f8", Span.synth), TypeRef("OptT0", Span.synth), Span.synth), + FieldDef(true, Spanned("f9", Span.synth), TypeRef("OptT2", Span.synth), Span.synth), + FieldDef(true, Spanned("f5", Span.synth), TypeRef("OptT2", Span.synth), Span.synth) + ), + Span.synth + )), + Span.synth + ), + TypeDef( + Spanned("T0", Span.synth), + List(EnumCase( + Spanned("T0", Span.synth), + List( + FieldDef(true, Spanned("f0", Span.synth), TypeRef("OptT0", Span.synth), Span.synth), + FieldDef(true, Spanned("f1", Span.synth), TypeRef("OptT2", Span.synth), Span.synth) + ), + Span.synth + )), + Span.synth + ), + TypeDef( + Spanned("T1", Span.synth), + List(EnumCase( + Spanned("T1", Span.synth), + List(FieldDef(true, Spanned("f0", Span.synth), TypeRef("OptT1", Span.synth), Span.synth)), + Span.synth + )), + Span.synth + ) + ), + Map( + "vT2_1" -> "T2", + "vT1_1" -> "T1", + "vT0_3" -> "T0", + "vT0_0" -> "T0", + "vT0_1" -> "T0", + "vT1_3" -> "T1", + "vT2_0" -> "T2", + "vT0_2" -> "T0", + "vT2_2" -> "T2", + "vT1_0" -> "T1", + "vT1_2" -> "T1", + "vT2_3" -> "T2" + ), + List( + ( + "vT0_3", + CtorCall( + Spanned("T0", Span.synth), + List( + (Spanned("f0", Span.synth), CtorCall(Spanned("NoneT0", Span.synth), List(), Span.synth)), + (Spanned("f1", Span.synth), CtorCall(Spanned("NoneT2", Span.synth), List(), Span.synth)) + ), + Span.synth + ) + ), + ( + "vT2_1", + CtorCall( + Spanned("T2", Span.synth), + List( + (Spanned("f3", Span.synth), VarRef("vT1_2", Span.synth)), + (Spanned("f1", Span.synth), CtorCall(Spanned("NoneT2", Span.synth), List(), Span.synth)), + (Spanned("f6", Span.synth), CtorCall(Spanned("NoneT2", Span.synth), List(), Span.synth)), + (Spanned("f10", Span.synth), CtorCall(Spanned("NoneT2", Span.synth), List(), Span.synth)), + (Spanned("f4", Span.synth), CtorCall(Spanned("NoneT0", Span.synth), List(), Span.synth)), + (Spanned("f2", Span.synth), CtorCall(Spanned("NoneT2", Span.synth), List(), Span.synth)), + (Spanned("f0", Span.synth), VarRef("vT1_2", Span.synth)), + (Spanned("f11", Span.synth), CtorCall(Spanned("NoneT2", Span.synth), List(), Span.synth)), + (Spanned("f7", Span.synth), CtorCall(Spanned("NoneT0", Span.synth), List(), Span.synth)), + (Spanned("f8", Span.synth), CtorCall(Spanned("NoneT0", Span.synth), List(), Span.synth)), + (Spanned("f9", Span.synth), CtorCall(Spanned("NoneT2", Span.synth), List(), Span.synth)), + (Spanned("f5", Span.synth), CtorCall(Spanned("NoneT2", Span.synth), List(), Span.synth)) + ), + Span.synth + ) + ), + ( + "vT0_1", + CtorCall( + Spanned("T0", Span.synth), + List( + (Spanned("f0", Span.synth), CtorCall(Spanned("NoneT0", Span.synth), List(), Span.synth)), + (Spanned("f1", Span.synth), CtorCall(Spanned("NoneT2", Span.synth), List(), Span.synth)) + ), + Span.synth + ) + ), + ( + "vT2_3", + CtorCall( + Spanned("T2", Span.synth), + List( + (Spanned("f3", Span.synth), VarRef("vT1_0", Span.synth)), + (Spanned("f1", Span.synth), CtorCall(Spanned("NoneT2", Span.synth), List(), Span.synth)), + (Spanned("f6", Span.synth), CtorCall(Spanned("NoneT2", Span.synth), List(), Span.synth)), + (Spanned("f10", Span.synth), CtorCall(Spanned("NoneT2", Span.synth), List(), Span.synth)), + (Spanned("f4", Span.synth), CtorCall(Spanned("NoneT0", Span.synth), List(), Span.synth)), + (Spanned("f2", Span.synth), CtorCall(Spanned("NoneT2", Span.synth), List(), Span.synth)), + (Spanned("f0", Span.synth), VarRef("vT1_1", Span.synth)), + (Spanned("f11", Span.synth), CtorCall(Spanned("NoneT2", Span.synth), List(), Span.synth)), + (Spanned("f7", Span.synth), CtorCall(Spanned("NoneT0", Span.synth), List(), Span.synth)), + (Spanned("f8", Span.synth), CtorCall(Spanned("NoneT0", Span.synth), List(), Span.synth)), + (Spanned("f9", Span.synth), CtorCall(Spanned("NoneT2", Span.synth), List(), Span.synth)), + (Spanned("f5", Span.synth), CtorCall(Spanned("NoneT2", Span.synth), List(), Span.synth)) + ), + Span.synth + ) + ), + ( + "vT2_0", + CtorCall( + Spanned("T2", Span.synth), + List( + (Spanned("f3", Span.synth), VarRef("vT1_3", Span.synth)), + (Spanned("f1", Span.synth), CtorCall(Spanned("NoneT2", Span.synth), List(), Span.synth)), + (Spanned("f6", Span.synth), CtorCall(Spanned("NoneT2", Span.synth), List(), Span.synth)), + (Spanned("f10", Span.synth), CtorCall(Spanned("NoneT2", Span.synth), List(), Span.synth)), + (Spanned("f4", Span.synth), CtorCall(Spanned("NoneT0", Span.synth), List(), Span.synth)), + (Spanned("f2", Span.synth), CtorCall(Spanned("NoneT2", Span.synth), List(), Span.synth)), + (Spanned("f0", Span.synth), VarRef("vT1_2", Span.synth)), + (Spanned("f11", Span.synth), CtorCall(Spanned("NoneT2", Span.synth), List(), Span.synth)), + (Spanned("f7", Span.synth), CtorCall(Spanned("NoneT0", Span.synth), List(), Span.synth)), + (Spanned("f8", Span.synth), CtorCall(Spanned("NoneT0", Span.synth), List(), Span.synth)), + (Spanned("f9", Span.synth), CtorCall(Spanned("NoneT2", Span.synth), List(), Span.synth)), + (Spanned("f5", Span.synth), CtorCall(Spanned("NoneT2", Span.synth), List(), Span.synth)) + ), + Span.synth + ) + ), + ( + "vT2_2", + CtorCall( + Spanned("T2", Span.synth), + List( + (Spanned("f3", Span.synth), VarRef("vT1_2", Span.synth)), + (Spanned("f1", Span.synth), CtorCall(Spanned("NoneT2", Span.synth), List(), Span.synth)), + (Spanned("f6", Span.synth), CtorCall(Spanned("NoneT2", Span.synth), List(), Span.synth)), + (Spanned("f10", Span.synth), CtorCall(Spanned("NoneT2", Span.synth), List(), Span.synth)), + (Spanned("f4", Span.synth), CtorCall(Spanned("NoneT0", Span.synth), List(), Span.synth)), + (Spanned("f2", Span.synth), CtorCall(Spanned("NoneT2", Span.synth), List(), Span.synth)), + (Spanned("f0", Span.synth), VarRef("vT1_1", Span.synth)), + (Spanned("f11", Span.synth), CtorCall(Spanned("NoneT2", Span.synth), List(), Span.synth)), + (Spanned("f7", Span.synth), CtorCall(Spanned("NoneT0", Span.synth), List(), Span.synth)), + (Spanned("f8", Span.synth), CtorCall(Spanned("NoneT0", Span.synth), List(), Span.synth)), + (Spanned("f9", Span.synth), CtorCall(Spanned("NoneT2", Span.synth), List(), Span.synth)), + (Spanned("f5", Span.synth), CtorCall(Spanned("NoneT2", Span.synth), List(), Span.synth)) + ), + Span.synth + ) + ), + ( + "vT0_0", + CtorCall( + Spanned("T0", Span.synth), + List( + (Spanned("f0", Span.synth), CtorCall(Spanned("NoneT0", Span.synth), List(), Span.synth)), + (Spanned("f1", Span.synth), CtorCall(Spanned("NoneT2", Span.synth), List(), Span.synth)) + ), + Span.synth + ) + ), + ( + "vT0_2", + CtorCall( + Spanned("T0", Span.synth), + List( + (Spanned("f0", Span.synth), CtorCall(Spanned("NoneT0", Span.synth), List(), Span.synth)), + (Spanned("f1", Span.synth), CtorCall(Spanned("NoneT2", Span.synth), List(), Span.synth)) + ), + Span.synth + ) + ), + ( + "vT1_0", + CtorCall( + Spanned("T1", Span.synth), + List((Spanned("f0", Span.synth), CtorCall(Spanned("NoneT1", Span.synth), List(), Span.synth))), + Span.synth + ) + ), + ( + "vT1_1", + CtorCall( + Spanned("T1", Span.synth), + List((Spanned("f0", Span.synth), CtorCall(Spanned("NoneT1", Span.synth), List(), Span.synth))), + Span.synth + ) + ), + ( + "vT1_2", + CtorCall( + Spanned("T1", Span.synth), + List((Spanned("f0", Span.synth), CtorCall(Spanned("NoneT1", Span.synth), List(), Span.synth))), + Span.synth + ) + ), + ( + "vT1_3", + CtorCall( + Spanned("T1", Span.synth), + List((Spanned("f0", Span.synth), CtorCall(Spanned("NoneT1", Span.synth), List(), Span.synth))), + Span.synth + ) + ) + ), + List( + GenStmt.Assign("vT0_3", "f0", "T0", "vT0_1"), + GenStmt.Assign("vT0_1", "f0", "T0", "vT0_1"), + GenStmt.ValgrindCheck, + GenStmt.Assign("vT0_0", "f0", "T0", "vT0_3") + ) + ) + property("With intermediate checks", Slow) { given PropertyCheckConfiguration = PropertyCheckConfiguration(minSize = 5, sizeRange = 40) @@ -99,23 +367,25 @@ class FuzzTests ) } - forAll(genFull) { generated => - ExecTests.valgrindCheck( - generated.asAst, - None, - None, - save = Some("blech-1234sd.c"), - settings = Settings(includeMemcheck = true), - processC = c => { - // TODO make lexical lifetimes or whatever they're called a setting in - // the compiler instead of this buffoonery - // Remove all $decr_TX calls for the variables at the end (but not $decr_OptTX calls) - // because we're calling $decr_TX ourselves above - val (beforeMain, afterMain) = c.splitAt(c.indexOf("int main")) - beforeMain + - afterMain.replaceAll(""" \$decr_T\d+\(vT\d+_\d+\);\n""", "") - } - ) + //forAll(genFull.apply(Parameters.default, Seed(6529581269390504088L)).get) { + forAll(Gen.const(gen)) { + generated => + ExecTests.valgrindCheck( + generated.asAst, + None, + None, + save = Some("blech-1234sd.c"), + settings = Settings(includeMemcheck = true), + processC = c => { + // TODO make lexical lifetimes or whatever they're called a setting in + // the compiler instead of this buffoonery + // Remove all $decr_TX calls for the variables at the end (but not $decr_OptTX calls) + // because we're calling $decr_TX ourselves above + val (beforeMain, afterMain) = c.splitAt(c.indexOf("int main")) + beforeMain + + afterMain.replaceAll(""" \$decr_T\d+\(vT\d+_\d+\);\n""", "") + } + ) } } } diff --git a/src/test/scala/fred/GenUtil.scala b/src/test/scala/fred/GenUtil.scala index 431fd06..f1c3bd6 100644 --- a/src/test/scala/fred/GenUtil.scala +++ b/src/test/scala/fred/GenUtil.scala @@ -78,7 +78,7 @@ object GenUtil { } given shrinkGenerated: Shrink[GeneratedProgram] = Shrink { prog => - if (prog.stmts.isEmpty) Stream.empty + if (prog.stmts.isEmpty || true) Stream.empty else { Shrink.shrink(prog.stmts)(Shrink.shrinkContainer) .map(stmts => prog.copy(stmts = stmts)) @@ -116,7 +116,7 @@ object GenUtil { val decrLhs = if (remVars.contains(lhs)) List(decrRc(lhs, varTypes(lhs))) else Nil val decrRhs = - if (remVars.contains(rhs)) List(decrRc(rhs, varTypes(rhs))) else Nil + if (lhs != rhs && remVars.contains(rhs)) List(decrRc(rhs, varTypes(rhs))) else Nil (stmt.asAst :: decrLhs ::: decrRhs ::: next, remVars - lhs - rhs) case stmt :: rest => val (next, remVars) = rec(rest)