<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[1288] MacRuby/branches/experimental</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.macosforge.org/projects/ruby/changeset/1288">1288</a></dd>
<dt>Author</dt> <dd>lsansonetti@apple.com</dd>
<dt>Date</dt> <dd>2009-04-02 19:11:56 -0700 (Thu, 02 Apr 2009)</dd>
</dl>

<h3>Log Message</h3>
<pre>a faster implementation of dvars + fixed eval bugs + preliminary implementation of binding</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#MacRubybranchesexperimentalTODO">MacRuby/branches/experimental/TODO</a></li>
<li><a href="#MacRubybranchesexperimentalbenchrb">MacRuby/branches/experimental/bench.rb</a></li>
<li><a href="#MacRubybranchesexperimentalevalc">MacRuby/branches/experimental/eval.c</a></li>
<li><a href="#MacRubybranchesexperimentalidc">MacRuby/branches/experimental/id.c</a></li>
<li><a href="#MacRubybranchesexperimentalidh">MacRuby/branches/experimental/id.h</a></li>
<li><a href="#MacRubybranchesexperimentalloadc">MacRuby/branches/experimental/load.c</a></li>
<li><a href="#MacRubybranchesexperimentalmainc">MacRuby/branches/experimental/main.c</a></li>
<li><a href="#MacRubybranchesexperimentalnumericc">MacRuby/branches/experimental/numeric.c</a></li>
<li><a href="#MacRubybranchesexperimentalprocc">MacRuby/branches/experimental/proc.c</a></li>
<li><a href="#MacRubybranchesexperimentalroxorcpp">MacRuby/branches/experimental/roxor.cpp</a></li>
<li><a href="#MacRubybranchesexperimentalroxorh">MacRuby/branches/experimental/roxor.h</a></li>
<li><a href="#MacRubybranchesexperimentaltoolcompile_preluderb">MacRuby/branches/experimental/tool/compile_prelude.rb</a></li>
<li><a href="#MacRubybranchesexperimentalvm_evalc">MacRuby/branches/experimental/vm_eval.c</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="MacRubybranchesexperimentalTODO"></a>
<div class="modfile"><h4>Modified: MacRuby/branches/experimental/TODO (1287 => 1288)</h4>
<pre class="diff"><span>
<span class="info">--- MacRuby/branches/experimental/TODO        2009-04-01 12:49:41 UTC (rev 1287)
+++ MacRuby/branches/experimental/TODO        2009-04-03 02:11:56 UTC (rev 1288)
</span><span class="lines">@@ -16,6 +16,7 @@
</span><span class="cx"> [X] fast #send
</span><span class="cx"> [ ] fast regexp =~
</span><span class="cx"> [X] fast break
</span><ins>+[ ] write a pass manager to eliminate unnecessary arrays generated by massigns
</ins><span class="cx"> [ ] Array and Hash subclasses to hold immediate Ruby objects without boxing
</span><span class="cx"> [/] implement backtracing/symbolication
</span><span class="cx"> [/] port all rb_define_method() calls to rb_objc_define_method()
</span></span></pre></div>
<a id="MacRubybranchesexperimentalbenchrb"></a>
<div class="modfile"><h4>Modified: MacRuby/branches/experimental/bench.rb (1287 => 1288)</h4>
<pre class="diff"><span>
<span class="info">--- MacRuby/branches/experimental/bench.rb        2009-04-01 12:49:41 UTC (rev 1287)
+++ MacRuby/branches/experimental/bench.rb        2009-04-03 02:11:56 UTC (rev 1288)
</span><span class="lines">@@ -147,7 +147,25 @@
</span><span class="cx">     o = proc {}
</span><span class="cx">     i=0; while i&lt;30000000; o.call; i+=1; end
</span><span class="cx">   end
</span><ins>+  bm.report('30000000 dvar write') do
+    i=0
+    30000000.times { i=1 }
+  end
</ins><span class="cx"> 
</span><ins>+  # Eval
+  bm.report('1000 eval') do
+    i=0
+    s = &quot;#{1+1}+#{20+20}&quot;
+    while i&lt;1000
+      eval(s)
+      i+=1
+    end
+  end
+  bm.report('30000000 binding-var write') do
+    i=0
+    eval('while i&lt;30000000; i+=1; end')
+  end
+
</ins><span class="cx">   # Break
</span><span class="cx">   bm.report('30000000 while break') do
</span><span class="cx">     i=0; while i&lt;30000000; while true; i+=1; break; end; end
</span><span class="lines">@@ -198,16 +216,6 @@
</span><span class="cx">     end
</span><span class="cx">   end
</span><span class="cx"> 
</span><del>-  # Eval
-  bm.report('1000 eval') do
-    i=0
-    s = &quot;#{1+1}+#{20+20}&quot;
-    while i&lt;1000
-      eval(s)
-      i+=1
-    end
-  end
-
</del><span class="cx">   # Method
</span><span class="cx">   bm.report('3000000 Method#call w/ 0 arg') do
</span><span class="cx">     o = Class1.new
</span></span></pre></div>
<a id="MacRubybranchesexperimentalevalc"></a>
<div class="modfile"><h4>Modified: MacRuby/branches/experimental/eval.c (1287 => 1288)</h4>
<pre class="diff"><span>
<span class="info">--- MacRuby/branches/experimental/eval.c        2009-04-01 12:49:41 UTC (rev 1287)
+++ MacRuby/branches/experimental/eval.c        2009-04-03 02:11:56 UTC (rev 1288)
</span><span class="lines">@@ -97,6 +97,7 @@
</span><span class="cx"> static void
</span><span class="cx"> ruby_finalize_1(void)
</span><span class="cx"> {
</span><ins>+    rb_vm_finalize();
</ins><span class="cx">     ruby_sig_finalize();
</span><span class="cx">     //GET_THREAD()-&gt;errinfo = Qnil;
</span><span class="cx">     rb_gc_call_finalizer_at_exit();
</span><span class="lines">@@ -195,7 +196,7 @@
</span><span class="cx">         return FIX2INT(n);
</span><span class="cx">     }
</span><span class="cx">     rb_vm_set_running(true);
</span><del>-    rb_vm_run(RSTRING_PTR(rb_progname), (NODE *)n);
</del><ins>+    rb_vm_run(RSTRING_PTR(rb_progname), (NODE *)n, NULL);
</ins><span class="cx">     return ruby_cleanup(0);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -736,8 +737,17 @@
</span><span class="cx"> static VALUE
</span><span class="cx"> rb_f_local_variables(VALUE rcv, SEL sel)
</span><span class="cx"> {
</span><del>-    // TODO
-    return Qnil;
</del><ins>+    rb_vm_binding_t *binding = rb_vm_current_binding();
+    assert(binding != NULL);
+
+    VALUE ary = rb_ary_new();
+    rb_vm_local_t *l;
+   
+    for (l = binding-&gt;locals; l != NULL; l = l-&gt;next) {
+        rb_ary_push(ary, ID2SYM(l-&gt;name));
+    }
+
+    return ary;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -820,27 +830,3 @@
</span><span class="cx">     //rb_ivar_set(exception_error, idThrowState, INT2FIX(TAG_FATAL));
</span><span class="cx">     rb_objc_retain((void *)exception_error);
</span><span class="cx"> }
</span><del>-
-
-/* for parser */
-
-int
-rb_dvar_defined(ID id)
-{
-    // TODO
-    return 0;
-}
-
-int
-rb_local_defined(ID id)
-{
-    // TODO
-    return 0;
-}
-
-int
-rb_parse_in_eval(void)
-{
-    // TODO
-    return 0;
-}
</del></span></pre></div>
<a id="MacRubybranchesexperimentalidc"></a>
<div class="modfile"><h4>Modified: MacRuby/branches/experimental/id.c (1287 => 1288)</h4>
<pre class="diff"><span>
<span class="info">--- MacRuby/branches/experimental/id.c        2009-04-01 12:49:41 UTC (rev 1287)
+++ MacRuby/branches/experimental/id.c        2009-04-03 02:11:56 UTC (rev 1288)
</span><span class="lines">@@ -74,6 +74,11 @@
</span><span class="cx">     sel__send__ = sel_registerName(&quot;__send__:&quot;);
</span><span class="cx">     selEqTilde = sel_registerName(&quot;=~:&quot;);
</span><span class="cx">     selEval = sel_registerName(&quot;eval:&quot;);
</span><ins>+    selInstanceEval = sel_registerName(&quot;instance_eval:&quot;);
+    selClassEval = sel_registerName(&quot;class_eval:&quot;);
+    selModuleEval = sel_registerName(&quot;module_eval:&quot;);
+    selLocalVariables = sel_registerName(&quot;local_variables&quot;);
+    selBinding = sel_registerName(&quot;binding&quot;);
</ins><span class="cx">     selEach = sel_registerName(&quot;each&quot;);
</span><span class="cx">     selEqq = sel_registerName(&quot;===:&quot;);
</span><span class="cx">     selBackquote = sel_registerName(&quot;`:&quot;);
</span></span></pre></div>
<a id="MacRubybranchesexperimentalidh"></a>
<div class="modfile"><h4>Modified: MacRuby/branches/experimental/id.h (1287 => 1288)</h4>
<pre class="diff"><span>
<span class="info">--- MacRuby/branches/experimental/id.h        2009-04-01 12:49:41 UTC (rev 1287)
+++ MacRuby/branches/experimental/id.h        2009-04-03 02:11:56 UTC (rev 1288)
</span><span class="lines">@@ -85,6 +85,11 @@
</span><span class="cx"> extern SEL sel__send__;
</span><span class="cx"> extern SEL selEqTilde;
</span><span class="cx"> extern SEL selEval;
</span><ins>+extern SEL selInstanceEval;
+extern SEL selClassEval;
+extern SEL selModuleEval;
+extern SEL selLocalVariables;
+extern SEL selBinding;
</ins><span class="cx"> extern SEL selEach;
</span><span class="cx"> extern SEL selEqq;
</span><span class="cx"> extern SEL selBackquote;
</span></span></pre></div>
<a id="MacRubybranchesexperimentalloadc"></a>
<div class="modfile"><h4>Modified: MacRuby/branches/experimental/load.c (1287 => 1288)</h4>
<pre class="diff"><span>
<span class="info">--- MacRuby/branches/experimental/load.c        2009-04-01 12:49:41 UTC (rev 1287)
+++ MacRuby/branches/experimental/load.c        2009-04-03 02:11:56 UTC (rev 1288)
</span><span class="lines">@@ -270,7 +270,7 @@
</span><span class="cx">     if (node == NULL) {
</span><span class="cx">         rb_raise(rb_eSyntaxError, &quot;compile error&quot;);
</span><span class="cx">     }
</span><del>-    rb_vm_run(fname_str, node);
</del><ins>+    rb_vm_run(fname_str, node, NULL);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void
</span></span></pre></div>
<a id="MacRubybranchesexperimentalmainc"></a>
<div class="modfile"><h4>Modified: MacRuby/branches/experimental/main.c (1287 => 1288)</h4>
<pre class="diff"><span>
<span class="info">--- MacRuby/branches/experimental/main.c        2009-04-01 12:49:41 UTC (rev 1287)
+++ MacRuby/branches/experimental/main.c        2009-04-03 02:11:56 UTC (rev 1288)
</span><span class="lines">@@ -30,6 +30,6 @@
</span><span class="cx">     ruby_sysinit(&amp;argc, &amp;argv);
</span><span class="cx">     {
</span><span class="cx">         ruby_init();
</span><del>-        return ruby_run_node(ruby_options(argc, argv));
</del><ins>+        rb_exit(ruby_run_node(ruby_options(argc, argv)));
</ins><span class="cx">     }
</span><span class="cx"> }
</span></span></pre></div>
<a id="MacRubybranchesexperimentalnumericc"></a>
<div class="modfile"><h4>Modified: MacRuby/branches/experimental/numeric.c (1287 => 1288)</h4>
<pre class="diff"><span>
<span class="info">--- MacRuby/branches/experimental/numeric.c        2009-04-01 12:49:41 UTC (rev 1287)
+++ MacRuby/branches/experimental/numeric.c        2009-04-03 02:11:56 UTC (rev 1288)
</span><span class="lines">@@ -532,30 +532,11 @@
</span><span class="cx"> VALUE
</span><span class="cx"> rb_float_new(double d)
</span><span class="cx"> {
</span><del>-#if 0
-    //printf(&quot;double %f\n&quot;, d);
-    struct rb_float_cache *cache = rb_vm_float_cache(d);
-
-    if (cache-&gt;obj != Qnil) {
-        //printf(&quot;cached\n&quot;);
-        return cache-&gt;obj;
-    }
-
-    cache-&gt;count++;
-#endif
-
</del><span class="cx">     NEWOBJ(flt, struct RFloat);
</span><span class="cx">     OBJSETUP(flt, rb_cFloat, T_FLOAT);
</span><span class="cx"> 
</span><span class="cx">     flt-&gt;float_value = d;
</span><span class="cx"> 
</span><del>-#if 0
-    rb_objc_retain((void *)flt);
-    //if (cache-&gt;count == 10) {
-        cache-&gt;obj = (VALUE)flt;
-    //}
-#endif
-
</del><span class="cx">     return (VALUE)flt;
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="MacRubybranchesexperimentalprocc"></a>
<div class="modfile"><h4>Modified: MacRuby/branches/experimental/proc.c (1287 => 1288)</h4>
<pre class="diff"><span>
<span class="info">--- MacRuby/branches/experimental/proc.c        2009-04-01 12:49:41 UTC (rev 1287)
+++ MacRuby/branches/experimental/proc.c        2009-04-03 02:11:56 UTC (rev 1288)
</span><span class="lines">@@ -17,10 +17,6 @@
</span><span class="cx"> 
</span><span class="cx"> #define GetProcPtr(obj, ptr) GetCoreDataFromValue(obj, rb_vm_block_t, ptr)
</span><span class="cx"> 
</span><del>-typedef struct {
-    // TODO
-} rb_binding_t;
-
</del><span class="cx"> VALUE rb_cUnboundMethod;
</span><span class="cx"> VALUE rb_cMethod;
</span><span class="cx"> VALUE rb_cBinding;
</span><span class="lines">@@ -202,8 +198,8 @@
</span><span class="cx"> binding_alloc(VALUE klass)
</span><span class="cx"> {
</span><span class="cx">     VALUE obj;
</span><del>-    rb_binding_t *bind;
-    obj = Data_Make_Struct(klass, rb_binding_t,
</del><ins>+    rb_vm_binding_t *bind;
+    obj = Data_Make_Struct(klass, rb_vm_binding_t,
</ins><span class="cx">                            NULL, NULL, bind);
</span><span class="cx">     return obj;
</span><span class="cx"> }
</span><span class="lines">@@ -232,17 +228,9 @@
</span><span class="cx"> VALUE
</span><span class="cx"> rb_binding_new(void)
</span><span class="cx"> {
</span><del>-#if 0 // TODO
-    rb_thread_t *th = GET_THREAD();
-    rb_control_frame_t *cfp = vm_get_ruby_level_cfp(th, th-&gt;cfp);
-    VALUE bindval = binding_alloc(rb_cBinding);
-    rb_binding_t *bind;
-
-    GetBindingPtr(bindval, bind);
-    GC_WB(&amp;bind-&gt;env, vm_make_env_object(th, cfp));
-    return bindval;
-#endif
-    return Qnil;
</del><ins>+    rb_vm_binding_t *bind = rb_vm_current_binding();
+    assert(bind != NULL);
+    return Data_Wrap_Struct(rb_cBinding, NULL, NULL, bind);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> /*
</span><span class="lines">@@ -1497,22 +1485,16 @@
</span><span class="cx"> static VALUE
</span><span class="cx"> proc_binding(VALUE self, SEL sel)
</span><span class="cx"> {
</span><del>-#if 0 // TODO
-    rb_proc_t *proc;
-    VALUE bindval = binding_alloc(rb_cBinding);
-    rb_binding_t *bind;
</del><ins>+    rb_vm_block_t *block;
+    GetProcPtr(self, block);
</ins><span class="cx"> 
</span><del>-    GetProcPtr(self, proc);
-    GetBindingPtr(bindval, bind);
</del><ins>+    rb_vm_binding_t *binding = (rb_vm_binding_t *)xmalloc(
+            sizeof(rb_vm_binding_t));
</ins><span class="cx"> 
</span><del>-    if (TYPE(proc-&gt;block.iseq) == T_NODE) {
-        rb_raise(rb_eArgError, &quot;Can't create Binding from C level Proc&quot;);
-    }
</del><ins>+    GC_WB(&amp;binding-&gt;self, self);
+    GC_WB(&amp;binding-&gt;locals, block-&gt;locals);
</ins><span class="cx"> 
</span><del>-    bind-&gt;env = proc-&gt;envval;
-    return bindval;
-#endif
-    return Qnil;
</del><ins>+    return Data_Wrap_Struct(rb_cBinding, NULL, NULL, binding);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> static VALUE curry(VALUE dummy, VALUE args, int argc, VALUE *argv);
</span></span></pre></div>
<a id="MacRubybranchesexperimentalroxorcpp"></a>
<div class="modfile"><h4>Modified: MacRuby/branches/experimental/roxor.cpp (1287 => 1288)</h4>
<pre class="diff"><span>
<span class="info">--- MacRuby/branches/experimental/roxor.cpp        2009-04-01 12:49:41 UTC (rev 1287)
+++ MacRuby/branches/experimental/roxor.cpp        2009-04-03 02:11:56 UTC (rev 1288)
</span><span class="lines">@@ -1,8 +1,8 @@
</span><span class="cx"> /* ROXOR: the new MacRuby VM that rocks! */
</span><span class="cx"> 
</span><del>-#define ROXOR_COMPILER_DEBUG        0
-#define ROXOR_VM_DEBUG                0
-#define ROXOR_DUMP_IR                0
</del><ins>+#define ROXOR_COMPILER_DEBUG                0
+#define ROXOR_VM_DEBUG                        0
+#define ROXOR_DUMP_IR_BEFORE_EXIT        0
</ins><span class="cx"> 
</span><span class="cx"> #include &lt;llvm/Module.h&gt;
</span><span class="cx"> #include &lt;llvm/DerivedTypes.h&gt;
</span><span class="lines">@@ -170,7 +170,7 @@
</span><span class="cx">         const char *fname;
</span><span class="cx"> 
</span><span class="cx">         std::map&lt;ID, Value *&gt; lvars;
</span><del>-        std::map&lt;ID, Value *&gt; dvars;
</del><ins>+        std::vector&lt;ID&gt; dvars;
</ins><span class="cx">         std::map&lt;ID, int *&gt; ivar_slots_cache;
</span><span class="cx"> 
</span><span class="cx"> #if ROXOR_COMPILER_DEBUG
</span><span class="lines">@@ -203,6 +203,7 @@
</span><span class="cx">         Function *fastEqqFunc;
</span><span class="cx">         Function *whenSplatFunc;
</span><span class="cx">         Function *prepareBlockFunc;
</span><ins>+        Function *pushBindingFunc;
</ins><span class="cx">         Function *getBlockFunc;
</span><span class="cx">         Function *currentBlockObjectFunc;
</span><span class="cx">         Function *getConstFunc;
</span><span class="lines">@@ -245,7 +246,8 @@
</span><span class="cx">         Constant *undefVal;
</span><span class="cx">         Constant *splatArgFollowsVal;
</span><span class="cx">         const Type *RubyObjTy; 
</span><del>-        const Type *RubyObjPtrTy; 
</del><ins>+        const Type *RubyObjPtrTy;
+        const Type *RubyObjPtrPtrTy;
</ins><span class="cx">         const Type *PtrTy;
</span><span class="cx">         const Type *IntTy;
</span><span class="cx"> 
</span><span class="lines">@@ -275,6 +277,7 @@
</span><span class="cx">         Value *compile_fast_eqq_call(Value *selfVal, Value *comparedToVal);
</span><span class="cx">         Value *compile_attribute_assign(NODE *node, Value *extra_val);
</span><span class="cx">         Value *compile_block_create(NODE *node=NULL);
</span><ins>+        Value *compile_binding(void);
</ins><span class="cx">         Value *compile_optimized_dispatch_call(SEL sel, int argc, std::vector&lt;Value *&gt; &amp;params);
</span><span class="cx">         Value *compile_ivar_read(ID vid);
</span><span class="cx">         Value *compile_ivar_assignment(ID vid, Value *val);
</span><span class="lines">@@ -284,30 +287,14 @@
</span><span class="cx">         Value *compile_singleton_class(Value *obj);
</span><span class="cx">         Value *compile_defined_expression(NODE *node);
</span><span class="cx">         Value *compile_dstr(NODE *node);
</span><ins>+        Value *compile_dvar_slot(ID name);
+
</ins><span class="cx">         void compile_dead_branch(void);
</span><span class="cx">         void compile_landing_pad_header(void);
</span><span class="cx">         void compile_landing_pad_footer(void);
</span><span class="cx">         void compile_rethrow_exception(void);
</span><ins>+        Value *compile_lvar_slot(ID name);
</ins><span class="cx"> 
</span><del>-        Value *get_var(ID name, std::map&lt;ID, Value *&gt; &amp;container, 
-                       bool do_assert) {
-            std::map&lt;ID, Value *&gt;::iterator iter = container.find(name);
-            if (do_assert) {
-#if ROXOR_COMPILER_DEBUG
-                printf(&quot;get_var %s\n&quot;, rb_id2name(name));
-#endif
-                assert(iter != container.end());
-                return iter-&gt;second;
-            }
-            else {
-                return iter != container.end() ? iter-&gt;second : NULL;
-            }
-        }
-
-        Value *get_lvar(ID name, bool do_assert=true) {
-            return get_var(name, lvars, do_assert);
-        }
-
</del><span class="cx">         int *get_slot_cache(ID id) {
</span><span class="cx">             if (current_block || !current_instance_method) {
</span><span class="cx">                 // TODO should also return NULL if we are inside a module
</span><span class="lines">@@ -413,6 +400,7 @@
</span><span class="cx">         VALUE last_status;
</span><span class="cx">         VALUE errinfo;
</span><span class="cx">         int safe_level;
</span><ins>+        std::vector&lt;rb_vm_binding_t *&gt; bindings;
</ins><span class="cx">         std::map&lt;NODE *, rb_vm_block_t *&gt; blocks;
</span><span class="cx">         std::map&lt;double, struct rb_float_cache *&gt; float_cache;
</span><span class="cx">         unsigned char method_missing_reason;
</span><span class="lines">@@ -520,6 +508,18 @@
</span><span class="cx">                 outers[klass] = class_outer;
</span><span class="cx">             }
</span><span class="cx">         }
</span><ins>+
+        VALUE *get_binding_lvar(ID name) {
+            if (!bindings.empty()) {
+                rb_vm_binding_t *b = bindings.back();
+                for (rb_vm_local_t *l = b-&gt;locals; l != NULL; l = l-&gt;next) {
+                    if (l-&gt;name == name) {
+                        return l-&gt;value;
+                    }
+                }
+            }
+            return NULL;
+        }
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> RoxorVM *RoxorVM::current = NULL;
</span><span class="lines">@@ -551,6 +551,7 @@
</span><span class="cx">     fastEqqFunc = NULL;
</span><span class="cx">     whenSplatFunc = NULL;
</span><span class="cx">     prepareBlockFunc = NULL;
</span><ins>+    pushBindingFunc = NULL;
</ins><span class="cx">     getBlockFunc = NULL;
</span><span class="cx">     currentBlockObjectFunc = NULL;
</span><span class="cx">     getConstFunc = NULL;
</span><span class="lines">@@ -595,6 +596,7 @@
</span><span class="cx">     twoVal = ConstantInt::get(IntTy, 2);
</span><span class="cx"> 
</span><span class="cx">     RubyObjPtrTy = PointerType::getUnqual(RubyObjTy);
</span><ins>+    RubyObjPtrPtrTy = PointerType::getUnqual(RubyObjPtrTy);
</ins><span class="cx">     nilVal = ConstantInt::get(RubyObjTy, Qnil);
</span><span class="cx">     trueVal = ConstantInt::get(RubyObjTy, Qtrue);
</span><span class="cx">     falseVal = ConstantInt::get(RubyObjTy, Qfalse);
</span><span class="lines">@@ -943,7 +945,8 @@
</span><span class="cx">     assert(current_block_func != NULL &amp;&amp; current_block_node != NULL);
</span><span class="cx"> 
</span><span class="cx">     if (prepareBlockFunc == NULL) {
</span><del>-        // void *rb_vm_prepare_block(Function *func, NODE *node, VALUE self, int dvars_size, ...);
</del><ins>+        // void *rb_vm_prepare_block(Function *func, NODE *node, VALUE self,
+        //                             int dvars_size, ...);
</ins><span class="cx">         std::vector&lt;const Type *&gt; types;
</span><span class="cx">         types.push_back(PtrTy);
</span><span class="cx">         types.push_back(PtrTy);
</span><span class="lines">@@ -959,20 +962,58 @@
</span><span class="cx">     params.push_back(compile_const_pointer(current_block_node));
</span><span class="cx">     params.push_back(current_self);
</span><span class="cx"> 
</span><ins>+    // Dvars.
</ins><span class="cx">     params.push_back(ConstantInt::get(Type::Int32Ty, (int)dvars.size()));
</span><ins>+    for (std::vector&lt;ID&gt;::iterator iter = dvars.begin();
+         iter != dvars.end(); ++iter) {
+        params.push_back(compile_lvar_slot(*iter));
+    }
</ins><span class="cx"> 
</span><del>-    std::map&lt;ID, Value *&gt;::iterator iter = dvars.begin();
-    while (iter != dvars.end()) {
-        std::map&lt;ID, Value *&gt;::iterator iter2 = lvars.find(iter-&gt;first);
-        assert(iter2 != lvars.end());
-        params.push_back(iter2-&gt;second);
-        ++iter;
</del><ins>+    // Lvars.
+    params.push_back(ConstantInt::get(Type::Int32Ty, (int)lvars.size()));
+    for (std::map&lt;ID, Value *&gt;::iterator iter = lvars.begin();
+         iter != lvars.end(); ++iter) {
+        ID name = iter-&gt;first;
+        Value *slot = iter-&gt;second;
+        if (std::find(dvars.begin(), dvars.end(), name) == dvars.end()) {
+            params.push_back(ConstantInt::get(IntTy, (long)name));
+            params.push_back(slot);
+        }
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    return CallInst::Create(prepareBlockFunc, params.begin(), params.end(), &quot;&quot;, bb);
</del><ins>+    return CallInst::Create(prepareBlockFunc, params.begin(), params.end(),
+            &quot;&quot;, bb);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> Value *
</span><ins>+RoxorCompiler::compile_binding(void)
+{
+    if (pushBindingFunc == NULL) {
+        // void rb_vm_push_binding(VALUE self, int lvars_size, ...);
+        std::vector&lt;const Type *&gt; types;
+        types.push_back(RubyObjTy);
+        types.push_back(Type::Int32Ty);
+        FunctionType *ft = FunctionType::get(Type::VoidTy, types, true);
+        pushBindingFunc = cast&lt;Function&gt;
+            (module-&gt;getOrInsertFunction(&quot;rb_vm_push_binding&quot;, ft));
+    }
+
+    std::vector&lt;Value *&gt; params;
+    params.push_back(current_self);
+
+    // Lvars.
+    params.push_back(ConstantInt::get(Type::Int32Ty, (int)lvars.size()));
+    for (std::map&lt;ID, Value *&gt;::iterator iter = lvars.begin();
+         iter != lvars.end(); ++iter) {
+        params.push_back(ConstantInt::get(IntTy, (long)iter-&gt;first));
+        params.push_back(iter-&gt;second);
+    }
+
+    return CallInst::Create(pushBindingFunc, params.begin(), params.end(),
+            &quot;&quot;, bb);
+}
+
+Value *
</ins><span class="cx"> RoxorCompiler::compile_ivar_read(ID vid)
</span><span class="cx"> {
</span><span class="cx">     if (getIvarFunc == NULL) {
</span><span class="lines">@@ -1277,6 +1318,34 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> Value *
</span><ins>+RoxorCompiler::compile_dvar_slot(ID name)
+{
+    // TODO we should cache this
+    int i = 0, idx = -1;
+    for (std::vector&lt;ID&gt;::iterator iter = dvars.begin();
+         iter != dvars.end(); ++iter) {
+        if (*iter == name) {
+            idx = i;
+            break;
+        }
+        i++;
+    }
+    if (idx == -1) {
+        return NULL;
+    }
+
+    Function::ArgumentListType::iterator fargs_i =
+        bb-&gt;getParent()-&gt;getArgumentList().begin();
+    ++fargs_i; // skip self
+    ++fargs_i; // skip sel
+    Value *dvars_ary = fargs_i;
+
+    Value *index = ConstantInt::get(Type::Int32Ty, idx);
+    Value *slot = GetElementPtrInst::Create(dvars_ary, index, rb_id2name(name), bb);
+    return new LoadInst(slot, &quot;&quot;, bb);
+}
+
+Value *
</ins><span class="cx"> RoxorCompiler::compile_class_path(NODE *node)
</span><span class="cx"> {
</span><span class="cx">     if (nd_type(node) == NODE_COLON3) {
</span><span class="lines">@@ -2273,15 +2342,22 @@
</span><span class="cx">             {
</span><span class="cx">                 rb_vm_arity_t arity = rb_vm_node_arity(node);
</span><span class="cx">                 const int nargs = bb == NULL ? 0 : arity.real;
</span><ins>+                const bool has_dvars = current_block &amp;&amp; current_mid == 0;
</ins><span class="cx"> 
</span><span class="cx">                 // Get dynamic vars.
</span><del>-                if (current_block &amp;&amp; node-&gt;nd_tbl != NULL) {
</del><ins>+                if (has_dvars &amp;&amp; node-&gt;nd_tbl != NULL) {
</ins><span class="cx">                     const int args_count = (int)node-&gt;nd_tbl[0];
</span><span class="cx">                     const int lvar_count = (int)node-&gt;nd_tbl[args_count + 1];
</span><span class="cx">                     for (int i = 0; i &lt; lvar_count; i++) {
</span><span class="cx">                         ID id = node-&gt;nd_tbl[i + args_count + 2];
</span><span class="cx">                         if (lvars.find(id) != lvars.end()) {
</span><del>-                            dvars[id] = NULL;
</del><ins>+                            std::vector&lt;ID&gt;::iterator iter = std::find(dvars.begin(), dvars.end(), id);
+                            if (iter == dvars.end()) {
+#if ROXOR_COMPILER_DEBUG
+                                printf(&quot;dvar %s\n&quot;, rb_id2name(id));
+#endif
+                                dvars.push_back(id);
+                            }
</ins><span class="cx">                         }
</span><span class="cx">                     }
</span><span class="cx">                 }
</span><span class="lines">@@ -2290,8 +2366,8 @@
</span><span class="cx">                 std::vector&lt;const Type *&gt; types;
</span><span class="cx">                 types.push_back(RubyObjTy);        // self
</span><span class="cx">                 types.push_back(PtrTy);                // sel
</span><del>-                for (int i = 0, count = dvars.size(); i &lt; count; i++) {
-                    types.push_back(RubyObjPtrTy);
</del><ins>+                if (has_dvars) {
+                    types.push_back(RubyObjPtrPtrTy); // dvars array
</ins><span class="cx">                 }
</span><span class="cx">                 for (int i = 0; i &lt; nargs; ++i) {
</span><span class="cx">                     types.push_back(RubyObjTy);
</span><span class="lines">@@ -2319,19 +2395,9 @@
</span><span class="cx">                 Value *sel = arg++;
</span><span class="cx">                 sel-&gt;setName(&quot;sel&quot;);
</span><span class="cx"> 
</span><del>-                for (std::map&lt;ID, Value *&gt;::iterator iter = dvars.begin();
-                     iter != dvars.end(); 
-                     ++iter) {
-
-                    ID id = iter-&gt;first;
-                    assert(iter-&gt;second == NULL);
-        
-                    Value *val = arg++;
-                    val-&gt;setName(std::string(&quot;dyna_&quot;) + rb_id2name(id));
-#if ROXOR_COMPILER_DEBUG
-                    printf(&quot;dvar %s\n&quot;, rb_id2name(id));
-#endif
-                    lvars[id] = val;
</del><ins>+                if (has_dvars) {
+                    Value *dvars_arg = arg++;
+                    dvars_arg-&gt;setName(&quot;dvars&quot;);
</ins><span class="cx">                 }
</span><span class="cx"> 
</span><span class="cx">                 if (node-&gt;nd_tbl != NULL) {
</span><span class="lines">@@ -2373,12 +2439,14 @@
</span><span class="cx">                         if (lvars.find(id) != lvars.end()) {
</span><span class="cx">                             continue;
</span><span class="cx">                         }
</span><ins>+                        if (std::find(dvars.begin(), dvars.end(), id) == dvars.end()) {
</ins><span class="cx"> #if ROXOR_COMPILER_DEBUG
</span><del>-                        printf(&quot;var %s\n&quot;, rb_id2name(id));
</del><ins>+                            printf(&quot;lvar %s\n&quot;, rb_id2name(id));
</ins><span class="cx"> #endif
</span><del>-                        Value *store = new AllocaInst(RubyObjTy, &quot;&quot;, bb);
-                        new StoreInst(nilVal, store, bb);
-                        lvars[id] = store;
</del><ins>+                            Value *store = new AllocaInst(RubyObjTy, &quot;&quot;, bb);
+                            new StoreInst(nilVal, store, bb);
+                            lvars[id] = store;
+                        }
</ins><span class="cx">                     }
</span><span class="cx"> 
</span><span class="cx">                     NODE *args_node = node-&gt;nd_args;
</span><span class="lines">@@ -2410,9 +2478,12 @@
</span><span class="cx">                         ++iter; // skip sel
</span><span class="cx">                         NODE *opt_node = args_node-&gt;nd_opt;
</span><span class="cx">                         if (opt_node != NULL) {
</span><del>-                            int to_skip = dvars.size() + args_node-&gt;nd_frml;
</del><ins>+                            int to_skip = args_node-&gt;nd_frml;
+                            if (has_dvars) {
+                                to_skip++; // dvars array
+                            }
</ins><span class="cx">                             for (i = 0; i &lt; to_skip; i++) {
</span><del>-                                ++iter;  // skip dvars and args required on the left-side
</del><ins>+                                ++iter; // skip dvars and args required on the left-side
</ins><span class="cx">                             }
</span><span class="cx">                             iter = compile_optional_arguments(iter, opt_node);
</span><span class="cx">                         }
</span><span class="lines">@@ -2448,8 +2519,8 @@
</span><span class="cx">         case NODE_LVAR:
</span><span class="cx">             {
</span><span class="cx">                 assert(node-&gt;nd_vid &gt; 0);
</span><del>-                
-                return new LoadInst(get_lvar(node-&gt;nd_vid), &quot;&quot;, bb);
</del><ins>+
+                return new LoadInst(compile_lvar_slot(node-&gt;nd_vid), &quot;&quot;, bb);
</ins><span class="cx">             }
</span><span class="cx">             break;
</span><span class="cx"> 
</span><span class="lines">@@ -2577,7 +2648,7 @@
</span><span class="cx">                         case NODE_DASGN:
</span><span class="cx">                         case NODE_DASGN_CURR:
</span><span class="cx">                             {                            
</span><del>-                                Value *slot = get_lvar(ln-&gt;nd_vid);
</del><ins>+                                Value *slot = compile_lvar_slot(ln-&gt;nd_vid);
</ins><span class="cx">                                 new StoreInst(elt, slot, bb);
</span><span class="cx">                             }
</span><span class="cx">                             break;
</span><span class="lines">@@ -2616,12 +2687,9 @@
</span><span class="cx">                 assert(node-&gt;nd_vid &gt; 0);
</span><span class="cx">                 assert(node-&gt;nd_value != NULL);
</span><span class="cx"> 
</span><del>-                Value *slot = get_lvar(node-&gt;nd_vid);
-
</del><span class="cx">                 Value *new_val = compile_node(node-&gt;nd_value);
</span><ins>+                new StoreInst(new_val, compile_lvar_slot(node-&gt;nd_vid), bb);
</ins><span class="cx"> 
</span><del>-                new StoreInst(new_val, slot, bb);
-
</del><span class="cx">                 return new_val;
</span><span class="cx">             }
</span><span class="cx">             break;
</span><span class="lines">@@ -3279,9 +3347,23 @@
</span><span class="cx">                 }
</span><span class="cx">                 params[3] = blockVal;
</span><span class="cx"> 
</span><ins>+                // If we are calling a method that needs a top-level binding
+                // object, let's create it.
+                // (Note: this won't work if the method is aliased, but we can
+                //  live with that for now)
+                if (sel == selEval
+                    || sel == selInstanceEval
+                    || sel == selClassEval
+                    || sel == selModuleEval
+                    || sel == selLocalVariables
+                    || sel == selBinding) {
+                    compile_binding();
+                }
+
</ins><span class="cx">                 // Can we optimize the call?
</span><span class="cx">                 if (!super_call &amp;&amp; !splat_args) {
</span><del>-                    Value *optimizedCall = compile_optimized_dispatch_call(sel, argc, params);
</del><ins>+                    Value *optimizedCall =
+                        compile_optimized_dispatch_call(sel, argc, params);
</ins><span class="cx">                     if (optimizedCall != NULL) {
</span><span class="cx">                         return optimizedCall;
</span><span class="cx">                     }
</span><span class="lines">@@ -4080,7 +4162,7 @@
</span><span class="cx">         case NODE_FOR:
</span><span class="cx">         case NODE_ITER:
</span><span class="cx">             {
</span><del>-                std::map&lt;ID, Value *&gt; old_dvars = dvars;
</del><ins>+                std::vector&lt;ID&gt; old_dvars = dvars;
</ins><span class="cx"> 
</span><span class="cx">                 BasicBlock *old_current_loop_begin_bb = current_loop_begin_bb;
</span><span class="cx">                 BasicBlock *old_current_loop_body_bb = current_loop_body_bb;
</span><span class="lines">@@ -4302,6 +4384,33 @@
</span><span class="cx">     return f;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+Value *
+RoxorCompiler::compile_lvar_slot(ID name)
+{
+    std::map&lt;ID, Value *&gt;::iterator iter = lvars.find(name);
+    if (iter != lvars.end()) {
+#if ROXOR_COMPILER_DEBUG
+        printf(&quot;get_lvar %s\n&quot;, rb_id2name(name));
+#endif
+        return iter-&gt;second;
+    }
+    VALUE *var = GET_VM()-&gt;get_binding_lvar(name);
+    if (var != NULL) {
+#if ROXOR_COMPILER_DEBUG
+        printf(&quot;get_binding_lvar %s (%p)\n&quot;, rb_id2name(name), *(void **)var);
+#endif
+        Value *int_val = ConstantInt::get(IntTy, (long)var);
+        return new IntToPtrInst(int_val, RubyObjPtrTy, &quot;&quot;, bb);
+    }
+    assert(current_block);
+    Value *slot = compile_dvar_slot(name);
+    assert(slot != NULL);
+#if ROXOR_COMPILER_DEBUG
+    printf(&quot;get_dvar %s\n&quot;, rb_id2name(name));
+#endif
+    return slot;
+}
+
</ins><span class="cx"> // VM primitives
</span><span class="cx"> 
</span><span class="cx"> #define MAX_ARITY 20
</span><span class="lines">@@ -4872,6 +4981,87 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> static inline VALUE
</span><ins>+__rb_vm_bcall(VALUE self, VALUE dvars, IMP pimp, const rb_vm_arity_t &amp;arity, int argc, const VALUE *argv)
+{
+    if ((arity.real != argc) || (arity.max == -1)) {
+        VALUE *new_argv = (VALUE *)alloca(sizeof(VALUE) * arity.real);
+        assert(argc &gt;= arity.min);
+        assert((arity.max == -1) || (argc &lt;= arity.max));
+        int used_opt_args = argc - arity.min;
+        int opt_args, rest_pos;
+        if (arity.max == -1) {
+            opt_args = arity.real - arity.min - 1;
+            rest_pos = arity.left_req + opt_args;
+        }
+        else {
+            opt_args = arity.real - arity.min;
+            rest_pos = -1;
+        }
+        for (int i = 0; i &lt; arity.real; ++i) {
+            if (i &lt; arity.left_req) {
+                // required args before optional args
+                new_argv[i] = argv[i];
+            }
+            else if (i &lt; arity.left_req + opt_args) {
+                // optional args
+                int opt_arg_index = i - arity.left_req;
+                if (opt_arg_index &gt;= used_opt_args) {
+                    new_argv[i] = Qundef;
+                }
+                else {
+                    new_argv[i] = argv[i];
+                }
+            }
+            else if (i == rest_pos) {
+                // rest
+                int rest_size = argc - arity.real + 1;
+                if (rest_size &lt;= 0) {
+                    new_argv[i] = rb_ary_new();
+                }
+                else {
+                    new_argv[i] = rb_ary_new4(rest_size, &amp;argv[i]);
+                }
+            }
+            else {
+                // required args after optional args
+                new_argv[i] = argv[argc-(arity.real - i)];
+            }
+        }
+        argv = new_argv;
+        argc = arity.real;
+    }
+
+    assert(pimp != NULL);
+
+    VALUE (*imp)(VALUE, SEL, VALUE, ...) = (VALUE (*)(VALUE, SEL, VALUE, ...))pimp;
+
+    switch (argc) {
+        case 0:
+            return (*imp)(self, 0, dvars);
+        case 1:
+            return (*imp)(self, 0, dvars, argv[0]);
+        case 2:
+            return (*imp)(self, 0, dvars, argv[0], argv[1]);                
+        case 3:
+            return (*imp)(self, 0, dvars, argv[0], argv[1], argv[2]);
+        case 4:
+            return (*imp)(self, 0, dvars, argv[0], argv[1], argv[2], argv[3]);
+        case 5:
+            return (*imp)(self, 0, dvars, argv[0], argv[1], argv[2], argv[3], argv[4]);
+        case 6:
+            return (*imp)(self, 0, dvars, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]);
+        case 7:
+            return (*imp)(self, 0, dvars, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6]);
+        case 8:
+            return (*imp)(self, 0, dvars, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7]);
+        case 9:
+            return (*imp)(self, 0, dvars, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8]);
+    }        
+    printf(&quot;invalid argc %d\n&quot;, argc);
+    abort();
+}
+
+static inline VALUE
</ins><span class="cx"> __rb_vm_rcall(VALUE self, NODE *node, IMP pimp, const rb_vm_arity_t &amp;arity,
</span><span class="cx">               int argc, const VALUE *argv)
</span><span class="cx"> {
</span><span class="lines">@@ -4952,7 +5142,6 @@
</span><span class="cx">     }        
</span><span class="cx">     printf(&quot;invalid argc %d\n&quot;, argc);
</span><span class="cx">     abort();
</span><del>-    return Qnil;
</del><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> static inline Method
</span><span class="lines">@@ -5151,8 +5340,11 @@
</span><span class="cx">                 ocache.helper = (struct ocall_helper *)malloc(
</span><span class="cx">                         sizeof(struct ocall_helper));
</span><span class="cx">                 ocache.helper-&gt;bs_method = rb_bs_find_method(klass, sel);
</span><del>-                assert(rb_objc_fill_sig(self, klass, sel, 
-                            &amp;ocache.helper-&gt;sig, ocache.helper-&gt;bs_method));
</del><ins>+                const bool ok = rb_objc_fill_sig(self, klass, sel, 
+                            &amp;ocache.helper-&gt;sig, ocache.helper-&gt;bs_method);
+                if (!ok) {
+                    abort();
+                }
</ins><span class="cx">             }
</span><span class="cx">         }
</span><span class="cx">         else {
</span><span class="lines">@@ -5301,6 +5493,12 @@
</span><span class="cx"> 
</span><span class="cx">     GET_VM()-&gt;current_block = old_b;
</span><span class="cx">     GET_VM()-&gt;block_saved = old_block_saved;
</span><ins>+
+    if (!GET_VM()-&gt;bindings.empty()) {
+        rb_objc_release(GET_VM()-&gt;bindings.back());        
+        GET_VM()-&gt;bindings.pop_back();
+    }
+
</ins><span class="cx">     return retval;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -5428,10 +5626,11 @@
</span><span class="cx">         GET_VM()-&gt;blocks.find(node);
</span><span class="cx"> 
</span><span class="cx">     rb_vm_block_t *b;
</span><ins>+    bool cached = false;
</ins><span class="cx"> 
</span><span class="cx">     if (iter == GET_VM()-&gt;blocks.end()) {
</span><span class="cx">         b = (rb_vm_block_t *)xmalloc(sizeof(rb_vm_block_t)
</span><del>-                + (sizeof(VALUE) * dvars_size));
</del><ins>+                + (sizeof(VALUE *) * dvars_size));
</ins><span class="cx"> 
</span><span class="cx">         if (nd_type(node) == NODE_IFUNC) {
</span><span class="cx">             assert(llvm_function == NULL);
</span><span class="lines">@@ -5452,24 +5651,85 @@
</span><span class="cx">     else {
</span><span class="cx">         b = iter-&gt;second;
</span><span class="cx">         assert(b-&gt;dvars_size == dvars_size);
</span><ins>+        cached = true;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     b-&gt;self = self;
</span><span class="cx">     b-&gt;node = node;
</span><span class="cx"> 
</span><del>-    if (dvars_size &gt; 0) {
-        va_list ar;
-        va_start(ar, dvars_size);
-        for (int i = 0; i &lt; dvars_size; ++i) {
-            b-&gt;dvars[i] = va_arg(ar, VALUE *);
</del><ins>+    va_list ar;
+    va_start(ar, dvars_size);
+    for (int i = 0; i &lt; dvars_size; ++i) {
+        b-&gt;dvars[i] = va_arg(ar, VALUE *);
+    }
+    int lvars_size = va_arg(ar, int);
+    if (lvars_size &gt; 0) {
+        if (!cached) {
+            rb_vm_local_t **l = &amp;b-&gt;locals;
+            for (int i = 0; i &lt; lvars_size; i++) {
+                GC_WB(l, xmalloc(sizeof(rb_vm_local_t)));
+                l = &amp;(*l)-&gt;next;
+            }
</ins><span class="cx">         }
</span><del>-        va_end(ar);
</del><ins>+        rb_vm_local_t *l = b-&gt;locals;
+        for (int i = 0; i &lt; lvars_size; ++i) {
+            assert(l != NULL);
+            l-&gt;name = va_arg(ar, ID);
+            l-&gt;value = va_arg(ar, VALUE *);
+            l = l-&gt;next;
+        }
</ins><span class="cx">     }
</span><ins>+    va_end(ar);
</ins><span class="cx"> 
</span><span class="cx">     return b;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> extern &quot;C&quot;
</span><ins>+void
+rb_vm_push_binding(VALUE self, int lvars_size, ...)
+{
+    rb_vm_binding_t *b = (rb_vm_binding_t *)xmalloc(sizeof(rb_vm_binding_t));
+    GC_WB(&amp;b-&gt;self, self);
+
+    va_list ar;
+    va_start(ar, lvars_size);
+    rb_vm_local_t **l = &amp;b-&gt;locals;
+    for (int i = 0; i &lt; lvars_size; ++i) {
+        GC_WB(l, xmalloc(sizeof(rb_vm_local_t)));
+        (*l)-&gt;name = va_arg(ar, ID);
+        (*l)-&gt;value = va_arg(ar, VALUE *);
+        (*l)-&gt;next = NULL;
+        l = &amp;(*l)-&gt;next;
+    }
+    va_end(ar);
+
+    rb_objc_retain(b);
+    GET_VM()-&gt;bindings.push_back(b);
+}
+
+extern &quot;C&quot;
+rb_vm_binding_t *
+rb_vm_current_binding(void)
+{
+   return GET_VM()-&gt;bindings.empty() ? NULL : GET_VM()-&gt;bindings.back();
+}
+
+extern &quot;C&quot;
+void
+rb_vm_add_binding(rb_vm_binding_t *binding)
+{
+    GET_VM()-&gt;bindings.push_back(binding);
+}
+
+extern &quot;C&quot;
+void
+rb_vm_pop_binding(void)
+{
+    GET_VM()-&gt;bindings.pop_back();
+}
+
+
+extern &quot;C&quot;
</ins><span class="cx"> VALUE
</span><span class="cx"> rb_vm_call(VALUE self, SEL sel, int argc, const VALUE *argv, bool super)
</span><span class="cx"> {
</span><span class="lines">@@ -5636,10 +5896,9 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    int dvars_size = b-&gt;dvars_size;
</del><span class="cx">     rb_vm_arity_t arity = b-&gt;arity;    
</span><span class="cx"> 
</span><del>-    if (dvars_size &gt; 0 || argc &lt; arity.min || argc &gt; arity.max) {
</del><ins>+    if (argc &lt; arity.min || argc &gt; arity.max) {
</ins><span class="cx">         VALUE *new_argv;
</span><span class="cx">         if (argc == 1 &amp;&amp; TYPE(argv[0]) == T_ARRAY &amp;&amp; (arity.min &gt; 1 || (arity.min == 1 &amp;&amp; arity.min != arity.max))) {
</span><span class="cx">             // Expand the array
</span><span class="lines">@@ -5650,63 +5909,47 @@
</span><span class="cx">             }
</span><span class="cx">             argv = new_argv;
</span><span class="cx">             argc = ary_len;
</span><del>-            if (dvars_size == 0 &amp;&amp; argc &gt;= arity.min
-                &amp;&amp; (argc &lt;= arity.max || b-&gt;arity.max == -1)) {
-                return __rb_vm_rcall(b-&gt;self, b-&gt;node, b-&gt;imp, arity, argc,
-                                     argv);
</del><ins>+            if (argc &gt;= arity.min &amp;&amp; (argc &lt;= arity.max || b-&gt;arity.max == -1)) {
+                goto block_call;
</ins><span class="cx">             }
</span><span class="cx">         }
</span><span class="cx">         int new_argc;
</span><span class="cx">         if (argc &lt;= arity.min) {
</span><del>-            new_argc = dvars_size + arity.min;
</del><ins>+            new_argc = arity.min;
</ins><span class="cx">         }
</span><span class="cx">         else if (argc &gt; arity.max &amp;&amp; b-&gt;arity.max != -1) {
</span><del>-            new_argc = dvars_size + arity.max;
</del><ins>+            new_argc = arity.max;
</ins><span class="cx">         }
</span><span class="cx">         else {
</span><del>-            new_argc = dvars_size + argc;
</del><ins>+            new_argc = argc;
</ins><span class="cx">         }
</span><span class="cx">         new_argv = (VALUE *)alloca(sizeof(VALUE) * new_argc);
</span><del>-        for (int i = 0; i &lt; dvars_size; i++) {
-            new_argv[i] = (VALUE)b-&gt;dvars[i];
</del><ins>+        for (int i = 0; i &lt; new_argc; i++) {
+            new_argv[i] = i &lt; argc ? argv[i] : Qnil;
</ins><span class="cx">         }
</span><del>-        for (int i = 0; i &lt; new_argc - dvars_size; i++) {
-            new_argv[dvars_size + i] = i &lt; argc ? argv[i] : Qnil;
-        }
</del><span class="cx">         argc = new_argc;
</span><span class="cx">         argv = new_argv;
</span><del>-        if (dvars_size &gt; 0) {
-            arity.min += dvars_size;
-            if (arity.max != -1) {
-                arity.max += dvars_size;
-            }
-            arity.real += dvars_size;
-            arity.left_req += dvars_size;
-        }
</del><span class="cx">     }
</span><span class="cx"> #if ROXOR_VM_DEBUG
</span><del>-    printf(&quot;yield block %p argc %d arity %d dvars %d\n&quot;, b, argc,
-            arity.real, b-&gt;dvars_size);
</del><ins>+    printf(&quot;yield block %p argc %d arity %d\n&quot;, b, argc, arity.real);
</ins><span class="cx"> #endif
</span><span class="cx"> 
</span><ins>+block_call:
+
</ins><span class="cx">     // We need to preserve dynamic variable slots here because our block may
</span><span class="cx">     // call the parent method which may call the block again, and since dvars
</span><span class="cx">     // are currently implemented using alloca() we will painfully die if the 
</span><span class="cx">     // previous slots are not restored.
</span><del>-
-    VALUE **old_dvars;
-    if (dvars_size &gt; 0) {
-        old_dvars = (VALUE **)alloca(sizeof(VALUE *) * dvars_size);
-        memcpy(old_dvars, b-&gt;dvars, sizeof(VALUE) * dvars_size);
</del><ins>+    VALUE *old_dvars[100];
+    assert(b-&gt;dvars_size &lt; 100);
+    for (int i = 0; i &lt; b-&gt;dvars_size; i++) {
+        old_dvars[i] = b-&gt;dvars[i];
</ins><span class="cx">     }
</span><del>-    else {
-        old_dvars = NULL;
-    }
</del><span class="cx"> 
</span><del>-    VALUE v = __rb_vm_rcall(b-&gt;self, b-&gt;node, b-&gt;imp, arity, argc, argv);
</del><ins>+    VALUE v = __rb_vm_bcall(b-&gt;self, (VALUE)b-&gt;dvars, b-&gt;imp, b-&gt;arity, argc, argv);
</ins><span class="cx"> 
</span><del>-    if (old_dvars != NULL) {
-        memcpy(b-&gt;dvars, old_dvars, sizeof(VALUE) * dvars_size);
</del><ins>+    for (int i = 0; i &lt; b-&gt;dvars_size; i++) {
+        b-&gt;dvars[i] = old_dvars[i];
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     return v;
</span><span class="lines">@@ -5780,27 +6023,6 @@
</span><span class="cx">     return rb_vm_yield0(argc, argv);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-extern &quot;C&quot;
-struct rb_float_cache *
-rb_vm_float_cache(double d)
-{
-    std::map&lt;double, struct rb_float_cache *&gt;::iterator iter = 
-        GET_VM()-&gt;float_cache.find(d);
-    if (iter == GET_VM()-&gt;float_cache.end()) {
-        struct rb_float_cache *fc = (struct rb_float_cache *)malloc(
-                sizeof(struct rb_float_cache));
-        assert(fc != NULL);
-
-        fc-&gt;count = 0;
-        fc-&gt;obj = Qnil;
-        GET_VM()-&gt;float_cache[d] = fc;
-
-        return fc;
-    }
-
-    return iter-&gt;second;
-}
-
</del><span class="cx"> extern IMP basic_respond_to_imp; // vm_method.c
</span><span class="cx"> 
</span><span class="cx"> extern &quot;C&quot;
</span><span class="lines">@@ -6065,6 +6287,28 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> extern &quot;C&quot;
</span><ins>+int
+rb_parse_in_eval(void)
+{
+    return rb_vm_parse_in_eval() ? 1 : 0;
+}
+
+extern &quot;C&quot;
+int
+rb_local_defined(ID id)
+{
+    return GET_VM()-&gt;get_binding_lvar(id) != NULL ? 1 : 0;
+}
+
+extern &quot;C&quot;
+int
+rb_dvar_defined(ID id)
+{
+    // TODO
+    return 0;
+}
+
+extern &quot;C&quot;
</ins><span class="cx"> IMP
</span><span class="cx"> rb_vm_compile(const char *fname, NODE *node)
</span><span class="cx"> {
</span><span class="lines">@@ -6099,12 +6343,6 @@
</span><span class="cx">     printf(&quot;compilation/optimization done, took %lld ns\n&quot;,  elapsedNano);
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><del>-#if ROXOR_DUMP_IR
-    printf(&quot;IR dump ----------------------------------------------\n&quot;);
-    RoxorCompiler::module-&gt;dump();
-    printf(&quot;------------------------------------------------------\n&quot;);
-#endif
-
</del><span class="cx">     delete compiler;
</span><span class="cx"> 
</span><span class="cx">     return imp;
</span><span class="lines">@@ -6112,10 +6350,18 @@
</span><span class="cx"> 
</span><span class="cx"> extern &quot;C&quot;
</span><span class="cx"> VALUE
</span><del>-rb_vm_run(const char *fname, NODE *node)
</del><ins>+rb_vm_run(const char *fname, NODE *node, rb_vm_binding_t *binding)
</ins><span class="cx"> {
</span><ins>+    if (binding != NULL) {
+        GET_VM()-&gt;bindings.push_back(binding);
+    }
+
</ins><span class="cx">     IMP imp = rb_vm_compile(fname, node);
</span><span class="cx"> 
</span><ins>+    if (binding != NULL) {
+        GET_VM()-&gt;bindings.pop_back();
+    }
+
</ins><span class="cx">     try {
</span><span class="cx">         return ((VALUE(*)(VALUE, SEL))imp)(GET_VM()-&gt;current_top_object, 0);
</span><span class="cx">     }
</span><span class="lines">@@ -6133,18 +6379,22 @@
</span><span class="cx"> 
</span><span class="cx"> extern &quot;C&quot;
</span><span class="cx"> VALUE
</span><del>-rb_vm_run_under(VALUE klass, VALUE self, const char *fname, NODE *node)
</del><ins>+rb_vm_run_under(VALUE klass, VALUE self, const char *fname, NODE *node,
+                rb_vm_binding_t *binding)
</ins><span class="cx"> {
</span><span class="cx">     assert(klass != 0);
</span><span class="cx"> 
</span><span class="cx">     VALUE old_top_object = GET_VM()-&gt;current_top_object;
</span><ins>+    if (binding != NULL) {
+        self = binding-&gt;self;
+    }
</ins><span class="cx">     if (self != 0) {
</span><span class="cx">         GET_VM()-&gt;current_top_object = self;
</span><span class="cx">     }
</span><span class="cx">     Class old_class = GET_VM()-&gt;current_class;
</span><span class="cx">     GET_VM()-&gt;current_class = (Class)klass;
</span><span class="cx"> 
</span><del>-    VALUE val = rb_vm_run(fname, node);
</del><ins>+    VALUE val = rb_vm_run(fname, node, binding);
</ins><span class="cx"> 
</span><span class="cx">     GET_VM()-&gt;current_top_object = old_top_object;
</span><span class="cx">     GET_VM()-&gt;current_class = old_class;
</span><span class="lines">@@ -6314,3 +6564,14 @@
</span><span class="cx">     rb_objc_retain((void *)top_self);
</span><span class="cx">     GET_VM()-&gt;current_top_object = top_self;
</span><span class="cx"> }
</span><ins>+
+extern &quot;C&quot;
+void
+rb_vm_finalize(void)
+{
+#if ROXOR_DUMP_IR_BEFORE_EXIT
+    printf(&quot;IR dump ----------------------------------------------\n&quot;);
+    RoxorCompiler::module-&gt;dump();
+    printf(&quot;------------------------------------------------------\n&quot;);
+#endif
+}
</ins></span></pre></div>
<a id="MacRubybranchesexperimentalroxorh"></a>
<div class="modfile"><h4>Modified: MacRuby/branches/experimental/roxor.h (1287 => 1288)</h4>
<pre class="diff"><span>
<span class="info">--- MacRuby/branches/experimental/roxor.h        2009-04-01 12:49:41 UTC (rev 1287)
+++ MacRuby/branches/experimental/roxor.h        2009-04-03 02:11:56 UTC (rev 1288)
</span><span class="lines">@@ -5,8 +5,52 @@
</span><span class="cx"> extern &quot;C&quot; {
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><del>-VALUE rb_vm_run(const char *fname, NODE *node);
-VALUE rb_vm_run_under(VALUE klass, VALUE self, const char *fname, NODE *node);
</del><ins>+typedef struct {
+    short min;                // min number of args that we accept
+    short max;                // max number of args that we accept (-1 if rest)
+    short left_req;        // number of args required on the left side
+    short real;                // number of args of the low level function
+} rb_vm_arity_t;
+
+struct rb_vm_local {
+    ID name;
+    VALUE *value;
+    struct rb_vm_local *next;
+};
+typedef struct rb_vm_local rb_vm_local_t;
+
+#define VM_BLOCK_PROC        0x0001        // block is a Proc object
+#define VM_BLOCK_LAMBDA 0x0002        // block is a lambda
+
+typedef struct {
+    VALUE self;
+    NODE *node;
+    rb_vm_arity_t arity;
+    IMP imp;
+    int flags;
+    rb_vm_local_t *locals;
+    int dvars_size;
+    VALUE *dvars[1];
+} rb_vm_block_t;
+
+typedef struct {
+    VALUE self;
+    rb_vm_local_t *locals;
+} rb_vm_binding_t;
+
+typedef struct {
+    VALUE oclass;
+    VALUE rclass;
+    VALUE recv;
+    SEL sel;
+    int arity;
+    NODE *node;                        // can be NULL (if pure Objective-C)
+    void *cache;
+} rb_vm_method_t;
+
+VALUE rb_vm_run(const char *fname, NODE *node, rb_vm_binding_t *binding);
+VALUE rb_vm_run_under(VALUE klass, VALUE self, const char *fname, NODE *node,
+                      rb_vm_binding_t *binding);
</ins><span class="cx"> IMP rb_vm_compile(const char *fname, NODE *node);
</span><span class="cx"> 
</span><span class="cx"> bool rb_vm_running(void);
</span><span class="lines">@@ -79,38 +123,8 @@
</span><span class="cx">     GC_WB(&amp;robj-&gt;slots[slot], val);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-typedef struct {
-    VALUE oclass;
-    VALUE rclass;
-    VALUE recv;
-    SEL sel;
-    int arity;
-    NODE *node;                        // can be NULL (if pure Objective-C)
-    void *cache;
-} rb_vm_method_t;
-
</del><span class="cx"> rb_vm_method_t *rb_vm_get_method(VALUE klass, VALUE obj, ID mid, int scope);
</span><span class="cx"> 
</span><del>-typedef struct {
-    short min;                // min number of args that we accept
-    short max;                // max number of args that we accept (-1 if rest)
-    short left_req;        // number of args required on the left side
-    short real;                // number of args of the low level function
-} rb_vm_arity_t;
-
-#define VM_BLOCK_PROC        0x0001        // block is a Proc object
-#define VM_BLOCK_LAMBDA 0x0002        // block is a lambda
-
-typedef struct {
-    VALUE self;
-    NODE *node;
-    rb_vm_arity_t arity;
-    IMP imp;
-    int flags;
-    int dvars_size;
-    VALUE *dvars[1];
-} rb_vm_block_t;
-
</del><span class="cx"> static inline rb_vm_block_t *
</span><span class="cx"> rb_proc_get_block(VALUE proc)
</span><span class="cx"> {
</span><span class="lines">@@ -124,13 +138,10 @@
</span><span class="cx"> void rb_vm_restore_current_block(void);
</span><span class="cx"> VALUE rb_vm_block_eval(rb_vm_block_t *block, int argc, const VALUE *argv);
</span><span class="cx"> 
</span><del>-struct rb_float_cache {
-    unsigned int count;
-    VALUE obj;
-};
</del><ins>+rb_vm_binding_t *rb_vm_current_binding(void);
+void rb_vm_add_binding(rb_vm_binding_t *binding);
+void rb_vm_pop_binding();
</ins><span class="cx"> 
</span><del>-struct rb_float_cache *rb_vm_float_cache(double d);
-
</del><span class="cx"> static inline VALUE
</span><span class="cx"> rb_robject_allocate_instance(VALUE klass)
</span><span class="cx"> {
</span><span class="lines">@@ -168,6 +179,8 @@
</span><span class="cx">     } \
</span><span class="cx">     while (0)
</span><span class="cx"> 
</span><ins>+void rb_vm_finalize(void);
+
</ins><span class="cx"> VALUE rb_iseq_compile(VALUE src, VALUE file, VALUE line);
</span><span class="cx"> VALUE rb_iseq_eval(VALUE iseq);
</span><span class="cx"> VALUE rb_iseq_new(NODE *node, VALUE filename);
</span></span></pre></div>
<a id="MacRubybranchesexperimentaltoolcompile_preluderb"></a>
<div class="modfile"><h4>Modified: MacRuby/branches/experimental/tool/compile_prelude.rb (1287 => 1288)</h4>
<pre class="diff"><span>
<span class="info">--- MacRuby/branches/experimental/tool/compile_prelude.rb        2009-04-01 12:49:41 UTC (rev 1287)
+++ MacRuby/branches/experimental/tool/compile_prelude.rb        2009-04-03 02:11:56 UTC (rev 1288)
</span><span class="lines">@@ -80,7 +80,7 @@
</span><span class="cx">   rb_vm_run(prelude_name&lt;%=i%&gt;, rb_compile_string(
</span><span class="cx">     prelude_name&lt;%=i%&gt;,
</span><span class="cx">     rb_str_new(prelude_code&lt;%=i%&gt;, sizeof(prelude_code&lt;%=i%&gt;) - 1),
</span><del>-    1));
</del><ins>+    1), NULL);
</ins><span class="cx"> 
</span><span class="cx"> % }
</span><span class="cx"> }
</span></span></pre></div>
<a id="MacRubybranchesexperimentalvm_evalc"></a>
<div class="modfile"><h4>Modified: MacRuby/branches/experimental/vm_eval.c (1287 => 1288)</h4>
<pre class="diff"><span>
<span class="info">--- MacRuby/branches/experimental/vm_eval.c        2009-04-01 12:49:41 UTC (rev 1287)
+++ MacRuby/branches/experimental/vm_eval.c        2009-04-03 02:11:56 UTC (rev 1288)
</span><span class="lines">@@ -278,7 +278,7 @@
</span><span class="cx">                    VALUE (*bl_proc) (ANYARGS), VALUE data2)
</span><span class="cx"> {
</span><span class="cx">     NODE *node = NEW_IFUNC(bl_proc, data2);
</span><del>-    rb_vm_block_t *b = rb_vm_prepare_block(NULL, node, obj, 0);
</del><ins>+    rb_vm_block_t *b = rb_vm_prepare_block(NULL, node, obj, 0, 0);
</ins><span class="cx">     rb_vm_change_current_block(b);
</span><span class="cx">     if (cache == NULL) {
</span><span class="cx">         cache = rb_vm_get_call_cache(sel);
</span><span class="lines">@@ -311,13 +311,34 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> static VALUE
</span><del>-eval_string(VALUE self, VALUE klass, VALUE src, VALUE scope, const char *file, int line)
</del><ins>+eval_string(VALUE self, VALUE klass, VALUE src, VALUE scope, const char *file,
+            const int line)
</ins><span class="cx"> {
</span><del>-    // TODO honor scope
</del><ins>+    rb_vm_binding_t *b = NULL;
+    if (scope != Qnil) {
+        if (!rb_obj_is_kind_of(scope, rb_cBinding)) {
+            rb_raise(rb_eTypeError, &quot;wrong argument type %s (expected Binding)&quot;,
+                     rb_obj_classname(scope));
+        }
+        b = (rb_vm_binding_t *)DATA_PTR(scope);
+    }
+
</ins><span class="cx">     bool old_parse_in_eval = rb_vm_parse_in_eval();
</span><span class="cx">     rb_vm_set_parse_in_eval(true);
</span><ins>+    if (b != NULL) {
+        // Binding must be added because the parser needs it.
+        rb_vm_add_binding(b);
+    }
+
</ins><span class="cx">     NODE *node = rb_compile_string(file, src, line);
</span><ins>+
+    if (b != NULL) {
+        // We remove the binding now but we still pass it to the VM, which
+        // will use it for compilation.
+        rb_vm_pop_binding();
+    }
</ins><span class="cx">     rb_vm_set_parse_in_eval(old_parse_in_eval);
</span><ins>+
</ins><span class="cx">     if (node == NULL) {
</span><span class="cx">         VALUE exc = rb_vm_current_exception();
</span><span class="cx">         if (exc != Qnil) {
</span><span class="lines">@@ -327,10 +348,11 @@
</span><span class="cx">             rb_raise(rb_eSyntaxError, &quot;compile error&quot;);
</span><span class="cx">         }
</span><span class="cx">     }
</span><ins>+
</ins><span class="cx">     if (klass == 0) {
</span><span class="cx">         klass = rb_cObject;
</span><span class="cx">     }
</span><del>-    return rb_vm_run_under(klass, self, file, node);
</del><ins>+    return rb_vm_run_under(klass, self, file, node, b);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> static VALUE
</span><span class="lines">@@ -417,13 +439,13 @@
</span><span class="cx">     if (!NIL_P(vfile)) {
</span><span class="cx">         file = RSTRING_PTR(vfile);
</span><span class="cx">     }
</span><del>-    return eval_string(0, self, src, scope, file, line);
</del><ins>+    return eval_string(self, 0, src, scope, file, line);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> VALUE
</span><span class="cx"> rb_eval_string(const char *str)
</span><span class="cx"> {
</span><del>-    return eval_string(0, rb_vm_top_self(), rb_str_new2(str), Qnil, &quot;(eval)&quot;, 1);
</del><ins>+    return eval_string(rb_vm_top_self(), 0, rb_str_new2(str), Qnil, &quot;(eval)&quot;, 1);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> VALUE
</span></span></pre>
</div>
</div>

</body>
</html>