diff --git a/src/main/scala/leon/codegen/CodeGen.scala b/src/main/scala/leon/codegen/CodeGen.scala deleted file mode 100644 index 7f84a897682d716f751f12dbdb68cdf00f9466de..0000000000000000000000000000000000000000 --- a/src/main/scala/leon/codegen/CodeGen.scala +++ /dev/null @@ -1,14 +0,0 @@ -package leon -package codegen - -import purescala.Common._ -import purescala.Definitions._ - -object CodeGenPhase extends LeonPhase[Program,CompilationResult] { - val name = "CodeGen" - val description = "Compiles a Leon program into Java methods" - - def run(ctx : LeonContext)(p : Program) : CompilationResult = { - CompilationResult(successful = true) - } -} diff --git a/src/main/scala/leon/codegen/CodeGenPhase.scala b/src/main/scala/leon/codegen/CodeGenPhase.scala new file mode 100644 index 0000000000000000000000000000000000000000..5c6c0ef16dabd3dd2b1ddafdb7d0b54fffd36f88 --- /dev/null +++ b/src/main/scala/leon/codegen/CodeGenPhase.scala @@ -0,0 +1,43 @@ +package leon +package codegen + +import purescala.Common._ +import purescala.Definitions._ + +import cafebabe._ +import cafebabe.ClassFileTypes.U2 +import cafebabe.Flags._ + +object CodeGenPhase extends LeonPhase[Program,CompilationResult] { + val name = "CodeGen" + val description = "Compiles a Leon program into Java methods" + + def run(ctx : LeonContext)(p : Program) : CompilationResult = { + import CodeGeneration._ + + implicit val env = CompilationEnvironment.fromProgram(p) + + val cName = programToClassName(p) + + val cf = new ClassFile(cName, None) + cf.setFlags( + (cf.getFlags | CLASS_ACC_PUBLIC | CLASS_ACC_FINAL).asInstanceOf[U2] + ) + + // This assumes that all functions of a given program get compiled + // as methods of a single class file. + for(funDef <- p.definedFunctions; + (_,mn) <- env.funDefToMethod(funDef)) { + + val m = cf.addMethod( + typeToJVM(funDef.returnType), + mn, + funDef.args.map(a => typeToJVM(a.tpe)) : _* + ) + + CodeGeneration.compileFunDef(funDef, m.codeHandler) + } + + CompilationResult(successful = true) + } +} diff --git a/src/main/scala/leon/codegen/CodeGeneration.scala b/src/main/scala/leon/codegen/CodeGeneration.scala new file mode 100644 index 0000000000000000000000000000000000000000..3fd57a438a86c5bf2ac669f7de0ff19ce8041188 --- /dev/null +++ b/src/main/scala/leon/codegen/CodeGeneration.scala @@ -0,0 +1,61 @@ +package leon +package codegen + +import purescala.Common._ +import purescala.Definitions._ +import purescala.Trees._ +import purescala.TypeTrees._ + +import cafebabe._ +import cafebabe.ByteCodes._ +import cafebabe.AbstractByteCodes._ + +object CodeGeneration { + def programToClassName(p : Program) : String = "Leon$CodeGen$" + p.mainObject.id.uniqueName + + def typeToJVM(tpe : TypeTree)(implicit env : CompilationEnvironment) : String = tpe match { + case Int32Type => "I" + case BooleanType => "Z" + case _ => throw CompilationException("Unsupported type : " + tpe) + } + + // Assumes the CodeHandler has never received any bytecode. + // Generates method body, and freezes the handler at the end. + def compileFunDef(funDef : FunDef, ch : CodeHandler)(implicit env : CompilationEnvironment) { + // TODO, change environment to include args. + mkExpr(funDef.getBody, ch) + + funDef.returnType match { + case Int32Type | BooleanType => + ch << IRETURN + + case other => + throw CompilationException("Unsupported return type : " + other) + } + + ch.freeze + } + + private def mkExpr(e : Expr, ch : CodeHandler)(implicit env : CompilationEnvironment) { + e match { + case IntLiteral(v) => ch << Ldc(v) + case BooleanLiteral(true) => ch << Ldc(1) + case BooleanLiteral(false) => ch << Ldc(0) + + case Plus(l, r) => + mkExpr(l, ch) + mkExpr(r, ch) + ch << IADD + + case Minus(l, r) => + mkExpr(l, ch) + mkExpr(r, ch) + ch << ISUB + + case UMinus(e) => + mkExpr(Minus(IntLiteral(0), e), ch) + + case _ => throw CompilationException("Unsupported expr : " + e) + } + } +} diff --git a/src/main/scala/leon/codegen/CompilationEnvironment.scala b/src/main/scala/leon/codegen/CompilationEnvironment.scala new file mode 100644 index 0000000000000000000000000000000000000000..1eb9514e1a81e8b615928f6b9f5da0a10d0b4557 --- /dev/null +++ b/src/main/scala/leon/codegen/CompilationEnvironment.scala @@ -0,0 +1,27 @@ +package leon +package codegen + +import purescala.Common._ +import purescala.Definitions._ + +abstract class CompilationEnvironment() { + // Should contain: + // - a mapping of function defs to class + method name + // - a mapping of class defs to class names + // - a mapping of class fields to fields + + def funDefToMethod(funDef : FunDef) : Option[(String,String)] +} + +object CompilationEnvironment { + def fromProgram(p : Program) : CompilationEnvironment = { + val className = CodeGeneration.programToClassName(p) + + val fs = p.definedFunctions.filter(_.hasImplementation) + val fPairs : Map[FunDef,String] = fs.map(fd => (fd -> fd.id.uniqueName)).toMap + + new CompilationEnvironment { + def funDefToMethod(funDef : FunDef) = fPairs.get(funDef).map(n => (className, n)) + } + } +} diff --git a/src/main/scala/leon/codegen/CompilationException.scala b/src/main/scala/leon/codegen/CompilationException.scala new file mode 100644 index 0000000000000000000000000000000000000000..236cc586e64b487170ba7f80377d8e690742c120 --- /dev/null +++ b/src/main/scala/leon/codegen/CompilationException.scala @@ -0,0 +1,6 @@ +package leon +package codegen + +case class CompilationException(msg : String) extends Exception { + override def getMessage = msg +} diff --git a/src/test/resources/regression/codegen/purescala/Prog001.scala b/src/test/resources/regression/codegen/purescala/Prog001.scala index c0eb52647720910e8f9a43c19a3af4f88c10261b..c0edc779fbcba95cec98102a9a4699fbbc12ef80 100644 --- a/src/test/resources/regression/codegen/purescala/Prog001.scala +++ b/src/test/resources/regression/codegen/purescala/Prog001.scala @@ -1,3 +1,5 @@ object Prog001 { - def plus(x : Int, y : Int) : Int = x + y + def fortyTwo() = 42 + + // def plus(x : Int, y : Int) = x + y } diff --git a/unmanaged/32/cafebabe_2.9.2-1.2.jar b/unmanaged/32/cafebabe_2.9.2-1.2.jar index 57defc82adbd3db0baa2f7bfe33f08f1ee2f9e38..a7f91ed1b7e26933e0b0c657dbd2f240a423dc50 100644 Binary files a/unmanaged/32/cafebabe_2.9.2-1.2.jar and b/unmanaged/32/cafebabe_2.9.2-1.2.jar differ