<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -3,6 +3,7 @@ Build:
   - Or at least advise that it might need to be run (hm)
 
 JIT:
+- Remove simple_send path in meta_send_op_*
 - Method lookup from IC results should include private methods
 - Debug JIT crashes on elle @urgent
 - Inline all methods</diff>
      <filename>doc/evan.taskpaper</filename>
    </modified>
    <modified>
      <diff>@@ -75,18 +75,22 @@ namespace rubinius {
 #ifdef ENABLE_LLVM
     if(vmm-&gt;call_count &gt;= 0) {
       if(vmm-&gt;call_count &gt;= state-&gt;shared.config.jit_call_til_compile) {
-        vmm-&gt;call_count = -1; // So we don't try and jit twice at the same time
-        state-&gt;stats.jitted_methods++;
-
         LLVMState* ls = LLVMState::get(state);
 
-        ls-&gt;compile_soon(state, vmm, env);
+        if(state-&gt;shared.config.jit_inline_blocks) {
+          if(VMMethod* parent = vmm-&gt;parent()) {
+            while(VMMethod* next = parent-&gt;parent()) {
+              parent = next;
+            }
 
-        if(state-&gt;shared.config.jit_show_compiling) {
-          std::cout &lt;&lt; &quot;[[[ JIT Queued method &quot;
-                    &lt;&lt; ls-&gt;queued_methods() &lt;&lt; &quot;/&quot;
-                    &lt;&lt; ls-&gt;jitted_methods() &lt;&lt; &quot; ]]]\n&quot;;
+            if(parent-&gt;call_count &gt;= 200) {
+              ls-&gt;compile_soon(state, parent);
+            }
+          }
         }
+
+        ls-&gt;compile_soon(state, vmm, env);
+
       } else {
         vmm-&gt;call_count++;
       }
@@ -191,6 +195,8 @@ namespace rubinius {
         vmm-&gt;specialize(state, caller-&gt;type);
       }
       caller-&gt;blocks[index] = vmm;
+
+      vmm-&gt;set_parent(caller);
     }
 
     be-&gt;scope(state, call_frame-&gt;promote_scope(state));</diff>
      <filename>vm/builtin/block_environment.cpp</filename>
    </modified>
    <modified>
      <diff>@@ -54,6 +54,14 @@ namespace rubinius {
     return as&lt;Fixnum&gt;(lines_-&gt;at(state, 1))-&gt;to_native();
   }
 
+  int CompiledMethod::start_line() {
+    if(lines_-&gt;nil_p()) return -1;
+    if(lines_-&gt;num_fields() &lt; 2) return -1;
+    // This is fixed as one because entry 0 is always ip = 0 and
+    // 1 is the first line
+    return as&lt;Fixnum&gt;(lines_-&gt;at(1))-&gt;to_native();
+  }
+
   int CompiledMethod::line(STATE, int ip) {
     if(lines_-&gt;nil_p()) return -3;
 </diff>
      <filename>vm/builtin/compiledmethod.cpp</filename>
    </modified>
    <modified>
      <diff>@@ -67,6 +67,7 @@ namespace rubinius {
     static Object* primitive_failed(STATE, CallFrame* call_frame, Dispatch&amp; msg, Arguments&amp; args);
 
     int start_line(STATE);
+    int start_line();
     int line(STATE, int ip);
 
     void post_marshal(STATE);</diff>
      <filename>vm/builtin/compiledmethod.hpp</filename>
    </modified>
    <modified>
      <diff>@@ -22,6 +22,7 @@ namespace rubinius {
     config::Bool    jit_profile;
     config::Bool    jit_inline_generic;
     config::Bool    jit_inline_debug;
+    config::Bool    jit_inline_blocks;
 
     config::BoolSet jit_defaults;
 
@@ -54,6 +55,7 @@ namespace rubinius {
       , jit_profile(this,     &quot;jit.profile&quot;)
       , jit_inline_generic(this, &quot;jit.inline.generic&quot;)
       , jit_inline_debug(this, &quot;jit.inline.debug&quot;)
+      , jit_inline_blocks(this, &quot;jit.inline.blocks&quot;)
       , jit_defaults(this, &quot;J&quot;)
       , gil_debug(this,       &quot;vm.gil.debug&quot;)
       , print_config(this,    &quot;config.print&quot;)
@@ -92,6 +94,9 @@ namespace rubinius {
       jit_inline_debug.set_description(
           &quot;Have the JIT print out information about inlining&quot;);
 
+      jit_inline_blocks.set_description(
+          &quot;Have the JIT try and inline methods and their literal blocks&quot;);
+
       jit_defaults.set_description(
           &quot;Enable the JIT and generic inlining&quot;);
 </diff>
      <filename>vm/configuration.hpp</filename>
    </modified>
    <modified>
      <diff>@@ -231,6 +231,18 @@ namespace rubinius {
         if(h1 * 10 &lt; h2) return seen_classes_[1].klass();
         return NULL;
       }
+
+      case 3: {
+        int h1 = seen_classes_[0].hits();
+        int h2 = seen_classes_[1].hits();
+        int h3 = seen_classes_[2].hits();
+
+        if(h2 * 10 &lt; h1 &amp;&amp; h3 * 10 &lt; h1) return seen_classes_[0].klass();
+        if(h1 * 10 &lt; h2 &amp;&amp; h3 * 10 &lt; h2) return seen_classes_[1].klass();
+        if(h1 * 10 &lt; h3 &amp;&amp; h2 * 10 &lt; h3) return seen_classes_[2].klass();
+
+        return NULL;
+      }
       default:
         return NULL;
       }</diff>
      <filename>vm/inline_cache.hpp</filename>
    </modified>
    <modified>
      <diff>@@ -55,10 +55,12 @@ namespace rubinius {
       } else if(detect_trivial_method(cm)) {
         inline_trivial_method(klass, cm);
       } else if(ops_.state()-&gt;config().jit_inline_generic) {
-        InlineDecision decision = ops_.should_inline_p(vmm);
+        InlinePolicy* policy = ops_.inline_policy();
+        assert(policy);
+
+        InlineDecision decision = policy-&gt;inline_p(vmm);
         if(decision != cInline) {
           if(ops_.state()-&gt;config().jit_inline_debug) {
-            InlinePolicy* policy = ops_.inline_policy();
 
             std::cerr &lt;&lt; &quot;NOT inlining: &quot;
               &lt;&lt; ops_.state()-&gt;symbol_cstr(cm-&gt;scope()-&gt;module()-&gt;name())
@@ -92,6 +94,7 @@ namespace rubinius {
             &lt;&lt; &quot; (&quot; &lt;&lt; ops_.state()-&gt;symbol_cstr(klass-&gt;name()) &lt;&lt; &quot;)\n&quot;;
         }
 
+        policy-&gt;increase_size(vmm);
         NoAccessManagedMemory unmemguard(ops_.state());
         inline_generic_method(klass, vmm);
       } else {
@@ -137,6 +140,31 @@ namespace rubinius {
     return true;
   }
 
+  void Inliner::inline_block(VMMethod* vmm, Value* self) {
+    AccessManagedMemory memguard(ops_.state());
+
+    CompiledMethod* cm = vmm-&gt;original.get();
+
+    if(detect_trivial_method(cm)) {
+      if(ops_.state()-&gt;config().jit_inline_debug) {
+        std::cerr &lt;&lt; &quot;inlining trivial block into: &quot;
+          &lt;&lt; ops_.state()-&gt;symbol_cstr(ops_.vmmethod()-&gt;original-&gt;name())
+          &lt;&lt; &quot;\n&quot;;
+      }
+
+      inline_trivial_method(0, cm);
+    } else {
+      if(ops_.state()-&gt;config().jit_inline_debug) {
+        std::cerr &lt;&lt; &quot;inlining block into: &quot;
+          &lt;&lt; ops_.state()-&gt;symbol_cstr(ops_.vmmethod()-&gt;original-&gt;name())
+          &lt;&lt; &quot;\n&quot;;
+      }
+
+      NoAccessManagedMemory unmemguard(ops_.state());
+      emit_inline_block(vmm, self);
+    }
+  }
+
   bool Inliner::detect_trivial_method(CompiledMethod* cm) {
     VMMethod* vmm = cm-&gt;backend_method();
 
@@ -175,7 +203,9 @@ namespace rubinius {
 
     Value* self = recv();
 
-    ops_.check_class(self, klass, failure());
+    if(klass) {
+      ops_.check_class(self, klass, failure());
+    }
 
     Value* val = 0;
     /////
@@ -321,32 +351,83 @@ namespace rubinius {
     set_result(ivar);
   }
 
-  void Inliner::inline_generic_method(Class* klass, VMMethod* vmm) {
-    LLVMWorkHorse work(ops_.state(), vmm);
-    work.valid_flag = ops_.valid_flag();
-
+  void Inliner::inline_generic_method(Class* klass, VMMethod* vmm, bool pass_block) {
     Value* self = recv();
-
     ops_.check_class(self, klass, failure());
 
+    JITMethodInfo info(vmm);
+    info.set_parent_info(ops_.info());
+
+    BasicBlock* on_return = ops_.new_block(&quot;inline_return&quot;);
+    info.inline_return = on_return;
+    info.inline_policy = ops_.inline_policy();
+    info.called_args = count_;
+    info.root = ops_.root_method_info();
+    info.passed_block = passed_block_;
+
+    LLVMWorkHorse work(ops_.state(), info);
+    work.valid_flag = ops_.valid_flag();
+
+    Value* blk = 0;
+
     std::vector&lt;Value*&gt; args;
-    for(int i = count_ - 1; i &gt;= 0; i--) {
-      args.push_back(ops_.stack_back(i));
+    if(block_on_stack_) {
+      blk = ops_.stack_top();
+      for(int i = count_; i &gt;= 1; i--) {
+        args.push_back(ops_.stack_back(i));
+      }
+    } else {
+      blk = ops_.constant(Qnil);
+      for(int i = count_ - 1; i &gt;= 0; i--) {
+        args.push_back(ops_.stack_back(i));
+      }
     }
 
     vmm-&gt;call_count /= 2;
 
-    BasicBlock* entry = work.setup_inline(ops_.function(), ops_.vm(), ops_.call_frame(),
-        self, ops_.constant(Qnil, ops_.state()-&gt;ptr_type(&quot;Module&quot;)), args);
+    BasicBlock* entry = work.setup_inline(self, blk,
+        ops_.constant(Qnil, ops_.state()-&gt;ptr_type(&quot;Module&quot;)), args);
 
-    BasicBlock* on_return = ops_.new_block(&quot;inline_return&quot;);
+    assert(work.generate_body());
+
+    on_return-&gt;moveAfter(info.fin_block);
+
+    ops_.create_branch(entry);
+
+    ops_.set_block(on_return);
+
+    ops_.b().Insert(cast&lt;Instruction&gt;(info.return_value));
+
+    set_result(info.return_value);
+  }
+
+  void Inliner::emit_inline_block(VMMethod* vmm, Value* self) {
     JITMethodInfo info(vmm);
+    info.set_parent_info(ops_.info());
+
+    BasicBlock* on_return = ops_.new_block(&quot;inline_return&quot;);
     info.inline_return = on_return;
     info.inline_policy = ops_.inline_policy();
     info.called_args = count_;
     info.root = ops_.root_method_info();
+    info.passed_block = passed_block_;
+
+    LLVMWorkHorse work(ops_.state(), info);
+    work.valid_flag = ops_.valid_flag();
+
+    std::vector&lt;Value*&gt; args;
+    for(int i = count_ - 1; i &gt;= 0; i--) {
+      args.push_back(ops_.stack_back(i));
+    }
+
+    info.stack_args = &amp;args;
+
+    vmm-&gt;call_count /= 2;
+
+    BasicBlock* entry = work.setup_inline_block(self,
+        ops_.constant(Qnil, ops_.state()-&gt;ptr_type(&quot;Module&quot;)));
 
-    assert(work.generate_body(info));
+    assert(work.generate_body());
 
     on_return-&gt;moveAfter(info.fin_block);
 </diff>
      <filename>vm/llvm/inline.cpp</filename>
    </modified>
    <modified>
      <diff>@@ -14,9 +14,13 @@ namespace rubinius {
     JITOperations&amp; ops_;
     InlineCache* cache_;
     int count_;
+    int self_pos_;
     BasicBlock* failure_;
     Value* result_;
     bool check_for_exception_;
+    VMMethod* passed_block_;
+
+    bool block_on_stack_;
 
   public:
 
@@ -24,17 +28,30 @@ namespace rubinius {
       : ops_(ops)
       , cache_(cache)
       , count_(count)
+      , self_pos_(count)
       , failure_(failure)
       , result_(0)
       , check_for_exception_(true)
+      , passed_block_(0)
+      , block_on_stack_(false)
+    {}
+
+    Inliner(JITOperations&amp; ops, int count)
+      : ops_(ops)
+      , cache_(0)
+      , count_(count)
+      , failure_(0)
+      , result_(0)
+      , check_for_exception_(true)
+      , passed_block_(0)
     {}
 
     Value* recv() {
-      return ops_.stack_back(count_);
+      return ops_.stack_back(self_pos_);
     }
 
     Value* arg(int which) {
-      return ops_.stack_back(count_ - (which + 1));
+      return ops_.stack_back(self_pos_ - (which + 1));
     }
 
     BasicBlock* failure() {
@@ -57,9 +74,19 @@ namespace rubinius {
       return check_for_exception_;
     }
 
+    void set_passed_block(CompiledMethod* cm) {
+      passed_block_ = cm-&gt;backend_method();
+    }
+
+    void set_block_on_stack() {
+      self_pos_++;
+      block_on_stack_ = true;
+    }
+
     bool consider();
+    void inline_block(VMMethod* vmm, Value* self);
 
-    void inline_generic_method(Class* klass, VMMethod* vmm);
+    void inline_generic_method(Class* klass, VMMethod* vmm, bool pass_block=false);
 
     bool detect_trivial_method(CompiledMethod* cm);
 
@@ -72,6 +99,8 @@ namespace rubinius {
     bool inline_primitive(Class* klass, CompiledMethod* cm, executor prim);
 
     bool inline_ffi(Class* klass, NativeFunction* nf);
+
+    void emit_inline_block(VMMethod* vmm, Value* val);
   };
 
 }</diff>
      <filename>vm/llvm/inline.hpp</filename>
    </modified>
    <modified>
      <diff>@@ -25,7 +25,7 @@ namespace rubinius {
       return true;
     }
 
-    void visit_create_block(opcode which) {
+    void visit_push_block() {
       throw Unsupported();
     }
 
@@ -79,19 +79,21 @@ namespace rubinius {
       return true;
     }
 
-    InlineDecision inline_p(VMMethod* vmm) {
+    InlineDecision inline_p(VMMethod* vmm, bool check_size=true) {
       if(!InlineEvaluator::can_inline_p(vmm)) return cTooComplex;
-      if(!check_size_p(vmm)) return cTooBig;
+      if(check_size &amp;&amp; !check_size_p(vmm)) return cTooBig;
+      return cInline;
+    }
 
+    void increase_size(VMMethod* vmm) {
       current_size_ += vmm-&gt;total;
-      return cInline;
     }
   };
 
   class SmallMethodInlinePolicy : public InlinePolicy {
   public:
     const static bool is_small_p(VMMethod* vmm) {
-      if(vmm-&gt;total &lt; 10) return true;
+      if(vmm-&gt;total &lt; 20) return true;
       return false;
     }
 </diff>
      <filename>vm/llvm/inline_policy.hpp</filename>
    </modified>
    <modified>
      <diff>@@ -418,6 +418,10 @@ namespace rubinius {
     Object* placement;
     bool is_block = false;
 
+    // Ignore it!
+    if(vmm-&gt;call_count &lt; 0) return;
+    vmm-&gt;call_count = -1;
+
     if(block) {
       is_block = true;
       placement = block;
@@ -425,12 +429,21 @@ namespace rubinius {
       placement = state-&gt;new_struct&lt;MachineMethod&gt;(G(machine_method));
     }
 
+    state-&gt;stats.jitted_methods++;
+
     BackgroundCompileRequest* req =
       new BackgroundCompileRequest(state, vmm, placement, is_block);
 
     queued_methods_++;
 
     background_thread_-&gt;add(req);
+
+    if(state-&gt;shared.config.jit_show_compiling) {
+      std::cout &lt;&lt; &quot;[[[ JIT Queued&quot;
+                &lt;&lt; (block ? &quot; block &quot; : &quot; method &quot;)
+                &lt;&lt; queued_methods() &lt;&lt; &quot;/&quot;
+                &lt;&lt; jitted_methods() &lt;&lt; &quot; ]]]\n&quot;;
+    }
   }
 
   void LLVMState::remove(llvm::Function* func) {
@@ -442,8 +455,11 @@ namespace rubinius {
     func-&gt;eraseFromParent();
   }
 
+  const static int cInlineMaxDepth = 8;
+
   VMMethod* LLVMState::find_candidate(VMMethod* start, CallFrame* call_frame) {
     VMMethod* last = start;
+    int depth = 0;
 
     // No upper call_frames or generic inlining is off, use the start.
     // With generic inlining off, there is no way to inline back to start,
@@ -451,14 +467,25 @@ namespace rubinius {
     if(!call_frame || !config_.jit_inline_generic) return last;
 
     VMMethod* cur = call_frame-&gt;cm-&gt;backend_method();
-    while(cur-&gt;required_args == cur-&gt;total_args &amp;&amp;
-          cur-&gt;call_count &gt;= 200 &amp;&amp;
-          !cur-&gt;jitted() &amp;&amp;
-          cur-&gt;total &gt; 10) {
-      last = cur;
+    while(depth &lt; cInlineMaxDepth) {
+      if(cur-&gt;required_args != cur-&gt;total_args ||
+          cur-&gt;call_count &lt; 200 ||
+          cur-&gt;jitted() ||
+          cur-&gt;total &lt; 10) break;
+
       call_frame = call_frame-&gt;previous;
       if(!call_frame) break;
+
       cur = call_frame-&gt;cm-&gt;backend_method();
+
+      // Jump to defining methods of blocks!
+      if(VMMethod* parent = cur-&gt;parent()) {
+        cur = parent;
+      } else {
+        last = cur;
+      }
+
+      depth++;
     }
 
     return last;
@@ -466,13 +493,29 @@ namespace rubinius {
 
   void LLVMCompiler::compile(LLVMState* ls, VMMethod* vmm, bool is_block) {
     if(ls-&gt;config().jit_inline_debug) {
-      std::cerr &lt;&lt; &quot;JIT: compiling &quot;
-                &lt;&lt; ls-&gt;symbol_cstr(vmm-&gt;original-&gt;scope()-&gt;module()-&gt;name())
-                &lt;&lt; &quot;#&quot;
-                &lt;&lt; ls-&gt;symbol_cstr(vmm-&gt;original-&gt;name()) &lt;&lt; &quot;\n&quot;;
+      if(is_block) {
+        VMMethod* parent = vmm-&gt;parent();
+        assert(parent);
+
+        std::cerr &lt;&lt; &quot;JIT: compiling block in &quot;
+                  &lt;&lt; ls-&gt;symbol_cstr(parent-&gt;original-&gt;scope()-&gt;module()-&gt;name())
+                  &lt;&lt; &quot;#&quot;
+                  &lt;&lt; ls-&gt;symbol_cstr(vmm-&gt;original-&gt;name())
+                  &lt;&lt; &quot; near &quot;
+                  &lt;&lt; ls-&gt;symbol_cstr(vmm-&gt;original-&gt;file()) &lt;&lt; &quot;:&quot;
+                  &lt;&lt; vmm-&gt;original-&gt;start_line() &lt;&lt; &quot;\n&quot;;
+      } else {
+        std::cerr &lt;&lt; &quot;JIT: compiling &quot;
+                  &lt;&lt; ls-&gt;symbol_cstr(vmm-&gt;original-&gt;scope()-&gt;module()-&gt;name())
+                  &lt;&lt; &quot;#&quot;
+                  &lt;&lt; ls-&gt;symbol_cstr(vmm-&gt;original-&gt;name()) &lt;&lt; &quot;\n&quot;;
+      }
     }
 
-    LLVMWorkHorse work(ls, vmm);
+    JITMethodInfo info(vmm);
+    info.is_block = is_block;
+
+    LLVMWorkHorse work(ls, info);
 
     if(is_block) {
       work.setup_block();
@@ -480,12 +523,9 @@ namespace rubinius {
       work.setup();
     }
 
-    llvm::Function* func = work.func;
-
-    JITMethodInfo info(vmm);
-    info.is_block = is_block;
+    llvm::Function* func = info.function();
 
-    if(!work.generate_body(info)) {
+    if(!work.generate_body()) {
       function_ = NULL;
       // This is too noisy to report
       // std::cout &lt;&lt; &quot;not supported yet.\n&quot;;
@@ -604,4 +644,10 @@ namespace rubinius {
 
 }
 
+extern &quot;C&quot; {
+  void llvm_dump(Value* val) {
+    std::cout &lt;&lt; *val;
+  }
+}
+
 #endif</diff>
      <filename>vm/llvm/jit.cpp</filename>
    </modified>
    <modified>
      <diff>@@ -30,7 +30,24 @@ namespace rubinius {
 
   class InlinePolicy;
 
-  struct JITMethodInfo {
+  class JITMethodInfo {
+    llvm::Function* function_;
+    llvm::BasicBlock* entry_;
+    llvm::Value* call_frame_;
+    llvm::Value* stack_;
+    llvm::Value* vm_;
+    llvm::Value* args_;
+    llvm::Value* variables_;
+    llvm::Value* previous_;
+    llvm::Value* profiling_entry_;
+    llvm::PHINode* block_break_result_;
+    llvm::BasicBlock* block_break_loc_;
+
+    JITMethodInfo* parent_info_;
+
+    bool use_full_scope_;
+
+  public:
     VMMethod* vmm;
     bool is_block;
     llvm::BasicBlock* inline_return;
@@ -38,18 +55,151 @@ namespace rubinius {
     InlinePolicy* inline_policy;
     llvm::BasicBlock* fin_block;
     int called_args;
+    VMMethod* passed_block;
+    std::vector&lt;llvm::Value*&gt;* stack_args;
+
     JITMethodInfo* root;
 
-    JITMethodInfo(VMMethod* v)
-      : vmm(v)
+  public:
+    JITMethodInfo(VMMethod* v, JITMethodInfo* parent = 0)
+      : function_(0)
+      , entry_(0)
+      , call_frame_(0)
+      , stack_(0)
+      , vm_(0)
+      , args_(0)
+      , previous_(0)
+      , profiling_entry_(0)
+      , parent_info_(parent)
+      , use_full_scope_(false)
+      , vmm(v)
       , is_block(false)
       , inline_return(0)
       , return_value(0)
       , inline_policy(0)
       , fin_block(0)
       , called_args(-1)
+      , passed_block(0)
+      , stack_args(0)
       , root(0)
     {}
+
+    void set_function(llvm::Function* func) {
+      function_ = func;
+    }
+
+    llvm::Function* function() {
+      return function_;
+    }
+
+    void set_vm(llvm::Value* vm) {
+      vm_ = vm;
+    }
+
+    llvm::Value* vm() {
+      return vm_;
+    }
+
+    void set_args(llvm::Value* args) {
+      args_ = args;
+    }
+
+    llvm::Value* args() {
+      return args_;
+    }
+
+    void set_previous(llvm::Value* prev) {
+      previous_ = prev;
+    }
+
+    llvm::Value* previous() {
+      return previous_;
+    }
+
+    void set_profiling_entry(llvm::Value* val) {
+      profiling_entry_ = val;
+    }
+
+    llvm::Value* profiling_entry() {
+      return profiling_entry_;
+    }
+
+    void set_entry(llvm::BasicBlock* entry) {
+      entry_ = entry;
+    }
+
+    llvm::BasicBlock* entry() {
+      return entry_;
+    }
+
+    void set_call_frame(llvm::Value* val) {
+      call_frame_ = val;
+    }
+
+    llvm::Value* call_frame() {
+      return call_frame_;
+    }
+
+    void set_stack(llvm::Value* val) {
+      stack_ = val;
+    }
+
+    llvm::Value* stack() {
+      return stack_;
+    }
+
+    void set_variables(llvm::Value* vars) {
+      variables_ = vars;
+    }
+
+    llvm::Value* variables() {
+      return variables_;
+    }
+
+    void set_parent_info(JITMethodInfo&amp; info) {
+      parent_info_ = &amp;info;
+      function_ = info.function();
+      vm_ = info.vm();
+    }
+
+    llvm::Value* parent_call_frame() {
+      if(parent_info_) {
+        return parent_info_-&gt;call_frame();
+      }
+
+      return 0;
+    }
+
+    JITMethodInfo* parent_info() {
+      return parent_info_;
+    }
+
+    llvm::BasicBlock* block_break_loc() {
+      return block_break_loc_;
+    }
+
+    llvm::PHINode* block_break_result() {
+      return block_break_result_;
+    }
+
+    void set_block_break(llvm::BasicBlock* block, llvm::PHINode* p) {
+      block_break_result_ = p;
+      block_break_loc_ = block;
+    }
+
+    void clear_block_break() {
+      block_break_result_ = 0;
+      block_break_loc_ = 0;
+    }
+
+    bool use_full_scope() {
+      return use_full_scope_;
+    }
+
+    void set_use_full_scope() {
+      use_full_scope_ = true;
+    }
+
   };
 
   struct JITBasicBlock {</diff>
      <filename>vm/llvm/jit.hpp</filename>
    </modified>
    <modified>
      <diff>@@ -62,17 +62,15 @@ namespace rubinius {
     llvm::Value* One;
 
   public:
-    JITOperations(LLVMState* ls, JITMethodInfo&amp; info, llvm::Module* mod,
-                  llvm::Value* stack, llvm::Value* call_frame,
-                  llvm::BasicBlock* start, llvm::Function* func)
-      : stack_(stack)
+    JITOperations(LLVMState* ls, JITMethodInfo&amp; info, llvm::BasicBlock* start)
+      : stack_(info.stack())
       , sp_(-1)
       , last_sp_(-1)
       , method_info_(info)
       , ls_(ls)
-      , module_(mod)
-      , function_(func)
-      , call_frame_(call_frame)
+      , module_(ls-&gt;module())
+      , function_(info.function())
+      , call_frame_(info.call_frame())
       , inline_policy_(0)
       , own_policy_(false)
     {
@@ -133,6 +131,10 @@ namespace rubinius {
       return inline_policy_;
     }
 
+    JITMethodInfo&amp; info() {
+      return method_info_;
+    }
+
     VMMethod* vmmethod() {
       return method_info_.vmm;
     }
@@ -145,6 +147,14 @@ namespace rubinius {
       }
     }
 
+    VMMethod* passed_block() {
+      return method_info_.passed_block;
+    }
+
+    std::vector&lt;Value*&gt;* incoming_args() {
+      return method_info_.stack_args;
+    }
+
     JITMethodInfo* root_method_info() {
       if(method_info_.root) {
         return method_info_.root;
@@ -169,11 +179,6 @@ namespace rubinius {
       return call_frame_;
     }
 
-    InlineDecision should_inline_p(VMMethod* vmm) {
-      if(inline_policy_) return inline_policy_-&gt;inline_p(vmm);
-      return cNoPolicy;
-    }
-
     static Value* cint(int num) {
       return ConstantInt::get(Type::Int32Ty, num);
     }</diff>
      <filename>vm/llvm/jit_operations.hpp</filename>
    </modified>
    <modified>
      <diff>@@ -28,6 +28,8 @@
 #include &quot;lookup_data.hpp&quot;
 #include &quot;inline_cache.hpp&quot;
 
+#include &lt;cstdarg&gt;
+
 #define both_fixnum_p(_p1, _p2) ((uintptr_t)(_p1) &amp; (uintptr_t)(_p2) &amp; TAG_FIXNUM)
 
 using namespace rubinius;
@@ -156,6 +158,35 @@ extern &quot;C&quot; {
                                               call_frame, index);
   }
 
+  Object* rbx_create_block_multi(STATE, CompiledMethod* cm, int index, int count, ...) {
+    va_list ap;
+
+    CallFrame* closest = 0;
+    VariableScope* top = 0;
+    VariableScope* parent = 0;
+
+    va_start(ap, count);
+    for(int i = 0; i &lt; count; i++) {
+      closest = va_arg(ap, CallFrame*);
+      closest-&gt;scope-&gt;set_parent(parent);
+      parent = closest-&gt;promote_scope(state);
+
+      if(!top) {
+        top = parent;
+      } else {
+        closest-&gt;flags |= CallFrame::cMultipleScopes;
+        closest-&gt;top_scope_ = top;
+      }
+    }
+    va_end(ap);
+
+    // TODO: We don't need to be doing this everytime.
+    cm-&gt;scope(state, closest-&gt;static_scope());
+
+    VMMethod* vmm = closest-&gt;previous-&gt;cm-&gt;backend_method();
+    return BlockEnvironment::under_call_frame(state, cm, vmm, closest, index);
+  }
+
   Object* rbx_promote_variables(STATE, CallFrame* call_frame) {
     return call_frame-&gt;promote_scope(state);
   }
@@ -223,6 +254,35 @@ extern &quot;C&quot; {
     return ary;
   }
 
+  Object* rbx_cast_for_multi_block_arg_varargs(STATE, int count, ...) {
+    va_list ap;
+
+    /* If there is only one argument and that thing is an array... */
+    if(count == 1) {
+      va_start(ap, count);
+
+      Object* first = va_arg(ap, Object*);
+      if(!kind_of&lt;Array&gt;(first)) {
+        Array* ary = Array::create(state, 1);
+        ary-&gt;set(state, 0, first);
+        first = ary;
+      }
+
+      va_end(ap);
+      return first;
+    }
+
+    Array* ary = Array::create(state, count);
+
+    va_start(ap, count);
+    for(int i = 0; i &lt; count; i++) {
+      ary-&gt;set(state, i, va_arg(ap, Object*));
+    }
+    va_end(ap);
+
+    return ary;
+  }
+
   Object* rbx_cast_for_single_block_arg(STATE, Arguments&amp; args) {
     int k = args.total();
     if(k == 0) {
@@ -295,6 +355,22 @@ extern &quot;C&quot; {
     return ary;
   }
 
+  Object* rbx_create_array(STATE, int count, ...) {
+    va_list ap;
+
+    Array* ary = Array::create(state, count);
+
+    va_start(ap, count);
+    for(int i = 0; i &lt; count; i++) {
+      Object* obj = va_arg(ap, Object*);
+      ary-&gt;set(state, i, obj);
+    }
+
+    va_end(ap);
+
+    return ary;
+  }
+
   Object* rbx_meta_send_call(STATE, CallFrame* call_frame, int count, Object** args) {
     Object* t1 = args[0];
 </diff>
      <filename>vm/llvm/jit_util.cpp</filename>
    </modified>
    <modified>
      <diff>@@ -84,7 +84,6 @@ namespace rubinius {
     Value* vars_;
     bool use_full_scope_;
 
-    bool is_block_;
     BasicBlock* inline_return_;
     PHINode* return_value_;
 
@@ -104,6 +103,7 @@ namespace rubinius {
     bool has_side_effects_;
 
     int current_ip_;
+    int current_block_;
 
   public:
 
@@ -131,28 +131,25 @@ namespace rubinius {
     }
 
     JITVisit(LLVMState* ls, JITMethodInfo&amp; info, BlockMap&amp; bm,
-             llvm::Module* mod, llvm::Function* func, llvm::BasicBlock* start,
-             llvm::Value* stack, llvm::Value* call_frame,
-             llvm::Value* me, llvm::Value* args,
-             llvm::Value* vars, bool is_block, BasicBlock* inline_return = 0)
-      : JITOperations(ls, info, mod, stack, call_frame, start, func)
+             llvm::BasicBlock* start)
+      : JITOperations(ls, info, start)
       , f(ls)
       , block_map_(bm)
       , allow_private_(false)
       , call_flags_(0)
       , rbx_simple_send_(0)
       , rbx_simple_send_private_(0)
-      , method_entry_(me)
-      , args_(args)
-      , vars_(vars)
+      , method_entry_(info.profiling_entry())
+      , args_(info.args())
+      , vars_(info.variables())
       , use_full_scope_(false)
-      , is_block_(is_block)
-      , inline_return_(inline_return)
+      , inline_return_(info.inline_return)
       , return_value_(0)
       , called_args_(-1)
       , sends_done_(0)
       , has_side_effects_(false)
       , current_ip_(0)
+      , current_block_(-1)
     {}
 
     void initialize() {
@@ -181,10 +178,8 @@ namespace rubinius {
       b().CreateCondBr(isit, ret_raise_val, bail_out_fast_);
 
       set_block(bail_out_fast_);
-      if(!inline_return_) {
-        if(use_full_scope_) {
-          flush_scope_to_heap(vars_);
-        }
+      if(use_full_scope_) {
+        flush_scope_to_heap(vars_);
       }
 
       if(inline_return_) {
@@ -196,9 +191,7 @@ namespace rubinius {
 
       set_block(ret_raise_val);
       Value* crv = f.clear_raise_value.call(&amp;vm_, 1, &quot;crv&quot;, b());
-      if(!inline_return_) {
-        if(use_full_scope_) flush_scope_to_heap(vars_);
-      }
+      if(use_full_scope_) flush_scope_to_heap(vars_);
 
       if(inline_return_) {
         return_value_-&gt;addIncoming(crv, current_block());
@@ -446,11 +439,12 @@ namespace rubinius {
         set_block(cont);
       }
 
+      if(use_full_scope_) flush_scope_to_heap(vars_);
+
       if(inline_return_) {
         return_value_-&gt;addIncoming(stack_top(), current_block());
         b().CreateBr(inline_return_);
       } else {
-        if(use_full_scope_) flush_scope_to_heap(vars_);
         b().CreateRet(stack_top());
       }
     }
@@ -1090,6 +1084,16 @@ namespace rubinius {
       stack_push(b().CreateLoad(val_pos, &quot;local&quot;));
     }
 
+    Value* local_location(Value* vars, opcode which) {
+      Value* idx2[] = {
+        ConstantInt::get(Type::Int32Ty, 0),
+        ConstantInt::get(Type::Int32Ty, offset::vars_tuple),
+        ConstantInt::get(Type::Int32Ty, which)
+      };
+
+      return b().CreateGEP(vars, idx2, idx2+3, &quot;local_pos&quot;);
+    }
+
     void visit_push_local(opcode which) {
       Value* idx2[] = {
         ConstantInt::get(Type::Int32Ty, 0),
@@ -1131,14 +1135,19 @@ namespace rubinius {
       b().CreateStore(val, pos);
     }
 
-    Value* get_self() {
+    Value* get_self(Value* vars = 0) {
+      if(!vars) vars = vars_;
+
+      assert(vars);
+
       return b().CreateLoad(
-          b().CreateConstGEP2_32(vars_, 0, offset::vars_self, &quot;self_pos&quot;));
+          b().CreateConstGEP2_32(vars, 0, offset::vars_self),
+          &quot;self&quot;);
     }
 
     Value* get_block() {
       return b().CreateLoad(
-          b().CreateConstGEP2_32(vars_, 0, offset::vars_block, &quot;self_pos&quot;));
+          b().CreateConstGEP2_32(vars_, 0, offset::vars_block, &quot;block_pos&quot;));
     }
 
     void visit_push_self() {
@@ -1262,9 +1271,50 @@ namespace rubinius {
     }
 
     void visit_create_block(opcode which) {
-      std::vector&lt;const Type*&gt; types;
+      // Don't actually do anything, just register which literal we would
+      // use for the block. The later send handles whether to actually
+      // emit the call to create the block
+      current_block_ = (int)which;
+    }
 
+    bool in_inlined_block() {
+      return inline_return_ &amp;&amp; info().is_block;
+    }
+
+    void emit_create_block(opcode which) {
+      std::vector&lt;const Type*&gt; types;
       types.push_back(VMTy);
+
+      if(in_inlined_block()) {
+        types.push_back(ObjType);
+        types.push_back(Type::Int32Ty);
+        types.push_back(Type::Int32Ty);
+
+        FunctionType* ft = FunctionType::get(ObjType, types, true);
+        Function* func = cast&lt;Function&gt;(
+          module_-&gt;getOrInsertFunction(&quot;rbx_create_block_multi&quot;, ft));
+
+        std::vector&lt;Value*&gt; call_args;
+
+        int count = 0;
+        JITMethodInfo* nfo = &amp;info();
+        while(nfo) {
+          call_args.push_back(nfo-&gt;call_frame());
+          count++;
+          nfo = nfo-&gt;parent_info();
+          if(!nfo) break;
+          nfo = nfo-&gt;parent_info();
+        }
+
+        call_args.push_back(ConstantInt::get(Type::Int32Ty, count));
+        call_args.push_back(ConstantInt::get(Type::Int32Ty, which));
+        call_args.push_back(get_literal(which));
+        call_args.push_back(vm_);
+
+        stack_push(b().CreateCall(func, call_args.rbegin(), call_args.rend(), &quot;create_block&quot;));
+        return;
+      };
+
       types.push_back(CallFrameTy);
       types.push_back(Type::Int32Ty);
 
@@ -1284,22 +1334,148 @@ namespace rubinius {
     void visit_send_stack_with_block(opcode which, opcode args) {
       set_has_side_effects();
 
+      bool has_literal_block = (current_block_ &gt;= 0);
+      bool block_on_stack = !has_literal_block;
+
       InlineCache* cache = reinterpret_cast&lt;InlineCache*&gt;(which);
+      CompiledMethod* block_code = 0;
+
+      if(cache-&gt;method &amp;&amp; ls_-&gt;config().jit_inline_blocks) {
+        if(has_literal_block) {
+          block_code = try_as&lt;CompiledMethod&gt;(literal(current_block_));
+
+          // Run the policy on the block code here, if we're not going to
+          // inline it, don't inline this either.
+          InlineDecision decision = inline_policy()-&gt;inline_p(
+              block_code-&gt;backend_method(), false);
+          if(decision != cInline) {
+            // We're not going to inline it, so emit the call to create it
+            emit_create_block(current_block_);
+            block_on_stack = true;
+            block_code = 0;
+          }
+        } else if(has_literal_block) {
+          block_on_stack = true;
+          emit_create_block(current_block_);
+        }
+
+        BasicBlock* failure = new_block(&quot;fallback&quot;);
+        BasicBlock* cont = new_block(&quot;continue&quot;);
+        BasicBlock* cleanup = new_block(&quot;send_done&quot;);
+        PHINode* send_result = b().CreatePHI(ObjType, &quot;send_result&quot;);
+
+        // Register data for the inlined block to see!
+        info().set_block_break(cleanup, send_result);
+
+        Inliner inl(*this, cache, args, failure);
+
+        if(block_code) {
+          inl.set_passed_block(block_code);
+        } else {
+          inl.set_block_on_stack();
+        }
+
+        if(inl.consider()) {
+          // Uncommon doesn't yet know how to synthesize UnwindInfos, so
+          // don't do uncommon if there are handlers.
+          if(exception_handlers_.size() == 0) {
+            send_result-&gt;addIncoming(inl.result(), b().GetInsertBlock());
+
+            b().CreateBr(cleanup);
+
+            set_block(failure);
+            if(!block_on_stack) {
+              emit_create_block(current_block_);
+              block_on_stack = true;
+            }
+            emit_uncommon();
+
+            set_block(cleanup);
+            send_result-&gt;removeFromParent();
+            cleanup-&gt;getInstList().push_back(send_result);
+
+            // send_result-&gt;moveBefore(&amp;cleanup-&gt;back());
+
+            stack_remove(args+1); // not 2, because we never created the block!
+            if(inl.check_for_exception()) {
+              check_for_exception(send_result);
+            }
+
+            stack_push(send_result);
+
+            b().CreateBr(cont);
+
+            set_block(cont);
+          } else {
+            // Emit both the inlined code and a send for it
+            send_result-&gt;addIncoming(inl.result(), b().GetInsertBlock());
+
+            b().CreateBr(cleanup);
+
+            set_block(failure);
+            if(!block_on_stack) {
+              emit_create_block(current_block_);
+              block_on_stack = true;
+            }
+
+            Value* send_res = block_send(cache, args, allow_private_);
+            b().CreateBr(cleanup);
+
+            set_block(cleanup);
+            send_result-&gt;removeFromParent();
+            cleanup-&gt;getInstList().push_back(send_result);
+
+            send_result-&gt;addIncoming(send_res, failure);
+
+            stack_remove(args + 2);
+            check_for_exception(send_result);
+
+            stack_push(send_result);
+          }
+
+          info().clear_block_break();
+
+          allow_private_ = false;
+
+          // Clear the current block
+          current_block_ = -1;
+          return;
+        }
+
+        // Don't need it.
+        send_result-&gt;eraseFromParent();
+      }
+
+      // Detect a literal block being created and passed here.
+      if(!block_on_stack) {
+        emit_create_block(current_block_);
+      }
+
       Value* ret = block_send(cache, args, allow_private_);
       stack_remove(args + 2);
       check_for_return(ret);
       allow_private_ = false;
+
+      // Clear the current block
+      current_block_ = -1;
     }
 
     void visit_send_stack_with_splat(opcode which, opcode args) {
       set_has_side_effects();
 
+      if(current_block_ &gt;= 0) {
+        emit_create_block(current_block_);
+      }
+
       InlineCache* cache = reinterpret_cast&lt;InlineCache*&gt;(which);
       Value* ret = splat_send(cache-&gt;name, args, allow_private_);
       stack_remove(args + 3);
       check_for_exception(ret);
       stack_push(ret);
       allow_private_ = false;
+
+      // Clear the current block
+      current_block_ = -1;
     }
 
     void visit_cast_array() {
@@ -1584,56 +1760,145 @@ namespace rubinius {
     }
 
     void visit_cast_for_single_block_arg() {
-      std::vector&lt;const Type*&gt; types;
+      std::vector&lt;Value*&gt;* inline_args = incoming_args();
+      if(inline_args) {
+        switch(inline_args-&gt;size()) {
+        case 0:
+          stack_push(constant(Qnil));
+          break;
+        case 1:
+          stack_push(inline_args-&gt;at(0));
+          break;
+        default: {
+          std::vector&lt;const Type*&gt; types;
+          types.push_back(ls_-&gt;ptr_type(&quot;VM&quot;));
+          types.push_back(Type::Int32Ty);
+
+          FunctionType* ft = FunctionType::get(ls_-&gt;ptr_type(&quot;Object&quot;), types, true);
+          Function* func = cast&lt;Function&gt;(
+              ls_-&gt;module()-&gt;getOrInsertFunction(&quot;rbx_create_array&quot;, ft));
+
+          std::vector&lt;Value*&gt; outgoing_args;
+          outgoing_args.push_back(vm());
+          outgoing_args.push_back(ConstantInt::get(Type::Int32Ty, inline_args-&gt;size()));
+
+          for(size_t i = 0; i &lt; inline_args-&gt;size(); i++) {
+            outgoing_args.push_back(inline_args-&gt;at(i));
+          }
 
-      types.push_back(VMTy);
-      types.push_back(ptr_type(&quot;Arguments&quot;));
+          Value* ary =
+            b().CreateCall(func, outgoing_args.begin(), outgoing_args.end(), &quot;ary&quot;);
+          stack_push(ary);
+         }
+        }
+      } else {
+        std::vector&lt;const Type*&gt; types;
 
-      FunctionType* ft = FunctionType::get(ObjType, types, false);
-      Function* func = cast&lt;Function&gt;(
-          module_-&gt;getOrInsertFunction(&quot;rbx_cast_for_single_block_arg&quot;, ft));
+        types.push_back(VMTy);
+        types.push_back(ptr_type(&quot;Arguments&quot;));
 
-      Value* call_args[] = {
-        vm_,
-        args_
-      };
+        FunctionType* ft = FunctionType::get(ObjType, types, false);
+        Function* func = cast&lt;Function&gt;(
+            module_-&gt;getOrInsertFunction(&quot;rbx_cast_for_single_block_arg&quot;, ft));
 
-      stack_push(b().CreateCall(func, call_args, call_args+2, &quot;cfsba&quot;));
+        Value* call_args[] = {
+          vm_,
+          args_
+        };
+
+        stack_push(b().CreateCall(func, call_args, call_args+2, &quot;cfsba&quot;));
+      }
     }
 
     void visit_cast_for_multi_block_arg() {
-      Signature sig(ls_, ObjType);
-      sig &lt;&lt; VMTy;
-      sig &lt;&lt; ptr_type(&quot;Arguments&quot;);
+      std::vector&lt;Value*&gt;* inline_args = incoming_args();
+      if(inline_args) {
+        std::vector&lt;const Type*&gt; types;
+        types.push_back(ls_-&gt;ptr_type(&quot;VM&quot;));
+        types.push_back(Type::Int32Ty);
 
-      Value* call_args[] = {
-        vm_,
-        args_
-      };
+        FunctionType* ft = FunctionType::get(ls_-&gt;ptr_type(&quot;Object&quot;), types, true);
+        Function* func = cast&lt;Function&gt;(
+            ls_-&gt;module()-&gt;getOrInsertFunction(&quot;rbx_cast_for_multi_block_arg_varargs&quot;, ft));
 
-      Value* val = sig.call(&quot;rbx_cast_for_multi_block_arg&quot;, call_args, 2,
-                            &quot;cfmba&quot;, b());
-      stack_push(val);
+        std::vector&lt;Value*&gt; outgoing_args;
+        outgoing_args.push_back(vm());
+        outgoing_args.push_back(ConstantInt::get(Type::Int32Ty, inline_args-&gt;size()));
+
+        for(size_t i = 0; i &lt; inline_args-&gt;size(); i++) {
+          outgoing_args.push_back(inline_args-&gt;at(i));
+        }
+
+        Value* ary =
+          b().CreateCall(func, outgoing_args.begin(), outgoing_args.end(), &quot;ary&quot;);
+        stack_push(ary);
+      } else {
+        Signature sig(ls_, ObjType);
+        sig &lt;&lt; VMTy;
+        sig &lt;&lt; ptr_type(&quot;Arguments&quot;);
+
+        Value* call_args[] = {
+          vm_,
+          args_
+        };
+
+        Value* val = sig.call(&quot;rbx_cast_for_multi_block_arg&quot;, call_args, 2,
+            &quot;cfmba&quot;, b());
+        stack_push(val);
+      }
     }
 
     void visit_cast_for_splat_block_arg() {
-      Signature sig(ls_, ObjType);
-      sig &lt;&lt; VMTy;
-      sig &lt;&lt; ptr_type(&quot;Arguments&quot;);
+      std::vector&lt;Value*&gt;* inline_args = incoming_args();
+      if(inline_args) {
+        std::vector&lt;const Type*&gt; types;
+        types.push_back(ls_-&gt;ptr_type(&quot;VM&quot;));
+        types.push_back(Type::Int32Ty);
 
-      Value* call_args[] = {
-        vm_,
-        args_
-      };
+        FunctionType* ft = FunctionType::get(ls_-&gt;ptr_type(&quot;Object&quot;), types, true);
+        Function* func = cast&lt;Function&gt;(
+            ls_-&gt;module()-&gt;getOrInsertFunction(&quot;rbx_create_array&quot;, ft));
 
-      Value* val = sig.call(&quot;rbx_cast_for_splat_block_arg&quot;, call_args, 2,
-                            &quot;cfmba&quot;, b());
-      stack_push(val);
+        std::vector&lt;Value*&gt; outgoing_args;
+        outgoing_args.push_back(vm());
+        outgoing_args.push_back(ConstantInt::get(Type::Int32Ty, inline_args-&gt;size()));
+
+        for(size_t i = 0; i &lt; inline_args-&gt;size(); i++) {
+          outgoing_args.push_back(inline_args-&gt;at(i));
+        }
+
+        Value* ary =
+          b().CreateCall(func, outgoing_args.begin(), outgoing_args.end(), &quot;ary&quot;);
+        stack_push(ary);
+      } else {
+        Signature sig(ls_, ObjType);
+        sig &lt;&lt; VMTy;
+        sig &lt;&lt; ptr_type(&quot;Arguments&quot;);
+
+        Value* call_args[] = {
+          vm_,
+          args_
+        };
+
+        Value* val = sig.call(&quot;rbx_cast_for_splat_block_arg&quot;, call_args, 2,
+            &quot;cfmba&quot;, b());
+        stack_push(val);
+      }
     }
 
     void visit_set_local_depth(opcode depth, opcode index) {
       set_has_side_effects();
 
+      // We're inlinig a block...
+      if(inline_return_) {
+        JITMethodInfo* nfo = upscope_info(depth);
+        assert(nfo);
+
+        Value* local_pos = local_location(nfo-&gt;variables(), index);
+        stack_push(b().CreateLoad(local_pos, &quot;upscope_local&quot;));
+        return;
+      }
+
       if(depth == 0) {
         std::cout &lt;&lt; &quot;why is depth 0 here?\n&quot;;
         visit_set_local(index);
@@ -1676,9 +1941,32 @@ namespace rubinius {
       stack_push(b().CreateCall(func, call_args, call_args+5, &quot;sld&quot;));
     }
 
+    JITMethodInfo* upscope_info(int which) {
+      JITMethodInfo* nfo = &amp;info();
+
+      for(int i = 0; i &lt; which; i++) {
+        // we always go 2 levels up, through the method that does the yield.
+        nfo = nfo-&gt;parent_info();
+        if(!nfo) return 0;
+        nfo = nfo-&gt;parent_info();
+      }
+
+      return nfo;
+    }
+
     void visit_push_local_depth(opcode depth, opcode index) {
       set_has_side_effects();
 
+      // We're in an inlined block..
+      if(inline_return_) {
+        JITMethodInfo* nfo = upscope_info(depth);
+        assert(nfo);
+
+        Value* local_pos = local_location(nfo-&gt;variables(), index);
+        stack_push(b().CreateLoad(local_pos, &quot;upscope_local&quot;));
+        return;
+      }
+
       if(depth == 0) {
         std::cout &lt;&lt; &quot;why is depth 0 here?\n&quot;;
         visit_push_local(index);
@@ -1760,6 +2048,28 @@ namespace rubinius {
     void visit_yield_stack(opcode count) {
       set_has_side_effects();
 
+      // Hey! Look at that! We know the block we'd be yielding to
+      // staticly! woo! ok, lets just emit the code for it here!
+      if(VMMethod* pb = passed_block()) {
+        JITMethodInfo* parent = info().parent_info();
+        assert(parent);
+
+        // Count the block against the policy size total
+        inline_policy()-&gt;increase_size(pb);
+
+        // We inline unconditionally here, since we make the decision
+        // wrt the block when we are considering inlining the send that
+        // has the block on it.
+        Inliner inl(*this, count);
+        inl.inline_block(pb, get_self(parent-&gt;variables()));
+        stack_remove(count);
+        if(inl.check_for_exception()) {
+          check_for_exception(inl.result());
+        }
+        stack_push(inl.result());
+        return;
+      }
+
       Signature sig(ls_, ObjType);
 
       sig &lt;&lt; VMTy;
@@ -1956,6 +2266,22 @@ namespace rubinius {
     }
 
     void visit_raise_return() {
+      // Inlining a block!
+      if(inline_return_) {
+        // We have to flush scopes before we return.
+        JITMethodInfo* nfo = &amp;info();
+        while(nfo) {
+          if(nfo-&gt;use_full_scope()) {
+            flush_scope_to_heap(nfo-&gt;variables());
+          }
+
+          nfo = nfo-&gt;parent_info();
+        }
+
+        b().CreateRet(stack_pop());
+        return;
+      }
+
       Signature sig(ls_, ObjType);
 
       sig &lt;&lt; VMTy;
@@ -1990,6 +2316,22 @@ namespace rubinius {
     }
 
     void visit_raise_break() {
+      // inlining a block!
+      if(inline_return_) {
+        JITMethodInfo* upinfo = upscope_info(1);
+        assert(upinfo);
+
+        BasicBlock* blk = upinfo-&gt;block_break_loc();
+        assert(blk);
+
+        PHINode* phi = upinfo-&gt;block_break_result();
+        phi-&gt;addIncoming(stack_pop(), b().GetInsertBlock());
+
+        b().CreateBr(blk);
+        set_block(new_block(&quot;continue&quot;));
+        return;
+      }
+
       Signature sig(ls_, ObjType);
 
       sig &lt;&lt; VMTy;</diff>
      <filename>vm/llvm/jit_visit.hpp</filename>
    </modified>
    <modified>
      <diff>@@ -10,12 +10,13 @@
 #include &lt;llvm/Analysis/CaptureTracking.h&gt;
 
 namespace rubinius {
-  LLVMWorkHorse::LLVMWorkHorse(LLVMState* ls, VMMethod* vmm)
+  LLVMWorkHorse::LLVMWorkHorse(LLVMState* ls, JITMethodInfo&amp; i)
     : ls_(ls)
-    , vmm_(vmm)
+    , vmm_(i.vmm)
     , use_full_scope_(false)
     , import_args_(0)
     , method_body_(0)
+    , info_(i)
   {
     llvm::Module* mod = ls-&gt;module();
     cf_type = mod-&gt;getTypeByName(&quot;struct.rubinius::CallFrame&quot;);
@@ -325,7 +326,7 @@ namespace rubinius {
     nil_locals();
   }
 
-  void LLVMWorkHorse::setup_inline_scope(Value* self, Value* mod) {
+  void LLVMWorkHorse::setup_inline_scope(Value* self, Value* blk, Value* mod) {
     Value* heap_null = ConstantExpr::getNullValue(PointerType::getUnqual(vars_type));
     Value* heap_pos = get_field(vars, offset::vars_on_heap);
     b().CreateStore(heap_null, heap_pos);
@@ -333,7 +334,6 @@ namespace rubinius {
     b().CreateStore(self, get_field(vars, offset::vars_self));
     b().CreateStore(mod, get_field(vars, offset::vars_module));
 
-    Value* blk = constant(Qnil, obj_type);
     b().CreateStore(blk, get_field(vars, offset::vars_block));
 
     b().CreateStore(Constant::getNullValue(ls_-&gt;ptr_type(&quot;VariableScope&quot;)),
@@ -576,6 +576,12 @@ namespace rubinius {
     BasicBlock* block = BasicBlock::Create(&quot;entry&quot;, func);
     b().SetInsertPoint(block);
 
+    info_.set_function(func);
+    info_.set_vm(vm);
+    info_.set_args(args);
+    info_.set_previous(prev);
+    info_.set_entry(block);
+
     BasicBlock* body = BasicBlock::Create(&quot;block_body&quot;, func);
 
     pass_one(body);
@@ -591,8 +597,12 @@ namespace rubinius {
         cfstk,
         PointerType::getUnqual(cf_type), &quot;call_frame&quot;);
 
+    info_.set_call_frame(call_frame);
+
     stk = b().CreateConstGEP1_32(cfstk, sizeof(CallFrame) / sizeof(Object*), &quot;stack&quot;);
 
+    info_.set_stack(stk);
+
     Value* var_mem = b().CreateAlloca(obj_type,
         ConstantInt::get(Type::Int32Ty,
           (sizeof(StackVariables) / sizeof(Object*)) + vmm_-&gt;number_of_locals),
@@ -602,6 +612,8 @@ namespace rubinius {
         var_mem,
         PointerType::getUnqual(stack_vars_type), &quot;vars&quot;);
 
+    info_.set_variables(vars);
+
     initialize_block_frame(vmm_-&gt;stack_size);
 
     nil_stack(vmm_-&gt;stack_size, constant(Qnil, obj_type));
@@ -697,6 +709,12 @@ namespace rubinius {
     BasicBlock* block = BasicBlock::Create(&quot;entry&quot;, func);
     builder_.SetInsertPoint(block);
 
+    info_.set_function(func);
+    info_.set_vm(vm);
+    info_.set_args(args);
+    info_.set_previous(prev);
+    info_.set_entry(block);
+
     BasicBlock* body = BasicBlock::Create(&quot;method_body&quot;, func);
     method_body_ = body;
 
@@ -722,12 +740,18 @@ namespace rubinius {
         cfstk,
         PointerType::getUnqual(cf_type), &quot;call_frame&quot;);
 
+    info_.set_call_frame(call_frame);
+
     stk = b().CreateConstGEP1_32(cfstk, sizeof(CallFrame) / sizeof(Object*), &quot;stack&quot;);
 
+    info_.set_stack(stk);
+
     vars = b().CreateBitCast(
         var_mem,
         PointerType::getUnqual(stack_vars_type), &quot;vars&quot;);
 
+    info_.set_variables(vars);
+
     initialize_call_frame(vmm_-&gt;stack_size);
 
     nil_stack(vmm_-&gt;stack_size, constant(Qnil, obj_type));
@@ -740,22 +764,25 @@ namespace rubinius {
     b().SetInsertPoint(body);
   }
 
-  BasicBlock* LLVMWorkHorse::setup_inline(Function* current,
-      Value* vm_i, Value* previous,
-      Value* self, Value* mod, std::vector&lt;Value*&gt;&amp; stack_args)
+  BasicBlock* LLVMWorkHorse::setup_inline(Value* self, Value* blk,
+      Value* mod, std::vector&lt;Value*&gt;&amp; stack_args)
   {
-    func = current;
-    vm = vm_i;
-    prev = previous;
+    func = info_.function();
+    vm = info_.vm();
+    prev = info_.parent_call_frame();
     args = ConstantExpr::getNullValue(ls_-&gt;ptr_type(&quot;Arguments&quot;));
 
     BasicBlock* entry = BasicBlock::Create(&quot;inline_entry&quot;, func);
     b().SetInsertPoint(entry);
 
+    info_.set_args(args);
+    info_.set_previous(prev);
+    info_.set_entry(entry);
+
     BasicBlock* body = BasicBlock::Create(&quot;method_body&quot;, func);
     pass_one(body);
 
-    BasicBlock* alloca_block = &amp;current-&gt;getEntryBlock();
+    BasicBlock* alloca_block = &amp;func-&gt;getEntryBlock();
 
     Value* cfstk = new AllocaInst(obj_type,
         ConstantInt::get(Type::Int32Ty,
@@ -768,6 +795,9 @@ namespace rubinius {
 
     stk = b().CreateConstGEP1_32(cfstk, sizeof(CallFrame) / sizeof(Object*), &quot;stack&quot;);
 
+    info_.set_call_frame(call_frame);
+    info_.set_stack(stk);
+
     Value* var_mem = new AllocaInst(obj_type,
         ConstantInt::get(Type::Int32Ty,
           (sizeof(StackVariables) / sizeof(Object*)) + vmm_-&gt;number_of_locals),
@@ -777,6 +807,8 @@ namespace rubinius {
         var_mem,
         PointerType::getUnqual(stack_vars_type), &quot;vars&quot;);
 
+    info_.set_variables(vars);
+
     //  Setup the CallFrame
     //
     // previous
@@ -810,7 +842,7 @@ namespace rubinius {
 
     nil_stack(vmm_-&gt;stack_size, constant(Qnil, obj_type));
 
-    setup_inline_scope(self, mod);
+    setup_inline_scope(self, blk, mod);
 
     // We know the right arguments are present, so we just need to put them
     // in the right place.
@@ -840,6 +872,94 @@ namespace rubinius {
     return entry;
   }
 
+  BasicBlock* LLVMWorkHorse::setup_inline_block(Value* self, Value* mod) {
+    func = info_.function();
+    vm = info_.vm();
+    prev = info_.parent_call_frame();
+    args = ConstantExpr::getNullValue(ls_-&gt;ptr_type(&quot;Arguments&quot;));
+
+    BasicBlock* entry = BasicBlock::Create(&quot;inline_entry&quot;, func);
+    b().SetInsertPoint(entry);
+
+    info_.set_args(args);
+    info_.set_previous(prev);
+    info_.set_entry(entry);
+
+    BasicBlock* body = BasicBlock::Create(&quot;block_body&quot;, func);
+    pass_one(body);
+
+    BasicBlock* alloca_block = &amp;func-&gt;getEntryBlock();
+
+    Value* cfstk = new AllocaInst(obj_type,
+        ConstantInt::get(Type::Int32Ty,
+          (sizeof(CallFrame) / sizeof(Object*)) + vmm_-&gt;stack_size),
+        &quot;cfstk&quot;, alloca_block-&gt;getTerminator());
+
+    call_frame = b().CreateBitCast(
+        cfstk,
+        PointerType::getUnqual(cf_type), &quot;call_frame&quot;);
+
+    info_.set_call_frame(call_frame);
+
+    stk = b().CreateConstGEP1_32(cfstk, sizeof(CallFrame) / sizeof(Object*), &quot;stack&quot;);
+
+    info_.set_stack(stk);
+
+    Value* var_mem = new AllocaInst(obj_type,
+        ConstantInt::get(Type::Int32Ty,
+          (sizeof(StackVariables) / sizeof(Object*)) + vmm_-&gt;number_of_locals),
+        &quot;var_mem&quot;, alloca_block-&gt;getTerminator());
+
+    vars = b().CreateBitCast(
+        var_mem,
+        PointerType::getUnqual(stack_vars_type), &quot;vars&quot;);
+
+    info_.set_variables(vars);
+
+    //  Setup the CallFrame
+    //
+    // previous
+    b().CreateStore(prev, get_field(call_frame, offset::cf_previous));
+
+    // msg
+    b().CreateStore(ConstantExpr::getNullValue(ls_-&gt;ptr_type(&quot;Dispatch&quot;)),
+        get_field(call_frame, offset::cf_msg));
+
+    // cm
+    Value* obj_addr = constant(vmm_-&gt;original.object_address(),
+        PointerType::getUnqual(ls_-&gt;ptr_type(&quot;CompiledMethod&quot;)));
+
+    method = b().CreateLoad(obj_addr, &quot;cm&quot;);
+    Value* cm_gep = get_field(call_frame, offset::cf_cm);
+    b().CreateStore(method, cm_gep);
+
+    // flags
+    int flags = CallFrame::cInlineFrame;
+    if(!use_full_scope_) flags |= CallFrame::cClosedScope;
+
+    b().CreateStore(ConstantInt::get(Type::Int32Ty, flags),
+        get_field(call_frame, offset::cf_flags));
+
+    // ip
+    b().CreateStore(ConstantInt::get(Type::Int32Ty, 0),
+        get_field(call_frame, offset::cf_ip));
+
+    // scope
+    b().CreateStore(vars, get_field(call_frame, offset::cf_scope));
+
+    nil_stack(vmm_-&gt;stack_size, constant(Qnil, obj_type));
+
+    setup_inline_scope(self, constant(Qnil, obj_type), mod);
+
+    // No argument handling, there are bytecodes in the body that
+    // do that. We just have to make stack_args available.
+
+    b().CreateBr(body);
+    b().SetInsertPoint(body);
+
+    return entry;
+  }
+
   class PassOne : public VisitInstructions&lt;PassOne&gt; {
     BlockMap&amp; map_;
     Function* function_;
@@ -1088,6 +1208,7 @@ namespace rubinius {
     finder.drive(vmm_);
 
     if(finder.creates_blocks() || finder.calls_evalish()) {
+      info_.set_use_full_scope();
       use_full_scope_ = true;
     }
 
@@ -1095,20 +1216,16 @@ namespace rubinius {
     loops_ = finder.loops_p();
   }
 
-  bool LLVMWorkHorse::generate_body(JITMethodInfo&amp; info) {
-    JITVisit visitor(ls_, info, block_map_,
-        ls_-&gt;module(), func,
-        b().GetInsertBlock(), stk, call_frame,
-        method_entry_, args,
-        vars, info.is_block, info.inline_return);
+  bool LLVMWorkHorse::generate_body() {
+    JITVisit visitor(ls_, info_, block_map_, b().GetInsertBlock());
 
-    if(info.inline_policy) {
-      visitor.set_policy(info.inline_policy);
+    if(info_.inline_policy) {
+      visitor.set_policy(info_.inline_policy);
     } else {
       visitor.init_policy();
     }
 
-    visitor.set_called_args(info.called_args);
+    visitor.set_called_args(info_.called_args);
 
     visitor.set_valid_flag(valid_flag);
 
@@ -1154,7 +1271,7 @@ namespace rubinius {
         std::cout &lt;&lt; info.vmm
           &lt;&lt; &quot; Driving: &quot; &lt;&lt; jbb.start_ip &lt;&lt; &quot;-&quot; &lt;&lt; jbb.end_ip &lt;&lt; &quot;\n&quot;;
         */
-        visitor.drive(info.vmm-&gt;opcodes, jbb.end_ip+1, jbb.start_ip);
+        visitor.drive(info_.vmm-&gt;opcodes, jbb.end_ip+1, jbb.start_ip);
       }
     } catch(JITVisit::Unsupported &amp;e) {
       return false;
@@ -1200,8 +1317,8 @@ namespace rubinius {
     }
     */
 
-    info.return_value = visitor.return_value();
-    info.fin_block = visitor.current_block();
+    info_.return_value = visitor.return_value();
+    info_.fin_block = visitor.current_block();
     return true;
   }
 }</diff>
      <filename>vm/llvm/jit_workhorse.cpp</filename>
    </modified>
    <modified>
      <diff>@@ -56,11 +56,13 @@ namespace rubinius {
     BasicBlock* import_args_;
     BasicBlock* method_body_;
 
+    JITMethodInfo&amp; info_;
+
   public:
 
     llvm::IRBuilder&lt;&gt;&amp; b() { return builder_; }
 
-    LLVMWorkHorse(LLVMState* ls, VMMethod* vmm);
+    LLVMWorkHorse(LLVMState* ls, JITMethodInfo&amp; info);
 
     void pass_one(BasicBlock* body);
 
@@ -78,7 +80,7 @@ namespace rubinius {
 
     void setup_scope();
 
-    void setup_inline_scope(Value* self, Value* mod);
+    void setup_inline_scope(Value* self, Value* blk, Value* mod);
 
     void setup_block_scope();
 
@@ -90,10 +92,11 @@ namespace rubinius {
 
     void setup();
 
-    BasicBlock* setup_inline(Function* current, Value* vm_i, Value* previous,
-        Value* self, Value* mod, std::vector&lt;Value*&gt;&amp; args);
+    BasicBlock* setup_inline(Value* self, Value* blk, Value* mod, std::vector&lt;Value*&gt;&amp; args);
+
+    BasicBlock* setup_inline_block(Value* self, Value* mod);
 
-    bool generate_body(JITMethodInfo&amp; info);
+    bool generate_body();
 
     Value* get_field(Value* val, int which);
 </diff>
      <filename>vm/llvm/jit_workhorse.hpp</filename>
    </modified>
    <modified>
      <diff>@@ -85,6 +85,7 @@ namespace rubinius {
    */
   VMMethod::VMMethod(STATE, CompiledMethod* meth)
     : machine_method_(state)
+    , parent_(NULL)
     , run(standard_interpreter)
     , original(state, meth)
     , type(NULL)
@@ -502,16 +503,14 @@ namespace rubinius {
           LLVMState* ls = LLVMState::get(state);
           VMMethod* candidate = ls-&gt;find_candidate(vmm, previous);
 
-          candidate-&gt;call_count = -1; // So we don't try and jit twice at the same time
-          state-&gt;stats.jitted_methods++;
+          assert(!candidate-&gt;parent());
 
-          ls-&gt;compile_soon(state, candidate);
-
-          if(state-&gt;shared.config.jit_show_compiling) {
-            std::cout &lt;&lt; &quot;[[[ JIT Queued method &quot;
-              &lt;&lt; ls-&gt;queued_methods() &lt;&lt; &quot;/&quot;
-              &lt;&lt; ls-&gt;jitted_methods() &lt;&lt; &quot; ]]]\n&quot;;
+          if(candidate-&gt;call_count &lt; 0) {
+            // Ignore it. compile this one.
+            candidate = vmm;
           }
+
+          ls-&gt;compile_soon(state, candidate);
         } else {
           vmm-&gt;call_count++;
         }</diff>
      <filename>vm/vmmethod.cpp</filename>
    </modified>
    <modified>
      <diff>@@ -47,6 +47,7 @@ namespace rubinius {
   private:
     TypedRoot&lt;MachineMethod*&gt; machine_method_;
     IndirectLiterals indirect_literals_;
+    VMMethod* parent_;
 
   public:
     static void** instructions;
@@ -136,6 +137,18 @@ namespace rubinius {
       return indirect_literals_;
     }
 
+    VMMethod* parent() {
+      return parent_;
+    }
+
+    void set_parent(VMMethod* parent) {
+      parent_ = parent;
+    }
+
+    bool for_block() {
+      return parent_ != 0;
+    }
+
     void set_machine_method(MachineMethod* mm);
 
     void specialize(STATE, TypeInfo* ti);</diff>
      <filename>vm/vmmethod.hpp</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>34103ab1d899fc0554d1bdce8a13b9d052163751</id>
    </parent>
  </parents>
  <author>
    <name>Evan Phoenix</name>
    <email>ephoenix@engineyard.com</email>
  </author>
  <url>http://github.com/evanphx/rubinius/commit/40bfc03201b797c8b8a5926a9a3c6336c0985416</url>
  <id>40bfc03201b797c8b8a5926a9a3c6336c0985416</id>
  <committed-date>2009-08-28T11:30:08-07:00</committed-date>
  <authored-date>2009-08-28T11:29:16-07:00</authored-date>
  <message>Add ability to inline blocks into their creation scope

Use -Xjit.inline.blocks to enable this for now</message>
  <tree>1c4781384beef63a7c2a2f8934b814c0262efe3b</tree>
  <committer>
    <name>Evan Phoenix</name>
    <email>ephoenix@engineyard.com</email>
  </committer>
</commit>
