<!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<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 = "#{1+1}+#{20+20}"
+ while i<1000
+ eval(s)
+ i+=1
+ end
+ end
+ bm.report('30000000 binding-var write') do
+ i=0
+ eval('while i<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<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 = "#{1+1}+#{20+20}"
- while i<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()->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->locals; l != NULL; l = l->next) {
+        rb_ary_push(ary, ID2SYM(l->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("__send__:");
</span><span class="cx"> selEqTilde = sel_registerName("=~:");
</span><span class="cx"> selEval = sel_registerName("eval:");
</span><ins>+ selInstanceEval = sel_registerName("instance_eval:");
+ selClassEval = sel_registerName("class_eval:");
+ selModuleEval = sel_registerName("module_eval:");
+ selLocalVariables = sel_registerName("local_variables");
+ selBinding = sel_registerName("binding");
</ins><span class="cx"> selEach = sel_registerName("each");
</span><span class="cx"> selEqq = sel_registerName("===:");
</span><span class="cx"> selBackquote = sel_registerName("`:");
</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, "compile error");
</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(&argc, &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("double %f\n", d);
- struct rb_float_cache *cache = rb_vm_float_cache(d);
-
- if (cache->obj != Qnil) {
-        //printf("cached\n");
-        return cache->obj;
- }
-
- cache->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->float_value = d;
</span><span class="cx">
</span><del>-#if 0
- rb_objc_retain((void *)flt);
- //if (cache->count == 10) {
- cache->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->cfp);
- VALUE bindval = binding_alloc(rb_cBinding);
- rb_binding_t *bind;
-
- GetBindingPtr(bindval, bind);
- GC_WB(&bind->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->block.iseq) == T_NODE) {
-        rb_raise(rb_eArgError, "Can't create Binding from C level Proc");
- }
</del><ins>+ GC_WB(&binding->self, self);
+ GC_WB(&binding->locals, block->locals);
</ins><span class="cx">
</span><del>- bind->env = proc->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 <llvm/Module.h>
</span><span class="cx"> #include <llvm/DerivedTypes.h>
</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<ID, Value *> lvars;
</span><del>-        std::map<ID, Value *> dvars;
</del><ins>+        std::vector<ID> dvars;
</ins><span class="cx">         std::map<ID, int *> 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<Value *> &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<ID, Value *> &container,
-                 bool do_assert) {
-         std::map<ID, Value *>::iterator iter = container.find(name);
-         if (do_assert) {
-#if ROXOR_COMPILER_DEBUG
-                printf("get_var %s\n", rb_id2name(name));
-#endif
-                assert(iter != container.end());
-                return iter->second;
-         }
-         else {
-                return iter != container.end() ? iter->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<rb_vm_binding_t *> bindings;
</ins><span class="cx">         std::map<NODE *, rb_vm_block_t *> blocks;
</span><span class="cx">         std::map<double, struct rb_float_cache *> 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->locals; l != NULL; l = l->next) {
+                 if (l->name == name) {
+                        return l->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 && 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<const Type *> 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<ID>::iterator iter = dvars.begin();
+         iter != dvars.end(); ++iter) {
+        params.push_back(compile_lvar_slot(*iter));
+ }
</ins><span class="cx">
</span><del>- std::map<ID, Value *>::iterator iter = dvars.begin();
- while (iter != dvars.end()) {
-        std::map<ID, Value *>::iterator iter2 = lvars.find(iter->first);
-        assert(iter2 != lvars.end());
-        params.push_back(iter2->second);
-        ++iter;
</del><ins>+ // Lvars.
+ params.push_back(ConstantInt::get(Type::Int32Ty, (int)lvars.size()));
+ for (std::map<ID, Value *>::iterator iter = lvars.begin();
+         iter != lvars.end(); ++iter) {
+        ID name = iter->first;
+        Value *slot = iter->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(), "", bb);
</del><ins>+ return CallInst::Create(prepareBlockFunc, params.begin(), params.end(),
+         "", 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<const Type *> types;
+        types.push_back(RubyObjTy);
+        types.push_back(Type::Int32Ty);
+        FunctionType *ft = FunctionType::get(Type::VoidTy, types, true);
+        pushBindingFunc = cast<Function>
+         (module->getOrInsertFunction("rb_vm_push_binding", ft));
+ }
+
+ std::vector<Value *> params;
+ params.push_back(current_self);
+
+ // Lvars.
+ params.push_back(ConstantInt::get(Type::Int32Ty, (int)lvars.size()));
+ for (std::map<ID, Value *>::iterator iter = lvars.begin();
+         iter != lvars.end(); ++iter) {
+        params.push_back(ConstantInt::get(IntTy, (long)iter->first));
+        params.push_back(iter->second);
+ }
+
+ return CallInst::Create(pushBindingFunc, params.begin(), params.end(),
+         "", 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<ID>::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->getParent()->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, "", 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 && current_mid == 0;
</ins><span class="cx">
</span><span class="cx">                 // Get dynamic vars.
</span><del>-                if (current_block && node->nd_tbl != NULL) {
</del><ins>+                if (has_dvars && node->nd_tbl != NULL) {
</ins><span class="cx">                  const int args_count = (int)node->nd_tbl[0];
</span><span class="cx">                  const int lvar_count = (int)node->nd_tbl[args_count + 1];
</span><span class="cx">                  for (int i = 0; i < lvar_count; i++) {
</span><span class="cx">                         ID id = node->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<ID>::iterator iter = std::find(dvars.begin(), dvars.end(), id);
+                         if (iter == dvars.end()) {
+#if ROXOR_COMPILER_DEBUG
+                                printf("dvar %s\n", 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<const Type *> 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 < 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 < 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->setName("sel");
</span><span class="cx">
</span><del>-                for (std::map<ID, Value *>::iterator iter = dvars.begin();
-                 iter != dvars.end();
-                 ++iter) {
-
-                 ID id = iter->first;
-                 assert(iter->second == NULL);
-        
-                 Value *val = arg++;
-                 val->setName(std::string("dyna_") + rb_id2name(id));
-#if ROXOR_COMPILER_DEBUG
-                 printf("dvar %s\n", rb_id2name(id));
-#endif
-                 lvars[id] = val;
</del><ins>+                if (has_dvars) {
+                 Value *dvars_arg = arg++;
+                 dvars_arg->setName("dvars");
</ins><span class="cx">                 }
</span><span class="cx">
</span><span class="cx">                 if (node->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("var %s\n", rb_id2name(id));
</del><ins>+                         printf("lvar %s\n", rb_id2name(id));
</ins><span class="cx"> #endif
</span><del>-                        Value *store = new AllocaInst(RubyObjTy, "", bb);
-                        new StoreInst(nilVal, store, bb);
-                        lvars[id] = store;
</del><ins>+                         Value *store = new AllocaInst(RubyObjTy, "", 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->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->nd_opt;
</span><span class="cx">                         if (opt_node != NULL) {
</span><del>-                         int to_skip = dvars.size() + args_node->nd_frml;
</del><ins>+                         int to_skip = args_node->nd_frml;
+                         if (has_dvars) {
+                                to_skip++; // dvars array
+                         }
</ins><span class="cx">                          for (i = 0; i < 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->nd_vid > 0);
</span><del>-                
-                return new LoadInst(get_lvar(node->nd_vid), "", bb);
</del><ins>+
+                return new LoadInst(compile_lvar_slot(node->nd_vid), "", 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->nd_vid);
</del><ins>+                                Value *slot = compile_lvar_slot(ln->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->nd_vid > 0);
</span><span class="cx">                 assert(node->nd_value != NULL);
</span><span class="cx">
</span><del>-                Value *slot = get_lvar(node->nd_vid);
-
</del><span class="cx">                 Value *new_val = compile_node(node->nd_value);
</span><ins>+                new StoreInst(new_val, compile_lvar_slot(node->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 && !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<ID, Value *> old_dvars = dvars;
</del><ins>+                std::vector<ID> 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<ID, Value *>::iterator iter = lvars.find(name);
+ if (iter != lvars.end()) {
+#if ROXOR_COMPILER_DEBUG
+        printf("get_lvar %s\n", rb_id2name(name));
+#endif
+        return iter->second;
+ }
+ VALUE *var = GET_VM()->get_binding_lvar(name);
+ if (var != NULL) {
+#if ROXOR_COMPILER_DEBUG
+        printf("get_binding_lvar %s (%p)\n", rb_id2name(name), *(void **)var);
+#endif
+        Value *int_val = ConstantInt::get(IntTy, (long)var);
+        return new IntToPtrInst(int_val, RubyObjPtrTy, "", bb);
+ }
+ assert(current_block);
+ Value *slot = compile_dvar_slot(name);
+ assert(slot != NULL);
+#if ROXOR_COMPILER_DEBUG
+ printf("get_dvar %s\n", 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 &arity, int argc, const VALUE *argv)
+{
+ if ((arity.real != argc) || (arity.max == -1)) {
+        VALUE *new_argv = (VALUE *)alloca(sizeof(VALUE) * arity.real);
+        assert(argc >= arity.min);
+        assert((arity.max == -1) || (argc <= 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 < arity.real; ++i) {
+         if (i < arity.left_req) {
+                // required args before optional args
+                new_argv[i] = argv[i];
+         }
+         else if (i < arity.left_req + opt_args) {
+                // optional args
+                int opt_arg_index = i - arity.left_req;
+                if (opt_arg_index >= 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 <= 0) {
+                 new_argv[i] = rb_ary_new();
+                }
+                else {
+                 new_argv[i] = rb_ary_new4(rest_size, &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("invalid argc %d\n", argc);
+ abort();
+}
+
+static inline VALUE
</ins><span class="cx"> __rb_vm_rcall(VALUE self, NODE *node, IMP pimp, const rb_vm_arity_t &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("invalid argc %d\n", 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->bs_method = rb_bs_find_method(klass, sel);
</span><del>-                assert(rb_objc_fill_sig(self, klass, sel,
-                         &ocache.helper->sig, ocache.helper->bs_method));
</del><ins>+                const bool ok = rb_objc_fill_sig(self, klass, sel,
+                         &ocache.helper->sig, ocache.helper->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()->current_block = old_b;
</span><span class="cx"> GET_VM()->block_saved = old_block_saved;
</span><ins>+
+ if (!GET_VM()->bindings.empty()) {
+        rb_objc_release(GET_VM()->bindings.back());        
+        GET_VM()->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()->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()->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->second;
</span><span class="cx">         assert(b->dvars_size == dvars_size);
</span><ins>+        cached = true;
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> b->self = self;
</span><span class="cx"> b->node = node;
</span><span class="cx">
</span><del>- if (dvars_size > 0) {
-        va_list ar;
-        va_start(ar, dvars_size);
-        for (int i = 0; i < dvars_size; ++i) {
-         b->dvars[i] = va_arg(ar, VALUE *);
</del><ins>+ va_list ar;
+ va_start(ar, dvars_size);
+ for (int i = 0; i < dvars_size; ++i) {
+        b->dvars[i] = va_arg(ar, VALUE *);
+ }
+ int lvars_size = va_arg(ar, int);
+ if (lvars_size > 0) {
+        if (!cached) {
+         rb_vm_local_t **l = &b->locals;
+         for (int i = 0; i < lvars_size; i++) {
+                GC_WB(l, xmalloc(sizeof(rb_vm_local_t)));
+                l = &(*l)->next;
+         }
</ins><span class="cx">         }
</span><del>-        va_end(ar);
</del><ins>+        rb_vm_local_t *l = b->locals;
+        for (int i = 0; i < lvars_size; ++i) {
+         assert(l != NULL);
+         l->name = va_arg(ar, ID);
+         l->value = va_arg(ar, VALUE *);
+         l = l->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 "C"
</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(&b->self, self);
+
+ va_list ar;
+ va_start(ar, lvars_size);
+ rb_vm_local_t **l = &b->locals;
+ for (int i = 0; i < lvars_size; ++i) {
+        GC_WB(l, xmalloc(sizeof(rb_vm_local_t)));
+        (*l)->name = va_arg(ar, ID);
+        (*l)->value = va_arg(ar, VALUE *);
+        (*l)->next = NULL;
+        l = &(*l)->next;
+ }
+ va_end(ar);
+
+ rb_objc_retain(b);
+ GET_VM()->bindings.push_back(b);
+}
+
+extern "C"
+rb_vm_binding_t *
+rb_vm_current_binding(void)
+{
+ return GET_VM()->bindings.empty() ? NULL : GET_VM()->bindings.back();
+}
+
+extern "C"
+void
+rb_vm_add_binding(rb_vm_binding_t *binding)
+{
+ GET_VM()->bindings.push_back(binding);
+}
+
+extern "C"
+void
+rb_vm_pop_binding(void)
+{
+ GET_VM()->bindings.pop_back();
+}
+
+
+extern "C"
</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->dvars_size;
</del><span class="cx"> rb_vm_arity_t arity = b->arity;
</span><span class="cx">
</span><del>- if (dvars_size > 0 || argc < arity.min || argc > arity.max) {
</del><ins>+ if (argc < arity.min || argc > arity.max) {
</ins><span class="cx">         VALUE *new_argv;
</span><span class="cx">         if (argc == 1 && TYPE(argv[0]) == T_ARRAY && (arity.min > 1 || (arity.min == 1 && 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 && argc >= arity.min
-                && (argc <= arity.max || b->arity.max == -1)) {
-                return __rb_vm_rcall(b->self, b->node, b->imp, arity, argc,
-                                 argv);
</del><ins>+         if (argc >= arity.min && (argc <= arity.max || b->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 <= 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 > arity.max && b->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 < dvars_size; i++) {
-         new_argv[i] = (VALUE)b->dvars[i];
</del><ins>+        for (int i = 0; i < new_argc; i++) {
+         new_argv[i] = i < argc ? argv[i] : Qnil;
</ins><span class="cx">         }
</span><del>-        for (int i = 0; i < new_argc - dvars_size; i++) {
-         new_argv[dvars_size + i] = i < argc ? argv[i] : Qnil;
-        }
</del><span class="cx">         argc = new_argc;
</span><span class="cx">         argv = new_argv;
</span><del>-        if (dvars_size > 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("yield block %p argc %d arity %d dvars %d\n", b, argc,
-         arity.real, b->dvars_size);
</del><ins>+ printf("yield block %p argc %d arity %d\n", 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 > 0) {
-        old_dvars = (VALUE **)alloca(sizeof(VALUE *) * dvars_size);
-        memcpy(old_dvars, b->dvars, sizeof(VALUE) * dvars_size);
</del><ins>+ VALUE *old_dvars[100];
+ assert(b->dvars_size < 100);
+ for (int i = 0; i < b->dvars_size; i++) {
+        old_dvars[i] = b->dvars[i];
</ins><span class="cx"> }
</span><del>- else {
-        old_dvars = NULL;
- }
</del><span class="cx">
</span><del>- VALUE v = __rb_vm_rcall(b->self, b->node, b->imp, arity, argc, argv);
</del><ins>+ VALUE v = __rb_vm_bcall(b->self, (VALUE)b->dvars, b->imp, b->arity, argc, argv);
</ins><span class="cx">
</span><del>- if (old_dvars != NULL) {
-        memcpy(b->dvars, old_dvars, sizeof(VALUE) * dvars_size);
</del><ins>+ for (int i = 0; i < b->dvars_size; i++) {
+        b->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 "C"
-struct rb_float_cache *
-rb_vm_float_cache(double d)
-{
- std::map<double, struct rb_float_cache *>::iterator iter =
-        GET_VM()->float_cache.find(d);
- if (iter == GET_VM()->float_cache.end()) {
-        struct rb_float_cache *fc = (struct rb_float_cache *)malloc(
-                sizeof(struct rb_float_cache));
-        assert(fc != NULL);
-
-        fc->count = 0;
-        fc->obj = Qnil;
-        GET_VM()->float_cache[d] = fc;
-
-        return fc;
- }
-
- return iter->second;
-}
-
</del><span class="cx"> extern IMP basic_respond_to_imp; // vm_method.c
</span><span class="cx">
</span><span class="cx"> extern "C"
</span><span class="lines">@@ -6065,6 +6287,28 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> extern "C"
</span><ins>+int
+rb_parse_in_eval(void)
+{
+ return rb_vm_parse_in_eval() ? 1 : 0;
+}
+
+extern "C"
+int
+rb_local_defined(ID id)
+{
+ return GET_VM()->get_binding_lvar(id) != NULL ? 1 : 0;
+}
+
+extern "C"
+int
+rb_dvar_defined(ID id)
+{
+ // TODO
+ return 0;
+}
+
+extern "C"
</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("compilation/optimization done, took %lld ns\n", elapsedNano);
</span><span class="cx"> #endif
</span><span class="cx">
</span><del>-#if ROXOR_DUMP_IR
- printf("IR dump ----------------------------------------------\n");
- RoxorCompiler::module->dump();
- printf("------------------------------------------------------\n");
-#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 "C"
</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()->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()->bindings.pop_back();
+ }
+
</ins><span class="cx"> try {
</span><span class="cx">         return ((VALUE(*)(VALUE, SEL))imp)(GET_VM()->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 "C"
</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()->current_top_object;
</span><ins>+ if (binding != NULL) {
+        self = binding->self;
+ }
</ins><span class="cx"> if (self != 0) {
</span><span class="cx">         GET_VM()->current_top_object = self;
</span><span class="cx"> }
</span><span class="cx"> Class old_class = GET_VM()->current_class;
</span><span class="cx"> GET_VM()->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()->current_top_object = old_top_object;
</span><span class="cx"> GET_VM()->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()->current_top_object = top_self;
</span><span class="cx"> }
</span><ins>+
+extern "C"
+void
+rb_vm_finalize(void)
+{
+#if ROXOR_DUMP_IR_BEFORE_EXIT
+ printf("IR dump ----------------------------------------------\n");
+ RoxorCompiler::module->dump();
+ printf("------------------------------------------------------\n");
+#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 "C" {
</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(&robj->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<%=i%>, rb_compile_string(
</span><span class="cx"> prelude_name<%=i%>,
</span><span class="cx"> rb_str_new(prelude_code<%=i%>, sizeof(prelude_code<%=i%>) - 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, "wrong argument type %s (expected Binding)",
+                 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, "compile error");
</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, "(eval)", 1);
</del><ins>+ return eval_string(rb_vm_top_self(), 0, rb_str_new2(str), Qnil, "(eval)", 1);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> VALUE
</span></span></pre>
</div>
</div>
</body>
</html>