Skip to content
Snippets Groups Projects
Commit 322a4f54 authored by Etienne Kneuss's avatar Etienne Kneuss Committed by Philippe Suter
Browse files

Basis for compiled expressions

parent 36e65536
No related branches found
No related tags found
No related merge requests found
...@@ -15,45 +15,13 @@ object CodeGenPhase extends LeonPhase[Program,CompilationResult] { ...@@ -15,45 +15,13 @@ object CodeGenPhase extends LeonPhase[Program,CompilationResult] {
def run(ctx : LeonContext)(p : Program) : CompilationResult = { def run(ctx : LeonContext)(p : Program) : CompilationResult = {
import CodeGeneration._ import CodeGeneration._
// This sets up an environment where all classes and all functions have names. CompilationUnit.compileProgram(p) match {
implicit val env = CompilationEnvironment.fromProgram(p) case Some(unit) =>
unit.writeClassFiles()
for((parent,children) <- p.algebraicDataTypes) { CompilationResult(successful = true)
val acf = compileAbstractClassDef(p, parent) case None =>
val ccfs = children.map(c => compileCaseClassDef(p, c)) CompilationResult(successful = false)
}
val mainClassName = defToJVMName(p, p.mainObject)
val cf = new ClassFile(mainClassName, None)
cf.addDefaultConstructor
cf.setFlags((
CLASS_ACC_SUPER |
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)) : _*
)
m.setFlags((
METHOD_ACC_PUBLIC |
METHOD_ACC_FINAL |
METHOD_ACC_STATIC
).asInstanceOf[U2])
CodeGeneration.compileFunDef(funDef, m.codeHandler)
} }
cf.writeToFile(mainClassName + ".class")
CompilationResult(successful = true)
} }
} }
...@@ -46,7 +46,7 @@ object CodeGeneration { ...@@ -46,7 +46,7 @@ object CodeGeneration {
ch.freeze ch.freeze
} }
private def mkExpr(e : Expr, ch : CodeHandler)(implicit env : CompilationEnvironment) { private[codegen] def mkExpr(e : Expr, ch : CodeHandler)(implicit env : CompilationEnvironment) {
e match { e match {
case Variable(id) => case Variable(id) =>
val slot = slotFor(id) val slot = slotFor(id)
...@@ -151,7 +151,7 @@ object CodeGeneration { ...@@ -151,7 +151,7 @@ object CodeGeneration {
} }
} }
private def mkBranch(cond : Expr, then : String, elze : String, ch : CodeHandler)(implicit env : CompilationEnvironment) { private[codegen] def mkBranch(cond : Expr, then : String, elze : String, ch : CodeHandler)(implicit env : CompilationEnvironment) {
cond match { cond match {
case BooleanLiteral(true) => case BooleanLiteral(true) =>
ch << Goto(then) ch << Goto(then)
...@@ -189,22 +189,22 @@ object CodeGeneration { ...@@ -189,22 +189,22 @@ object CodeGeneration {
mkExpr(l, ch) mkExpr(l, ch)
mkExpr(r, ch) mkExpr(r, ch)
ch << If_ICmpLt(then) << Goto(elze) ch << If_ICmpLt(then) << Goto(elze)
case GreaterThan(l,r) => case GreaterThan(l,r) =>
mkExpr(l, ch) mkExpr(l, ch)
mkExpr(r, ch) mkExpr(r, ch)
ch << If_ICmpGt(then) << Goto(elze) ch << If_ICmpGt(then) << Goto(elze)
case LessEquals(l,r) => case LessEquals(l,r) =>
mkExpr(l, ch) mkExpr(l, ch)
mkExpr(r, ch) mkExpr(r, ch)
ch << If_ICmpLe(then) << Goto(elze) ch << If_ICmpLe(then) << Goto(elze)
case GreaterEquals(l,r) => case GreaterEquals(l,r) =>
mkExpr(l, ch) mkExpr(l, ch)
mkExpr(r, ch) mkExpr(r, ch)
ch << If_ICmpGe(then) << Goto(elze) ch << If_ICmpGe(then) << Goto(elze)
// WARNING !!! mkBranch delegates to mkExpr, and mkExpr delegates to mkBranch ! // WARNING !!! mkBranch delegates to mkExpr, and mkExpr delegates to mkBranch !
// That means, between the two of them, they'd better know what to generate ! // That means, between the two of them, they'd better know what to generate !
case other => case other =>
...@@ -213,7 +213,7 @@ object CodeGeneration { ...@@ -213,7 +213,7 @@ object CodeGeneration {
} }
} }
private def slotFor(id : Identifier)(implicit env : CompilationEnvironment) : Int = { private[codegen] def slotFor(id : Identifier)(implicit env : CompilationEnvironment) : Int = {
env.varToLocal(id).getOrElse { env.varToLocal(id).getOrElse {
throw CompilationException("Unknown variable : " + id) throw CompilationException("Unknown variable : " + id)
} }
......
package leon
package codegen
import purescala.Common._
import purescala.Definitions._
import purescala.Trees._
import purescala.TypeTrees._
import cafebabe._
import cafebabe.AbstractByteCodes._
import cafebabe.ByteCodes._
import cafebabe.ClassFileTypes._
import cafebabe.Flags._
import CodeGeneration._
class CompilationUnit(val p: Program, val mainClass: ClassFile, implicit val env: CompilationEnvironment) {
val mainClassName = defToJVMName(p, p.mainObject)
val loader = new CafebabeClassLoader
def writeClassFiles() {
mainClass.writeToFile(mainClassName + ".class")
}
private var _nextExprId = 0
def nextExprId = {
_nextExprId += 1
_nextExprId
}
def groundExprToJava(e: Expr): AnyRef = {
null
}
def javaToGroundExpr(e: AnyRef): Expr = {
null
}
def compileExpression(e: Expr, args: Seq[Identifier]): CompiledExpression = {
val id = nextExprId
val cName = "Leon$CodeGen$Expr$"+id
val cf = new ClassFile(cName, None)
cf.setFlags((
CLASS_ACC_PUBLIC |
CLASS_ACC_FINAL
).asInstanceOf[U2])
cf.addDefaultConstructor
val m = cf.addMethod(
typeToJVM(e.getType),
"eval",
args.map(a => typeToJVM(a.getType)) : _*
)
m.setFlags((
METHOD_ACC_PUBLIC |
METHOD_ACC_FINAL |
METHOD_ACC_STATIC
).asInstanceOf[U2])
val ch = m.codeHandler
val newMapping = args.zipWithIndex.toMap
val exprToCompile = purescala.TreeOps.matchToIfThenElse(e)
mkExpr(e, ch)(env.withVars(newMapping))
e.getType match {
case Int32Type | BooleanType =>
ch << IRETURN
case UnitType | TupleType(_) | SetType(_) | MapType(_, _) =>
ch << ARETURN
case other =>
throw CompilationException("Unsupported return type : " + other)
}
ch.freeze
loader.register(cf)
new CompiledExpression(this, cf, args)
}
}
object CompilationUnit {
def compileProgram(p: Program): Option[CompilationUnit] = {
implicit val env = CompilationEnvironment.fromProgram(p)
for((parent,children) <- p.algebraicDataTypes) {
val acf = compileAbstractClassDef(p, parent)
val ccfs = children.map(c => compileCaseClassDef(p, c))
}
val mainClassName = defToJVMName(p, p.mainObject)
val cf = new ClassFile(mainClassName, None)
cf.addDefaultConstructor
cf.setFlags((
CLASS_ACC_SUPER |
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)) : _*
)
m.setFlags((
METHOD_ACC_PUBLIC |
METHOD_ACC_FINAL |
METHOD_ACC_STATIC
).asInstanceOf[U2])
compileFunDef(funDef, m.codeHandler)
}
Some(new CompilationUnit(p, cf, env))
}
}
package leon
package codegen
import purescala.Common._
import purescala.Definitions._
import purescala.Trees._
import purescala.TypeTrees._
import cafebabe._
import cafebabe.AbstractByteCodes._
import cafebabe.ByteCodes._
import cafebabe.ClassFileTypes._
import cafebabe.Flags._
class CompiledExpression(unit: CompilationUnit, cf: ClassFile, argsDecl: Seq[Identifier]) {
def eval(args: Seq[Expr]): Expr = {
val cl = unit.loader.loadClass(cf.className)
val obj = cl.newInstance()
val meth = cl.getMethods()(0)
val res = meth.invoke(obj, args.map(unit.groundExprToJava))
unit.javaToGroundExpr(res)
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment