Report abuse

diff --git a/rakelib/vm.rake b/rakelib/vm.rake
index 25e30d7..2d526e8 100644
--- a/rakelib/vm.rake
+++ b/rakelib/vm.rake
@@ -479,10 +479,14 @@ end
 files TYPE_GEN, field_extract_headers + %w[vm/codegen/field_extract.rb] + [:run_field_extract] do
 end

-file 'vm/jit-test' => EXTERNALS + objs + jit_objs + ["vm/assembler/libudis86.a"] do |t|
+file 'vm/jit-test' => EXTERNALS + objs + jit_objs + ["vm/drivers/jit-test.o", "vm/assembler/libudis86.a"] do |t|
   ld t
 end

+file "vm/drivers/jit-test.o" => "vm/drivers/jit-test.cpp" do
+  compile_c "vm/drivers/jit-test.o", "vm/drivers/jit-test.cpp"
+end
+
 file 'vm/vm' => EXTERNALS + objs + vm_objs do |t|
   ld t
 end
diff --git a/vm/assembler/jit.cpp b/vm/assembler/jit.cpp
index 551f4f7..3c74d5a 100644
--- a/vm/assembler/jit.cpp
+++ b/vm/assembler/jit.cpp
@@ -18,12 +18,17 @@ using namespace assembler_x86;
 using namespace operations;
 using namespace rubinius;

