diff --git a/src/main/scala/leon/codegen/CodeGenPhase.scala b/src/main/scala/leon/codegen/CodeGenPhase.scala
index 5c6c0ef16dabd3dd2b1ddafdb7d0b54fffd36f88..bfd072b88b39650a60fcc14f2f3794e40a2f93d0 100644
--- a/src/main/scala/leon/codegen/CodeGenPhase.scala
+++ b/src/main/scala/leon/codegen/CodeGenPhase.scala
@@ -20,24 +20,35 @@ object CodeGenPhase extends LeonPhase[Program,CompilationResult] {
     val cName = programToClassName(p)
 
     val cf = new ClassFile(cName, None)
-    cf.setFlags(
-      (cf.getFlags | CLASS_ACC_PUBLIC | CLASS_ACC_FINAL).asInstanceOf[U2]
-    )
+    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)) {
+        (_,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(cName + ".class")
+
     CompilationResult(successful = true)
   } 
 }
diff --git a/src/main/scala/leon/codegen/CodeGeneration.scala b/src/main/scala/leon/codegen/CodeGeneration.scala
index 3fd57a438a86c5bf2ac669f7de0ff19ce8041188..7c55ac76c0de58ceba686919ad0c808d13a4d144 100644
--- a/src/main/scala/leon/codegen/CodeGeneration.scala
+++ b/src/main/scala/leon/codegen/CodeGeneration.scala
@@ -22,8 +22,8 @@ object CodeGeneration {
   // 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)
+    val newMapping = funDef.args.map(_.id).zipWithIndex.toMap
+    mkExpr(funDef.getBody, ch)(env.withVars(newMapping))
 
     funDef.returnType match {
       case Int32Type | BooleanType =>
@@ -38,9 +38,52 @@ object CodeGeneration {
 
   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 Variable(id) =>
+        val slot = slotFor(id)
+        val instr = id.getType match {
+          case Int32Type | BooleanType => ILoad(slot)
+          case _ => ALoad(slot)
+        }
+        ch << instr
+
+      case Let(i,d,b) =>
+        mkExpr(d, ch)
+        val slot = ch.getFreshVar
+        val instr = i.getType match {
+          case Int32Type | BooleanType => IStore(slot)
+          case _ => AStore(slot)
+        }
+        ch << instr
+        mkExpr(b, ch)(env.withVars(Map(i -> slot)))
+
+      case IntLiteral(v) =>
+        ch << Ldc(v)
+
+      case BooleanLiteral(true) =>
+        ch << Ldc(1)
+
+      case BooleanLiteral(false) =>
+        ch << Ldc(0)
+
+      case IfExpr(c, t, e) =>
+        val tl = ch.getFreshLabel("then")
+        val el = ch.getFreshLabel("else")
+        val al = ch.getFreshLabel("after")
+        mkBranch(c, tl, el, ch)
+        ch << Label(tl)
+        mkExpr(t, ch)
+        ch << Goto(al) << Label(el)
+        mkExpr(e, ch)
+        ch << Label(al)
+
+      case FunctionInvocation(fd, as) =>
+        val (cn, mn, ms) = env.funDefToMethod(fd).getOrElse {
+          throw CompilationException("Unknown method : " + fd.id)
+        }
+        for(a <- as) {
+          mkExpr(a, ch)
+        }
+        ch << InvokeStatic(cn, mn, ms)
 
       case Plus(l, r) =>
         mkExpr(l, ch)
@@ -52,10 +95,71 @@ object CodeGeneration {
         mkExpr(r, ch)
         ch << ISUB
 
+      case Times(l, r) =>
+        mkExpr(l, ch)
+        mkExpr(r, ch)
+        ch << IMUL
+
       case UMinus(e) =>
         mkExpr(Minus(IntLiteral(0), e), ch)
 
-      case _ => throw CompilationException("Unsupported expr : " + e) 
+      case _ => throw CompilationException("Unsupported expr. : " + e) 
+    }
+  }
+
+  private def mkBranch(cond : Expr, then : String, elze : String, ch : CodeHandler)(implicit env : CompilationEnvironment) {
+    cond match {
+      case BooleanLiteral(true) =>
+        ch << Goto(then)
+
+      case BooleanLiteral(false) =>
+        ch << Goto(elze)
+
+      case And(es) =>
+        val fl = ch.getFreshLabel("andnext")
+        mkBranch(es.head, fl, elze, ch)
+        ch << Label(fl)
+        mkBranch(And(es.tail), then, elze, ch)
+
+      case Or(es) =>
+        val fl = ch.getFreshLabel("ornext")
+        mkBranch(es.head, then, fl, ch)
+        ch << Label(fl)
+        mkBranch(Or(es.tail), then, elze, ch) 
+
+      case Not(c) =>
+        mkBranch(c, elze, then, ch)
+
+      case Variable(b) =>
+        ch << ILoad(slotFor(b)) << IfEq(elze) << Goto(then)
+
+      case LessThan(l,r) =>
+        mkExpr(l, ch)
+        mkExpr(r, ch)
+        ch << If_ICmpLt(then) << Goto(elze) 
+      
+      case GreaterThan(l,r) =>
+        mkExpr(l, ch)
+        mkExpr(r, ch)
+        ch << If_ICmpGt(then) << Goto(elze) 
+      
+      case LessEquals(l,r) =>
+        mkExpr(l, ch)
+        mkExpr(r, ch)
+        ch << If_ICmpLe(then) << Goto(elze) 
+      
+      case GreaterEquals(l,r) =>
+        mkExpr(l, ch)
+        mkExpr(r, ch)
+        ch << If_ICmpGe(then) << Goto(elze) 
+      
+      case _ => throw CompilationException("Unsupported cond. expr. : " + cond)
+    }
+  }
+
+  private def slotFor(id : Identifier)(implicit env : CompilationEnvironment) : Int = {
+    env.varToLocal(id).getOrElse {
+      throw CompilationException("Unknown variable : " + id)
     }
   }
 }
diff --git a/src/main/scala/leon/codegen/CompilationEnvironment.scala b/src/main/scala/leon/codegen/CompilationEnvironment.scala
index 1eb9514e1a81e8b615928f6b9f5da0a10d0b4557..2bec36229355f8f1c82ba171336df49314ea219c 100644
--- a/src/main/scala/leon/codegen/CompilationEnvironment.scala
+++ b/src/main/scala/leon/codegen/CompilationEnvironment.scala
@@ -5,23 +5,53 @@ import purescala.Common._
 import purescala.Definitions._
 
 abstract class CompilationEnvironment() {
+  self =>
   // 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)]
+  def funDefToMethod(funDef : FunDef) : Option[(String,String,String)]
+
+  def varToLocal(v : Identifier) : Option[Int]
+
+  /** Augment the environment with new local var. mappings. */
+  def withVars(pairs : Map[Identifier,Int]) = {
+    new CompilationEnvironment {
+      def funDefToMethod(funDef : FunDef) = self.funDefToMethod(funDef)
+      def varToLocal(v : Identifier) = pairs.get(v).orElse(self.varToLocal(v))
+    }
+  }
 }
 
 object CompilationEnvironment {
+
+  lazy val empty = new CompilationEnvironment {
+    def funDefToMethod(funDef : FunDef) = None
+    def varToLocal(v : Identifier) = None
+  }
+
   def fromProgram(p : Program) : CompilationEnvironment = {
+    import CodeGeneration.typeToJVM
+
+    // This should change: it should contain the case classes before
+    // we go and generate function signatures.
+    implicit val env = empty
+
     val className = CodeGeneration.programToClassName(p)
 
     val fs = p.definedFunctions.filter(_.hasImplementation)
-    val fPairs : Map[FunDef,String] = fs.map(fd => (fd -> fd.id.uniqueName)).toMap
+
+    val fMap : Map[FunDef,(String,String,String)] = (fs.map { fd =>
+      val sig = "(" + fd.args.map(a => typeToJVM(a.tpe)).mkString("") + ")" + typeToJVM(fd.returnType)
+
+      fd -> (className, fd.id.uniqueName, sig)
+    }).toMap
 
     new CompilationEnvironment {
-      def funDefToMethod(funDef : FunDef) = fPairs.get(funDef).map(n => (className, n))
+      def funDefToMethod(funDef : FunDef) = fMap.get(funDef)
+
+      def varToLocal(v : Identifier) = None
     }
   }
 }
diff --git a/src/test/resources/regression/codegen/purescala/Prog001.scala b/src/test/resources/regression/codegen/purescala/Prog001.scala
index c0edc779fbcba95cec98102a9a4699fbbc12ef80..a7f3b23356fe439747cf3f3d6fc9f4a2dc3216a3 100644
--- a/src/test/resources/regression/codegen/purescala/Prog001.scala
+++ b/src/test/resources/regression/codegen/purescala/Prog001.scala
@@ -1,5 +1,18 @@
 object Prog001 {
   def fortyTwo() = 42
 
-  // def plus(x : Int, y : Int) = x + y
+  def plus(x : Int, y : Int) = x + y
+
+  def double(x : Int) : Int = {
+    val a = x
+    a + a
+  }
+
+  // def implies(a : Boolean, b : Boolean) : Boolean = !a || b
+
+  def abs(x : Int) : Int = {
+    if(x < 0) -x else x
+  }
+
+  def factorial(i : Int) : Int = if(i <= 1) 1 else (i * factorial(i - 1))
 }
diff --git a/unmanaged/32/cafebabe_2.9.2-1.2.jar b/unmanaged/32/cafebabe_2.9.2-1.2.jar
index a7f91ed1b7e26933e0b0c657dbd2f240a423dc50..ccfc6ff432dfbae28dbb6508948a4a87dc52524f 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