   add_stmt: (stmt) -> @stmts.push stmt
   new_temp: -> @block_chain.new_temp()
 
+  entryFromVar: (v) ->
+    if v instanceof StackVar
+      expr = @stack[v.id]
+    else
+      expr = @locals[v.id]
+
+  forEachVar: (cb) ->
+    for s, i in @stack when s?
+      new_s = new StackVar i
+      cb new_s
+
+    for l, i in @locals when l?
+      new_l = new LocalVar i
+      cb new_l
+
   compile_epilogue: ->
     # copy our stack / local values into appropriately-named vars so that they
     # can be accessed from other blocks
     rv = []
-    for blk_id in @next
-      block = @block_chain.get_block_from_instr blk_id
-      for s, i in @stack when s?
-        unless /^\$\d+$/.test s
-          temp = @new_temp()
-          rv.push new Move temp, s
-          @stack[i] = temp
-        rv.push new Move block.in_stack[i], @stack[i] if block.in_stack[i]?
-
-      for l, i in @locals when l?
-        unless /^\$\d+$/.test l
-          temp = @new_temp()
-          rv.push new Move temp, l
-          @locals[i] = temp
-        rv.push new Move block.in_locals[i], @locals[i] if block.in_locals[i]?
-    rv
+
+    postordered = []
+    visited = {}
+    clobbered = {}
+    replacements = {}
+    traverse = (v) =>
+      return if visited[v]
+      visited[v] = true
+
+      expr = @entryFromVar v
+
+      unless expr instanceof Primitive and v.equals expr
+        clobbered[v] = true
+        replacer = (d) =>
+          return d unless (d instanceof StackVar or d instanceof LocalVar) and not d.equals v
+          if clobbered[d]
+            unless replacements[d]
+              replacements[d] = @new_temp()
+              rv.push new Move replacements[d], d
+            return replacements[d]
+          traverse d
+          d
+
+        if expr instanceof Expr
+          expr.replace replacer
+        else
+          expr = replacer expr
+
+        postordered.push new Move v, expr
+      
+    @forEachVar traverse
+
+    rv.concat postordered.reverse()
 
   compile: (prev_stack, prev_locals) ->
     return if @visited

        labels.push target

    for idx, i in labels
      @blocks.push new BasicBlock @, idx
      @instr2block[idx] = i
      # we initially assume all blocks are connected linearly.
      # compiling the individual instructions will adjust this as needed.
      if @blocks.length > 1
        @blocks[@blocks.length - 2].next.push idx

    current_block = -1
    method.code.each_opcode (idx, oc) =>

    unless op.offset? or (op.name.indexOf 'return') != -1
      @add_stmt => @compile_epilogue()

    for next_block in @next
      # java bytecode verification ensures that the stack height and stack /
      # local table types match up across blocks
      next_block.compile @stack, @locals