+extern "C" Object* send_slowly(STATE, VMMethod* vmm, CallFrame* const call_frame, Symbol* name, size_t args);
+
+// It's not thread safe. Although it's okay for now (becuase we use GIL),
+//  at some point in the future you might want to get rid of it
+static uint8_t * global_buffer = new uint8_t[1024*1024];

 namespace rubinius {
   JITCompiler::JITCompiler()
     : stack_cached_(false)
     , own_buffer_(true)
-    , buffer_(new uint8_t[1024*1024])
+    , buffer_(global_buffer)
     , a(buffer_)
     , s(a, ebx)
     , ops(s) { }
@@ -36,13 +41,6 @@ namespace rubinius {
     , s(a, ebx)
     , ops(s) { }

-  JITCompiler::~JITCompiler() {
-    if(own_buffer_) {
-      memset(buffer_, 0, 1024*1024);
-      delete[] buffer_;
-    }
-  }
-
   void JITCompiler::cache_stack(bool force) {
     if(!force && stack_cached_) return;
     stack_cached_ = true;
@@ -55,42 +53,29 @@ namespace rubinius {
     ops.save_stack_pointer();
   }

-/** @todo Fix JIT. Task is gone. --rue */
-//  ExecuteStatus JITCompiler::check_interrupts(VMMethod* const vmm, Task* const task,
-//      MethodContext* const ctx) {
-//    task->state->events->poll();
-//    return task->state->interrupts.check_events ? cExecuteRestart : cExecuteContinue;
-//  }
-//
-//  ExecuteStatus JITCompiler::slow_plus_path(VMMethod* const vmm, Task* const task,
-//      MethodContext* const ctx) {
-//    return send_slowly(vmm, task, ctx, task->state->globals.sym_plus.get(), 1);
-//  }
-//
-//  ExecuteStatus JITCompiler::slow_minus_path(VMMethod* const vmm, Task* const task,
-//      MethodContext* const ctx) {
-//    return send_slowly(vmm, task, ctx, task->state->globals.sym_minus.get(), 1);
-//  }
-//
-//  ExecuteStatus JITCompiler::slow_equal_path(VMMethod* const vmm, Task* const task,
-//      MethodContext* const ctx) {
-//    return send_slowly(vmm, task, ctx, task->state->globals.sym_equal.get(), 1);
-//  }
-//
-//  ExecuteStatus JITCompiler::slow_nequal_path(VMMethod* const vmm, Task* const task,
-//      MethodContext* const ctx) {
-//    return send_slowly(vmm, task, ctx, task->state->globals.sym_nequal.get(), 1);
-//  }
-//
-//  ExecuteStatus JITCompiler::slow_lt_path(VMMethod* const vmm, Task* const task,
-//      MethodContext* const ctx) {
-//    return send_slowly(vmm, task, ctx, task->state->globals.sym_lt.get(), 1);
-//  }
-//
-//  ExecuteStatus JITCompiler::slow_gt_path(VMMethod* const vmm, Task* const task,
-//      MethodContext* const ctx) {
-//    return send_slowly(vmm, task, ctx, task->state->globals.sym_gt.get(), 1);
-//  }
+ Object * JITCompiler::slow_plus_path(STATE, VMMethod* const vmm, CallFrame* const call_frame) {
+   return send_slowly(state, vmm, call_frame, G(sym_plus), 1);
+ }
+
+ Object * JITCompiler::slow_minus_path(STATE, VMMethod* const vmm, CallFrame* const call_frame) {
+   return send_slowly(state, vmm, call_frame, G(sym_minus), 1);
+ }
+
+ Object * JITCompiler::slow_equal_path(STATE, VMMethod* const vmm, CallFrame* const call_frame) {
+   return send_slowly(state, vmm, call_frame, G(sym_equal), 1);
+ }
+
+ Object * JITCompiler::slow_nequal_path(STATE, VMMethod* const vmm, CallFrame* const call_frame) {
+   return send_slowly(state, vmm, call_frame, G(sym_nequal), 1);
+ }
+
+ Object * JITCompiler::slow_lt_path(STATE, VMMethod* const vmm, CallFrame* const call_frame) {
+   return send_slowly(state, vmm, call_frame, G(sym_lt), 1);
+ }
+
+ Object * JITCompiler::slow_gt_path(STATE, VMMethod* const vmm, CallFrame* const call_frame) {
+   return send_slowly(state, vmm, call_frame, G(sym_gt), 1);
+ }

   void JITCompiler::maybe_return(int i, uintptr_t **last_imm, AssemblerX86::NearJumpLocation &fin) {

@@ -105,12 +90,12 @@ namespace rubinius {
     // back into the MethodContext in the epilogue
     // The + 1 is to match the interpreter, where the ip points
     // to the next instruction rather than the current one
-    a.mov(ecx, i + 1);
+    a.mov(ecx, i);

     // If the return value of the operation (located in eax),
-    // is cExecuteRestart, then jump to the epilogue, which
+    // is NULL, then jump to the epilogue, which
     // stores ecx as the virtual ip and returns.
-    a.cmp(eax, cExecuteRestart);
+    a.cmp(eax, 0);
     a.jump_if_equal(fin);
   }

@@ -156,24 +141,14 @@ namespace rubinius {
       a.add(eax, 1);
     }

-    // Remove one from the stack
-    s.pop();
-
-    // Put the result on the stack
-    s.set_top(eax);
-
     a.jump(done);

     a.set_label(slow_path);
     uncache_stack();
     if(add) {
-      /** @todo Fix through Message::send, Task is gone. --rue */
-      abort();
-//      ops.call_via_symbol((void*)JITCompiler::slow_plus_path);
+      ops.call_via_symbol((void*)JITCompiler::slow_plus_path);
     } else {
-      /** @todo Fix through Message::send, Task is gone. --rue */
-      abort();
-//      ops.call_via_symbol((void*)JITCompiler::slow_minus_path);
+      ops.call_via_symbol((void*)JITCompiler::slow_minus_path);
     }
     cache_stack();
   }
@@ -205,20 +180,20 @@ namespace rubinius {
     a.jump_if_equal(equal_path);

     if(equal) {
-      s.set_top(cFalse);
+      a.mov(eax, cFalse);
       a.jump(done);

       a.set_label(equal_path);

-      s.set_top(cTrue);
+      a.mov(eax, cTrue);
       a.jump(done);
     } else {
-      s.set_top(cTrue);
+      a.mov(eax, cTrue);
       a.jump(done);

       a.set_label(equal_path);

-      s.set_top(cFalse);
+      a.mov(eax, cFalse);
       a.jump(done);
     }

@@ -226,16 +201,13 @@ namespace rubinius {
     uncache_stack();

     if(equal) {
-      /** @todo Fix through Message::send, Task is gone. --rue */
-      abort();
-//      ops.call_via_symbol((void*)JITCompiler::slow_equal_path);
+     ops.call_via_symbol((void*)JITCompiler::slow_equal_path);
     } else {
-      /** @todo Fix through Message::send, Task is gone. --rue */
-      abort();
-//      ops.call_via_symbol((void*)JITCompiler::slow_nequal_path);
+     ops.call_via_symbol((void*)JITCompiler::slow_nequal_path);
     }

     cache_stack();
+    s.pop();
   }

   void JITCompiler::emit_fast_compare(AssemblerX86::NearJumpLocation& done, bool less) {
@@ -262,21 +234,21 @@ namespace rubinius {
       AssemblerX86::NearJumpLocation less_path;

       a.jump_if_less(less_path);
-      s.set_top(cFalse);
+      a.mov(eax, cFalse);
       a.jump(done);

       a.set_label(less_path);
-      s.set_top(cTrue);
+      a.mov(eax, cTrue);
       a.jump(done);
     } else {
       AssemblerX86::NearJumpLocation greater_path;

       a.jump_if_greater(greater_path);
-      s.set_top(cFalse);
+      a.mov(eax, cFalse);
       a.jump(done);

       a.set_label(greater_path);
-      s.set_top(cTrue);
+      a.mov(eax, cTrue);
       a.jump(done);
     }

@@ -284,16 +256,12 @@ namespace rubinius {
     uncache_stack();

     if(less) {
-      /** @todo Fix through Message::send, Task is gone. --rue */
-      abort();
-//      ops.call_via_symbol((void*)JITCompiler::slow_lt_path);
+     ops.call_via_symbol((void*)JITCompiler::slow_lt_path);
     } else {
-      /** @todo Fix through Message::send, Task is gone. --rue */
-      abort();
-//      ops.call_via_symbol((void*)JITCompiler::slow_gt_path);
+     ops.call_via_symbol((void*)JITCompiler::slow_gt_path);
     }
-
     cache_stack();
+    s.pop();
   }

   void JITCompiler::compile(STATE, VMMethod* vmm) {
@@ -336,6 +304,7 @@ namespace rubinius {

     for(size_t i = 0; i < vmm->total;) {
       opcode op = vmm->opcodes[i];
+      op = instructions::reverse_superop(op);
       size_t width = InstructionSequence::instruction_width(op);

       // Set the label location
@@ -441,9 +410,12 @@ namespace rubinius {
         ops.load_self(eax);
         s.push(eax);
         break;
-
+      case InstructionSequence::insn_ret:
+        s.load_nth(eax, 0);
+        a.jump(real_fin);
+        break;
       // Now, for a bit more complicated ones...
-      //
+
       case InstructionSequence::insn_push_local:
         ops.get_local(eax, vmm->opcodes[i + 1]);
         s.push(eax);
@@ -463,13 +435,17 @@ namespace rubinius {
       case InstructionSequence::insn_meta_send_op_plus: {
         AssemblerX86::NearJumpLocation done;
         emit_fast_math(done, op == InstructionSequence::insn_meta_send_op_plus);
-        maybe_return(i, &last_imm, fin);
+        maybe_return(i+width, &last_imm, fin);

         // This is a phi point, where the fast path and slow path merge.
         // We have to be sure that the stack cache settings are in sync
         // for both paths taken at this point. To be sure of that, we
         // always run cache_stack() after calling slow_path_plus.
         a.set_label(done);
+        // Remove one from the stack
+        s.pop();
+        // Put the result on the stack
+        s.set_top(eax);
         break;
       }

@@ -477,9 +453,13 @@ namespace rubinius {
       case InstructionSequence::insn_meta_send_op_nequal: {
         AssemblerX86::NearJumpLocation done;
         emit_fast_equal(done, op == InstructionSequence::insn_meta_send_op_equal);
-        maybe_return(i, &last_imm, fin);
+        maybe_return(i+width, &last_imm, fin);

         a.set_label(done);
+
+        // Put the result on the stack
+        s.set_top(eax);
+
         break;
       }

@@ -487,41 +467,38 @@ namespace rubinius {
       case InstructionSequence::insn_meta_send_op_gt: {
         AssemblerX86::NearJumpLocation done;
         emit_fast_compare(done, op == InstructionSequence::insn_meta_send_op_lt);
-        maybe_return(i, &last_imm, fin);
+        maybe_return(i+width, &last_imm, fin);

         a.set_label(done);
+        // Put the result on the stack
+        s.set_top(eax);
         break;
       }
-
-      case InstructionSequence::insn_push_const_fast: {
-        AssemblerX86::NearJumpLocation slow_path;
-        AssemblerX86::NearJumpLocation done;
-
-        ops.get_literal(eax, vmm->opcodes[i + 2]);
-        a.cmp(eax, reinterpret_cast<uintptr_t>(Qnil));
-        a.jump_if_equal(slow_path);
-        a.mov(eax, a.address(eax, FIELD_OFFSET(rubinius::LookupTableAssociation, value_)));
-        // TODO this doesn't support autoload!
-        s.push(eax);
-
-        a.jump(done);
-
-        a.set_label(slow_path);
-        uncache_stack();
-        const instructions::Implementation* impl = instructions::implementation(op);
-        ops.call_operation(impl->address, impl->name,
-            vmm->opcodes[i + 1],
-            vmm->opcodes[i + 2]);
-        maybe_return(i, &last_imm, fin);
-
-        a.set_label(done);
-        break;
-      }
-
-      case InstructionSequence::insn_set_call_flags:
-        ops.store_call_flags(vmm->opcodes[i + 1]);
-        break;
-
+      //
+      // case InstructionSequence::insn_push_const_fast: {
+      //   AssemblerX86::NearJumpLocation slow_path;
+      //   AssemblerX86::NearJumpLocation done;
+      //
+      //   ops.get_literal(eax, vmm->opcodes[i + 2]);
+      //   a.cmp(eax, reinterpret_cast<uintptr_t>(Qnil));
+      //   a.jump_if_equal(slow_path);
+      //   a.mov(eax, a.address(eax, FIELD_OFFSET(rubinius::LookupTableAssociation, value_)));
+      //   // TODO this doesn't support autoload!
+      //   s.push(eax);
+      //
+      //   a.jump(done);
+      //
+      //   a.set_label(slow_path);
+      //   uncache_stack();
+      //   const instructions::Implementation* impl = instructions::implementation(op);
+      //   ops.call_operation(impl->address, impl->name,
+      //       vmm->opcodes[i + 1],
+      //       vmm->opcodes[i + 2]);
+      //   maybe_return(i, &last_imm, fin);
+      //
+      //   a.set_label(done);
+      //   break;
+      // }
         // for any instruction we don't handle with a special code sequence,
         // just call the regular function for it.
       default: {
@@ -546,15 +523,13 @@ call_op:
             op << "'\n";
           abort();
         }
+        cache_stack();

         instructions::Status status = instructions::check_status(op);
         if(status == instructions::MightReturn) {
-          maybe_return(i, &last_imm, fin);
+          maybe_return(i + width, &last_imm, fin);
         } else if(status == instructions::Terminate) {
           a.jump(real_fin);
-          cache_stack();
-        } else {
-          cache_stack();
         }
         break;
       }
@@ -700,75 +675,75 @@ call_op:
       ops.tag_fixnum(eax);
       s.push(eax);
       break;
-    case InstructionSequence::insn_push_self:
-      ops.load_self(eax);
-      s.push(eax);
-      break;
-    case InstructionSequence::insn_push_local:
-      ops.load_next_opcode(ecx);
-      ops.get_local(eax, ecx);        // eax == local
-      s.push(eax);
-      break;
-    case InstructionSequence::insn_set_local:
-      ops.load_next_opcode(ecx);
-      s.load_nth(edx, 0);
-      ops.set_local(edx, ecx);
-      break;
-    case InstructionSequence::insn_push_literal:
-      ops.load_next_opcode(ecx);
-      ops.get_literal(eax, ecx);
-      s.push(eax);
-      break;
-    case InstructionSequence::insn_meta_send_op_minus:
-    case InstructionSequence::insn_meta_send_op_plus: {
-      AssemblerX86::NearJumpLocation done;
-      emit_fast_math(done, op == InstructionSequence::insn_meta_send_op_plus);
-
-      // If the return value of the operation (located in eax),
-      // is cExecuteRestart, then jump to the epilogue, which
-      // stores ecx as the virtual ip and returns.
-      a.cmp(eax, cExecuteRestart);
-      a.jump_if_equal(fin);
-
-      // This is a phi point, where the fast path and slow path merge.
-      // We have to be sure that the stack cache settings are in sync
-      // for both paths taken at this point. To be sure of that, we
-      // always run cache_stack() after calling slow_path_plus.
-      a.set_label(done);
-      break;
-    }
-
-    case InstructionSequence::insn_meta_send_op_equal:
-    case InstructionSequence::insn_meta_send_op_nequal: {
-      AssemblerX86::NearJumpLocation done;
-      emit_fast_equal(done, op == InstructionSequence::insn_meta_send_op_equal);
-
-      // If the return value of the operation (located in eax),
-      // is cExecuteRestart, then jump to the epilogue, which
-      // stores ecx as the virtual ip and returns.
-      a.cmp(eax, cExecuteRestart);
-      a.jump_if_equal(fin);
-
-      a.set_label(done);
-      break;
-    }
-
-
-    case InstructionSequence::insn_meta_send_op_lt:
-    case InstructionSequence::insn_meta_send_op_gt: {
-      AssemblerX86::NearJumpLocation done;
-      emit_fast_compare(done, op == InstructionSequence::insn_meta_send_op_lt);
-      a.cmp(eax, cExecuteRestart);
-      a.jump_if_equal(fin);
-
-      a.set_label(done);
-      break;
-    }
-
-    case InstructionSequence::insn_set_call_flags:
-      ops.load_next_opcode(ecx);
-      ops.store_call_flags(ecx);
-      break;
+    // case InstructionSequence::insn_push_self:
+    //   ops.load_self(eax);
+    //   s.push(eax);
+    //   break;
+    // case InstructionSequence::insn_push_local:
+    //   ops.load_next_opcode(ecx);
+    //   ops.get_local(eax, ecx);        // eax == local
+    //   s.push(eax);
+    //   break;
+    // case InstructionSequence::insn_set_local:
+    //   ops.load_next_opcode(ecx);
+    //   s.load_nth(edx, 0);
+    //   ops.set_local(edx, ecx);
+    //   break;
+    // case InstructionSequence::insn_push_literal:
+    //   ops.load_next_opcode(ecx);
+    //   ops.get_literal(eax, ecx);
+    //   s.push(eax);
+    //   break;
+    // case InstructionSequence::insn_meta_send_op_minus:
+    // case InstructionSequence::insn_meta_send_op_plus: {
+    //   AssemblerX86::NearJumpLocation done;
+    //   emit_fast_math(done, op == InstructionSequence::insn_meta_send_op_plus);
+    //
+    //   // If the return value of the operation (located in eax),
+    //   // is cExecuteRestart, then jump to the epilogue, which
+    //   // stores ecx as the virtual ip and returns.
+    //   a.cmp(eax, cExecuteRestart);
+    //   a.jump_if_equal(fin);
+    //
+    //   // This is a phi point, where the fast path and slow path merge.
+    //   // We have to be sure that the stack cache settings are in sync
+    //   // for both paths taken at this point. To be sure of that, we
+    //   // always run cache_stack() after calling slow_path_plus.
+    //   a.set_label(done);
+    //   break;
+    // }
+    //
+    // case InstructionSequence::insn_meta_send_op_equal:
+    // case InstructionSequence::insn_meta_send_op_nequal: {
+    //   AssemblerX86::NearJumpLocation done;
+    //   emit_fast_equal(done, op == InstructionSequence::insn_meta_send_op_equal);
+    //
+    //   // If the return value of the operation (located in eax),
+    //   // is cExecuteRestart, then jump to the epilogue, which
+    //   // stores ecx as the virtual ip and returns.
+    //   a.cmp(eax, cExecuteRestart);
+    //   a.jump_if_equal(fin);
+    //
+    //   a.set_label(done);
+    //   break;
+    // }
+    //
+    //
+    // case InstructionSequence::insn_meta_send_op_lt:
+    // case InstructionSequence::insn_meta_send_op_gt: {
+    //   AssemblerX86::NearJumpLocation done;
+    //   emit_fast_compare(done, op == InstructionSequence::insn_meta_send_op_lt);
+    //   a.cmp(eax, cExecuteRestart);
+    //   a.jump_if_equal(fin);
+    //
+    //   a.set_label(done);
+    //   break;
+    // }
+
+    // case InstructionSequence::insn_set_call_flags:
+    //   ops.load_next_opcode(ecx);
+    //   ops.store_call_flags(ecx);
+    //   break;

     default: {
       uncache_stack();
diff --git a/vm/assembler/jit.hpp b/vm/assembler/jit.hpp
index 8cefb21..a41a38a 100644
--- a/vm/assembler/jit.hpp
+++ b/vm/assembler/jit.hpp
@@ -31,7 +31,6 @@ namespace rubinius {

     JITCompiler();
     JITCompiler(uint8_t* buffer);
-    ~JITCompiler();

     assembler_x86::AssemblerX86& assembler() {
       return a;
@@ -55,24 +54,17 @@ namespace rubinius {
     void emit_fast_compare(assembler_x86::AssemblerX86::NearJumpLocation& done, bool less);
     void emit_opcode(opcode op, assembler_x86::AssemblerX86::NearJumpLocation& fin);

-/** @todo Fix JIT. Task is gone. --rue */
-//    static ExecuteStatus slow_plus_path(VMMethod* const vmm, Task* const task,
-//        MethodContext* const ctx);
-//
-//    static ExecuteStatus slow_minus_path(VMMethod* const vmm, Task* const task,
-//        MethodContext* const ctx);
-//
-//    static ExecuteStatus slow_equal_path(VMMethod* const vmm, Task* const task,
-//        MethodContext* const ctx);
-//
-//    static ExecuteStatus slow_nequal_path(VMMethod* const vmm, Task* const task,
-//        MethodContext* const ctx);
-//
-//    static ExecuteStatus slow_lt_path(VMMethod* const vmm, Task* const task,
-//        MethodContext* const ctx);
-//
-//    static ExecuteStatus slow_gt_path(VMMethod* const vmm, Task* const task,
-//        MethodContext* const ctx);
+   static Object * slow_plus_path(STATE, VMMethod* const vmm, CallFrame* const call_frame);
+
+   static Object * slow_minus_path(STATE, VMMethod* const vmm, CallFrame* const call_frame);
+
+   static Object * slow_equal_path(STATE, VMMethod* const vmm, CallFrame* const call_frame);
+
+   static Object * slow_nequal_path(STATE, VMMethod* const vmm, CallFrame* const call_frame);
+
+   static Object * slow_lt_path(STATE, VMMethod* const vmm, CallFrame* const call_frame);
+
+   static Object * slow_gt_path(STATE, VMMethod* const vmm, CallFrame* const call_frame);
 //
 //    static ExecuteStatus check_interrupts(VMMethod* const vmm, Task* const task,
 //      MethodContext* const ctx);
@@ -82,6 +74,7 @@ namespace rubinius {
     // Emit code to check %eax and determine if a new context was
     // installed.
     void maybe_return(int i, uintptr_t **last_imm, assembler_x86::AssemblerX86::NearJumpLocation& fin);
+    void must_return(int i, uintptr_t **last_imm, assembler_x86::AssemblerX86::NearJumpLocation& fin);

     // Pull the stack pointer into ebx if it's not there already
     void cache_stack(bool force = false);
diff --git a/vm/assembler/operations.hpp b/vm/assembler/operations.hpp
index c794d62..90a2265 100644
--- a/vm/assembler/operations.hpp
+++ b/vm/assembler/operations.hpp
@@ -5,6 +5,7 @@
 #include "oop.hpp"
 #include "jit_state.h"
 #include "builtin/tuple.hpp"
+#include "call_frame.hpp"

 namespace operations {

@@ -74,8 +75,8 @@ namespace operations {
   };

   // HACK to eliminate using MethodContext quickly
-#undef FIELD_OFFSET
-#define FIELD_OFFSET(a,b) 0
+// #undef FIELD_OFFSET
+// #define FIELD_OFFSET(a,b) 0

   class ObjectOperations {
     StackOperations &s;
@@ -112,7 +113,7 @@ namespace operations {

       // Pull jit_state.stack into the stack pointer
       s.assembler().mov(s.stack_pointer(), s.assembler().address(esi,
-        FIELD_OFFSET(rubinius::MethodContext, js.stack)));
+        FIELD_OFFSET(rubinius::CallFrame, js.stack)));
     }

     void save_stack_pointer() {
@@ -121,7 +122,7 @@ namespace operations {
       // Mov the stack pointer into  jit_state.stack
       s.assembler().mov(
           s.assembler().address(esi,
-            FIELD_OFFSET(rubinius::MethodContext, js.stack)),
+            FIELD_OFFSET(rubinius::CallFrame, js.stack)),
           s.stack_pointer());
     }

@@ -131,14 +132,19 @@ namespace operations {
       // Do the normal prologue
       a.prologue(0);

+      // Interpreter state
+      a.push(0);
+      a.push(0);
+      a.mov(eax, esp);
       // seed the stack with the operation arguments so we don't have
       // to push them over and over again
       //
-      // First, add some space for 5 extra args
+      // First, add some space for 2 extra args
       // This seems like a lot, but we need space for at least 2 AND
       // we have to keep the stack aligned properly.
-      a.sub(esp, 0x14);
+      a.sub(esp, 0x08);

+      a.push(eax);
       // Now push the incoming arguments on
       a.push_arg(2);
       a.push_arg(1);
@@ -146,6 +152,7 @@ namespace operations {
     }

     void epilogue() {
+      AssemblerX86::NearJumpLocation fail;
       // Remove the spots for 8 args we setup in prologue
       s.assembler().add(esp, 0x20);

@@ -155,16 +162,18 @@ namespace operations {

     // Attempts to call +func+ as a symbol.
     void call_via_symbol(void* func) {
-      Dl_info info;
-      if(!dladdr(func, &info)) {
-        throw std::runtime_error("Unable to find symbol");
-      }
-
-      if(!info.dli_sname || info.dli_saddr != func) {
-        throw std::runtime_error("Unable to resolve symbol properly");
-      }
+      // Who cares about func name?
+      // Dl_info info;
+      // if(!dladdr(func, &info)) {
+      //   throw std::runtime_error("Unable to find symbol");
+      // }
+      //
+      // if(!info.dli_sname || info.dli_saddr != func) {
+      //   throw std::runtime_error("Unable to resolve symbol properly");
+      // }

-      s.assembler().call(func, info.dli_sname);
+      // s.assembler().call(func, info.dli_sname);
+      s.assembler().call(func);
     }

     void call_operation(void* func, const char* name) {
@@ -173,27 +182,27 @@ namespace operations {

     void call_operation(void* func, const char* name, int arg) {
       AssemblerX86 &a = s.assembler();
-      a.mov(a.address(esp, 12), arg);
+      a.mov(a.address(esp, 16), arg);
       a.call(func, name);
     }

     void call_operation(void* func, const char* name, Register& arg) {
       AssemblerX86 &a = s.assembler();
-      a.mov(a.address(esp, 12), arg);
+      a.mov(a.address(esp, 16), arg);
       a.call(func, name);
     }

     void call_operation(void* func, const char* name, int arg, int arg2) {
       AssemblerX86 &a = s.assembler();
-      a.mov(a.address(esp, 12), arg);
-      a.mov(a.address(esp, 16), arg2);
+      a.mov(a.address(esp, 16), arg);
+      a.mov(a.address(esp, 20), arg2);
       a.call(func, name);
     }

     void call_operation(void* func, const char* name, Register& arg, Register& arg2) {
       AssemblerX86 &a = s.assembler();
-      a.mov(a.address(esp, 12), arg);
-      a.mov(a.address(esp, 16), arg2);
+      a.mov(a.address(esp, 16), arg);
+      a.mov(a.address(esp, 20), arg2);
       a.call(func, name);
     }

@@ -210,29 +219,29 @@ namespace operations {
     }

     void store_virtual_ip(Register& reg) {
-      store_mc_field(reg, FIELD_OFFSET(rubinius::MethodContext, ip));
+      store_mc_field(reg, FIELD_OFFSET(rubinius::CallFrame, ip));
     }

     void store_native_ip(Register& reg) {
-      store_mc_field(reg, FIELD_OFFSET(rubinius::MethodContext, native_ip));
+      store_mc_field(reg, FIELD_OFFSET(rubinius::CallFrame, native_ip));
     }

     void load_native_ip(Register& reg) {
-      load_mc_field(reg, FIELD_OFFSET(rubinius::MethodContext, native_ip));
+      load_mc_field(reg, FIELD_OFFSET(rubinius::CallFrame, native_ip));
     }

     void store_ip(Register& virtual_ip, Register& native_ip) {
       load_mc();
       AssemblerX86 &a = s.assembler();
-      a.mov(a.address(esi, FIELD_OFFSET(rubinius::MethodContext, ip)), virtual_ip);
-      a.mov(a.address(esi, FIELD_OFFSET(rubinius::MethodContext, native_ip)), native_ip);
+      a.mov(a.address(esi, FIELD_OFFSET(rubinius::CallFrame, ip)), virtual_ip);
+      a.mov(a.address(esi, FIELD_OFFSET(rubinius::CallFrame, native_ip)), native_ip);
     }

     void load_and_increment_ip(Register& reg) {
       load_mc();
       AssemblerX86 &a = s.assembler();
-      a.mov(reg, a.address(esi, FIELD_OFFSET(rubinius::MethodContext, ip)));
-      a.add(a.address(esi, FIELD_OFFSET(rubinius::MethodContext, ip)), 1);
+      a.mov(reg, a.address(esi, FIELD_OFFSET(rubinius::CallFrame, ip)));
+      a.add(a.address(esi, FIELD_OFFSET(rubinius::CallFrame, ip)), 1);
     }

     void load_opcodes(Register& reg) {
@@ -253,48 +262,54 @@ namespace operations {
     }

     void load_self(Register& reg) {
-      load_home(reg);
       AssemblerX86 &a = s.assembler();
-      a.mov(reg, a.address(reg, FIELD_OFFSET(rubinius::MethodContext, self_)));
+      load_call_frame(reg);
+      a.mov(reg, a.address(reg, FIELD_OFFSET(rubinius::CallFrame, scope)));
+      a.mov(reg, a.address(reg, FIELD_OFFSET(rubinius::VariableScope, self_)));
     }

-    void load_home(Register& reg) {
-      load_mc_field(reg, FIELD_OFFSET(rubinius::MethodContext, home_));
+    void load_call_frame(Register& reg) {
+      s.assembler().load_arg(reg, 2);
     }

     void load_literals(Register& reg) {
-      load_mc_field(reg, FIELD_OFFSET(rubinius::MethodContext, cm_));
       AssemblerX86 &a = s.assembler();
+      load_call_frame(reg);
+      a.mov(reg, a.address(reg, FIELD_OFFSET(rubinius::CallFrame, cm)));
       a.mov(reg, a.address(reg, FIELD_OFFSET(rubinius::CompiledMethod, literals_)));
     }

     void set_local(Register& val, int which) {
-      load_home(eax);
+      load_call_frame(eax);
       AssemblerX86 &a = s.assembler();
-      int base =   FIELD_OFFSET(rubinius::MethodContext, stk);
+      int base =   FIELD_OFFSET(rubinius::VariableScope, locals_);
       int offset = which * sizeof(void*);
+      a.mov(eax, a.address(eax, FIELD_OFFSET(rubinius::CallFrame, top_scope)));
       a.mov(a.address(eax, base + offset), val);
     }

     void set_local(Register& val, Register& which) {
-      load_home(eax);
+      load_call_frame(eax);
       AssemblerX86 &a = s.assembler();
-      int base =   FIELD_OFFSET(rubinius::MethodContext, stk);
+      int base =   FIELD_OFFSET(rubinius::VariableScope, locals_);
+      a.mov(eax, a.address(eax, FIELD_OFFSET(rubinius::CallFrame, top_scope)));
       a.mov_to_table(eax, which, sizeof(void*), base, val);
     }

     void get_local(Register& val, int which) {
-      load_home(eax);
+      load_call_frame(eax);
       AssemblerX86 &a = s.assembler();
-      int base =   FIELD_OFFSET(rubinius::MethodContext, stk);
+      int base =   FIELD_OFFSET(rubinius::VariableScope, locals_);
       int offset = which * sizeof(void*);
+      a.mov(eax, a.address(eax, FIELD_OFFSET(rubinius::CallFrame, top_scope)));
       a.mov(val, a.address(eax, base + offset));
     }

     void get_local(Register& val, Register& which) {
-      load_home(eax);
+      load_call_frame(eax);
       AssemblerX86 &a = s.assembler();
-      int base =   FIELD_OFFSET(rubinius::MethodContext, stk);
+      int base =   FIELD_OFFSET(rubinius::VariableScope, locals_);
+      a.mov(eax, a.address(eax, FIELD_OFFSET(rubinius::CallFrame, top_scope)));
       a.mov_from_table(val, eax, which, sizeof(void*), base);
     }

diff --git a/vm/builtin/compiledmethod.cpp b/vm/builtin/compiledmethod.cpp
index 0009293..db0fb31 100644
--- a/vm/builtin/compiledmethod.cpp
+++ b/vm/builtin/compiledmethod.cpp
@@ -19,6 +19,8 @@
 #include "dispatch.hpp"
 #include "call_frame.hpp"
 #include "object_utils.hpp"
+#include "vm/object_utils.hpp"
+#include "assembler/jit.hpp"

 namespace rubinius {

@@ -156,17 +158,13 @@ namespace rubinius {
   }

   MachineMethod* CompiledMethod::make_machine_method(STATE) {
-    if(backend_method_ == 0) {
+    if(backend_method_ == NULL) {
       formalize(state, false);
     }

-    /*
     JITCompiler jit;
     jit.compile(state, backend_method_);
     return MachineMethod::create(state, backend_method_, jit);
-    */
-
-    return NULL;
   }

   bool CompiledMethod::is_rescue_target(STATE, int ip) {
diff --git a/vm/builtin/machine_method.cpp b/vm/builtin/machine_method.cpp
index ade3ac0..92893d7 100644
--- a/vm/builtin/machine_method.cpp
+++ b/vm/builtin/machine_method.cpp
@@ -2,6 +2,7 @@
 #include "builtin/class.hpp"
 #include "builtin/machine_method.hpp"
 #include "vmmethod.hpp"
+#include "assembler/jit.hpp"

 #include "vm/exception.hpp"

@@ -15,7 +16,7 @@ namespace rubinius {
     GO(machine_method).set(state->new_class_under("MachineMethod", G(rubinius)));
   }

-  /*
+
   static void* adjust(void* old_base, void* new_base, void* address) {
     uintptr_t diff = reinterpret_cast<uintptr_t>(new_base) -
                      reinterpret_cast<uintptr_t>(old_base);
@@ -23,11 +24,8 @@ namespace rubinius {
     return reinterpret_cast<void*>(
         reinterpret_cast<uintptr_t>(address) + diff);
   }
-  */

   MachineMethod* MachineMethod::create(STATE, VMMethod* vmm, JITCompiler& jit) {
-    return NULL;
-    /*
     size_t code_size = jit.assembler().used_bytes();
     MachineMethod* mm = state->new_struct<MachineMethod>(G(machine_method));

@@ -71,7 +69,6 @@ namespace rubinius {
     }

     return mm;
-    */
   }

   void* MachineMethod::resolve_virtual_ip(int ip) {
@@ -81,7 +78,6 @@ namespace rubinius {
   }

   Object* MachineMethod::show() {
-    /*
     std::cout << "== stats ==\n";
     std::cout << "number of bytecodes: " << vmmethod_->total << "\n";
     std::cout << " bytes of assembley: " << code_size_ << "\n";
@@ -91,16 +87,15 @@ namespace rubinius {
     std::cout << "       memory ratio: " << ratio << "\n";
     std::cout << "\n== x86 assembly ==\n";
     assembler_x86::AssemblerX86::show_buffer(function(), code_size_, false, comments_);
-    */
     return Qnil;
   }

-  void MachineMethod::run_code(STATE, VMMethod* const vmm,
+  Object * MachineMethod::run_code(STATE, VMMethod* const vmm,
       CallFrame* const call_frame) {
 #ifdef IS_X86
     MachineMethod* mm = vmm->machine_method();
     void* func = mm->function();
-    ((Runner)func)(state, vmm, call_frame);
+    return ((Runner)func)(state, vmm, call_frame);
 #else
     Assertion::raise("Only supported on x86");
 #endif
diff --git a/vm/builtin/machine_method.hpp b/vm/builtin/machine_method.hpp
index 718a865..bc74e8f 100644
--- a/vm/builtin/machine_method.hpp
+++ b/vm/builtin/machine_method.hpp
@@ -25,6 +25,8 @@ namespace rubinius {
     static void init(STATE);
     static MachineMethod* create(STATE, VMMethod* vmm, JITCompiler& jit);

+    void cleanup();
+
     void* function() {
       return reinterpret_cast<void*>(function_);
     }
@@ -34,7 +36,7 @@ namespace rubinius {
     }

     // Used for debugging. Gives us a place to break on before entering jit'd code
-    static void run_code(STATE, VMMethod* const vmm, CallFrame* const call_frame);
+    static Object * run_code(STATE, VMMethod* const vmm, CallFrame* const call_frame);

     // Ruby.primitive :machine_method_show
     Object* show();
diff --git a/vm/builtin/variable_scope.hpp b/vm/builtin/variable_scope.hpp
index b93b0e2..5640585 100644
--- a/vm/builtin/variable_scope.hpp
+++ b/vm/builtin/variable_scope.hpp
@@ -122,7 +122,9 @@ namespace rubinius {
     CompiledMethod* method_;  // slot
     Module*         module_;  // slot
     VariableScope*  parent_;  // slot
+  public:  // required for JIT
     Object*         self_;    // slot
+  public:

     int             number_of_locals_;
     Object*         locals_[];
diff --git a/vm/call_frame.hpp b/vm/call_frame.hpp
index f9d2010..0e55f1f 100644
--- a/vm/call_frame.hpp
+++ b/vm/call_frame.hpp
@@ -28,6 +28,7 @@ namespace rubinius {
     int flags;
     int args;
     int ip;
+    int native_ip;

     int stack_size;
     struct jit_state js;
@@ -47,6 +48,7 @@ namespace rubinius {
     void prepare(int stack) {
       is_block = false;
       ip = 0;
+      native_ip = 0;
       current_unwind = 0;
       stack_size = stack;

@@ -133,6 +135,10 @@ namespace rubinius {
       ip = new_ip;
     }

+    void set_native_ip(void * new_ip) {
+      native_ip = (int)new_ip;
+    }
+
     // Manage the dynamic Unwind stack for this context
     void push_unwind(int target_ip, UnwindType type) {
       assert(current_unwind < kMaxUnwindInfos);
diff --git a/vm/codegen/instructions_gen.rb b/vm/codegen/instructions_gen.rb
index 1edfe76..b32ca5b 100644
--- a/vm/codegen/instructions_gen.rb
+++ b/vm/codegen/instructions_gen.rb
@@ -66,7 +66,7 @@ class Instructions
     # Indicates if this opcode dynamicly defines whether
     # execution should continue
     def custom_continue?
-      /RETURN\(/.match(body)
+      /RETURN\(/.match(body) || /HANDLE_EXCEPTION\(/.match(body) || /RUN_EXCEPTION\(/.match(body)
     end

     # Generate a C signature for the implementation code, to be used as a
@@ -197,9 +197,9 @@ class Instructions
     methods.each do |impl|
       io.puts "#{impl.signature} {"
       io.puts impl.body
-      unless impl.custom_continue?
-        io.puts "return NULL;"
-      end
+      # unless impl.custom_continue?
+        io.puts "return stack_top();"
+      # end
       io.puts "}"
     end
   end
@@ -458,6 +458,17 @@ CODE
     code << "  return -1;\n"
     code << "}\n"

+    regular = InstructionSet::OpCodes.size
+    code << "int reverse_superop(opcode superop) {\n"
+    code << "  static int superops[] = {"
+    @superinsns.each_with_index do |combo, superop|
+      insn = InstructionSet[combo.first]
+      code << " #{insn.bytecode},"
+    end
+    code << "};\n"
+    code << "  if(superop < #{regular}) return superop;\n"
+    code << "  return superops[superop - #{regular}];\n"
+    code << "}\n"
 =begin
     code << "int find_superop(opcode* stream) {\n"
     code << "  opcode one = stream[0];\n"
@@ -515,10 +526,10 @@ CODE
     str << "static Status check_status[] = {\n"
     methods = decode_methods()
     methods.each do |impl|
-      if impl.custom_continue?
-        str << "MightReturn,\n"
-      elsif [:return, :raise].include?(impl.name.flow)
+      if [:return, :raise].include?(impl.name.flow)
         str << "Terminate,\n"
+      elsif impl.custom_continue?
+        str << "MightReturn,\n"
       else
         str << "Unchanged,\n"
       end
diff --git a/vm/drivers/jit-test.cpp b/vm/drivers/jit-test.cpp
index 40b3010..b7a2a6f 100644
--- a/vm/drivers/jit-test.cpp
+++ b/vm/drivers/jit-test.cpp
@@ -1,9 +1,12 @@
 #include "prelude.hpp"
 #include "object_utils.hpp"
+#include "vmmethod.hpp"
 #include "jit.hpp"
 #include "environment.hpp"
+#include "config_parser.hpp"

 #include "builtin/compiledmethod.hpp"
+#include "builtin/machine_method.hpp"
 #include "compiled_file.hpp"

 #include <iostream>
@@ -14,7 +17,16 @@ using namespace std;

 int main(int argc, char **argv) {
   JITCompiler compiler;
-  VM state;
+  VMManager * manager = new VMManager;
+  SharedState * shared = manager->create_shared_state();
+  ConfigParser * config = new ConfigParser;
+  shared->user_config = config;
+  VM * state = shared->new_vm();
+
+  state->initialize(VM::default_bytes);
+  state->boot();
+
+  state->global_lock().lock();

   std::ifstream stream(argv[1]);
   if(!stream) {
@@ -27,11 +39,12 @@ int main(int argc, char **argv) {
     cout << "Invalid file.\n";
   }

-  VMMethod* vmm = as<CompiledMethod>(cf->body(&state))->formalize(&state, false);
+  VMMethod* vmm = as<CompiledMethod>(cf->body(state))->formalize(state, false);

   delete cf;

-  MachineMethod* mm = compiler.compile(vmm);
+  compiler.compile(state, vmm);
+  MachineMethod* mm = MachineMethod::create(state, vmm, compiler);
   mm->show();
   return 0;
 }
diff --git a/vm/instructions.hpp b/vm/instructions.hpp
index 0c387a1..fdb6c93 100644
--- a/vm/instructions.hpp
+++ b/vm/instructions.hpp
@@ -20,6 +20,7 @@ namespace rubinius {

     Status check_status(int op);
     int find_superop(opcode* stream);
+    int reverse_superop(opcode superop);
   }
 }

diff --git a/vm/vmmethod.cpp b/vm/vmmethod.cpp
index f2a977a..cba5246 100644
--- a/vm/vmmethod.cpp
+++ b/vm/vmmethod.cpp
@@ -25,6 +25,8 @@

 #include "raise_reason.hpp"

+#include "assembler/jit.hpp"
+
 #define CALLS_TIL_JIT 50
 #define JIT_MAX_METHOD_SIZE 2048

@@ -476,6 +478,23 @@ namespace rubinius {
       CompiledMethod* cm = as<CompiledMethod>(msg.method);
       VMMethod* vmm = cm->backend_method_;

+#ifdef USE_USAGE_JIT
+    // A negative call_count means we've disabled usage based JIT
+    // for this method.
+    if(vmm->call_count >= 0) {
+      if(vmm->call_count >= CALLS_TIL_JIT) {
+        state->stats.jitted_methods++;
+        uint64_t start = get_current_time();
+        MachineMethod* mm = cm->make_machine_method(state);
+        mm->activate();
+        vmm->call_count = -1;
+        state->stats.jit_timing += (get_current_time() - start);
+      } else {
+        vmm->call_count++;
+      }
+    }
+#endif
+
       VariableScope* scope = (VariableScope*)alloca(sizeof(VariableScope) +
                                  (vmm->number_of_locals * sizeof(Object*)));

@@ -700,6 +719,9 @@ namespace rubinius {
           UnwindInfo& info = call_frame->pop_unwind();
           call_frame->position_stack(info.stack_depth);
           call_frame->set_ip(info.target_ip);
+          if(vmm->machine_method_.get()) {
+            call_frame->set_native_ip(vmm->machine_method_->resolve_virtual_ip(info.target_ip));
+          }
         } else {
           return NULL;
         }
@@ -714,6 +736,9 @@ namespace rubinius {
           if(info.for_ensure()) {
             call_frame->position_stack(info.stack_depth);
             call_frame->set_ip(info.target_ip);
+            if(vmm->machine_method_.get()) {
+              call_frame->set_native_ip(vmm->machine_method_->resolve_virtual_ip(info.target_ip));
+            }

             // Don't reset ep here, we're still handling the return/break.
             goto continue_to_run;