[macruby-changes] [1288] MacRuby/branches/experimental

source_changes at macosforge.org source_changes at macosforge.org
Thu Apr 2 19:11:56 PDT 2009


Revision: 1288
          http://trac.macosforge.org/projects/ruby/changeset/1288
Author:   lsansonetti at apple.com
Date:     2009-04-02 19:11:56 -0700 (Thu, 02 Apr 2009)
Log Message:
-----------
a faster implementation of dvars + fixed eval bugs + preliminary implementation of binding

Modified Paths:
--------------
    MacRuby/branches/experimental/TODO
    MacRuby/branches/experimental/bench.rb
    MacRuby/branches/experimental/eval.c
    MacRuby/branches/experimental/id.c
    MacRuby/branches/experimental/id.h
    MacRuby/branches/experimental/load.c
    MacRuby/branches/experimental/main.c
    MacRuby/branches/experimental/numeric.c
    MacRuby/branches/experimental/proc.c
    MacRuby/branches/experimental/roxor.cpp
    MacRuby/branches/experimental/roxor.h
    MacRuby/branches/experimental/tool/compile_prelude.rb
    MacRuby/branches/experimental/vm_eval.c

Modified: MacRuby/branches/experimental/TODO
===================================================================
--- 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)
@@ -16,6 +16,7 @@
 [X] fast #send
 [ ] fast regexp =~
 [X] fast break
+[ ] write a pass manager to eliminate unnecessary arrays generated by massigns
 [ ] Array and Hash subclasses to hold immediate Ruby objects without boxing
 [/] implement backtracing/symbolication
 [/] port all rb_define_method() calls to rb_objc_define_method()

Modified: MacRuby/branches/experimental/bench.rb
===================================================================
--- 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)
@@ -147,7 +147,25 @@
     o = proc {}
     i=0; while i<30000000; o.call; i+=1; end
   end
+  bm.report('30000000 dvar write') do
+    i=0
+    30000000.times { i=1 }
+  end
 
+  # 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
+
   # Break
   bm.report('30000000 while break') do
     i=0; while i<30000000; while true; i+=1; break; end; end
@@ -198,16 +216,6 @@
     end
   end
 
-  # Eval
-  bm.report('1000 eval') do
-    i=0
-    s = "#{1+1}+#{20+20}"
-    while i<1000
-      eval(s)
-      i+=1
-    end
-  end
-
   # Method
   bm.report('3000000 Method#call w/ 0 arg') do
     o = Class1.new

Modified: MacRuby/branches/experimental/eval.c
===================================================================
--- 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)
@@ -97,6 +97,7 @@
 static void
 ruby_finalize_1(void)
 {
+    rb_vm_finalize();
     ruby_sig_finalize();
     //GET_THREAD()->errinfo = Qnil;
     rb_gc_call_finalizer_at_exit();
@@ -195,7 +196,7 @@
 	return FIX2INT(n);
     }
     rb_vm_set_running(true);
-    rb_vm_run(RSTRING_PTR(rb_progname), (NODE *)n);
+    rb_vm_run(RSTRING_PTR(rb_progname), (NODE *)n, NULL);
     return ruby_cleanup(0);
 }
 
@@ -736,8 +737,17 @@
 static VALUE
 rb_f_local_variables(VALUE rcv, SEL sel)
 {
-    // TODO
-    return Qnil;
+    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;
 }
 
 
@@ -820,27 +830,3 @@
     //rb_ivar_set(exception_error, idThrowState, INT2FIX(TAG_FATAL));
     rb_objc_retain((void *)exception_error);
 }
-
-
-/* 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;
-}

Modified: MacRuby/branches/experimental/id.c
===================================================================
--- 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)
@@ -74,6 +74,11 @@
     sel__send__ = sel_registerName("__send__:");
     selEqTilde = sel_registerName("=~:");
     selEval = sel_registerName("eval:");
+    selInstanceEval = sel_registerName("instance_eval:");
+    selClassEval = sel_registerName("class_eval:");
+    selModuleEval = sel_registerName("module_eval:");
+    selLocalVariables = sel_registerName("local_variables");
+    selBinding = sel_registerName("binding");
     selEach = sel_registerName("each");
     selEqq = sel_registerName("===:");
     selBackquote = sel_registerName("`:");

Modified: MacRuby/branches/experimental/id.h
===================================================================
--- 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)
@@ -85,6 +85,11 @@
 extern SEL sel__send__;
 extern SEL selEqTilde;
 extern SEL selEval;
+extern SEL selInstanceEval;
+extern SEL selClassEval;
+extern SEL selModuleEval;
+extern SEL selLocalVariables;
+extern SEL selBinding;
 extern SEL selEach;
 extern SEL selEqq;
 extern SEL selBackquote;

Modified: MacRuby/branches/experimental/load.c
===================================================================
--- 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)
@@ -270,7 +270,7 @@
     if (node == NULL) {
 	rb_raise(rb_eSyntaxError, "compile error");
     }
-    rb_vm_run(fname_str, node);
+    rb_vm_run(fname_str, node, NULL);
 }
 
 void

Modified: MacRuby/branches/experimental/main.c
===================================================================
--- 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)
@@ -30,6 +30,6 @@
     ruby_sysinit(&argc, &argv);
     {
 	ruby_init();
-	return ruby_run_node(ruby_options(argc, argv));
+	rb_exit(ruby_run_node(ruby_options(argc, argv)));
     }
 }

Modified: MacRuby/branches/experimental/numeric.c
===================================================================
--- 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)
@@ -532,30 +532,11 @@
 VALUE
 rb_float_new(double d)
 {
-#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
-
     NEWOBJ(flt, struct RFloat);
     OBJSETUP(flt, rb_cFloat, T_FLOAT);
 
     flt->float_value = d;
 
-#if 0
-    rb_objc_retain((void *)flt);
-    //if (cache->count == 10) {
-        cache->obj = (VALUE)flt;
-    //}
-#endif
-
     return (VALUE)flt;
 }
 

Modified: MacRuby/branches/experimental/proc.c
===================================================================
--- 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)
@@ -17,10 +17,6 @@
 
 #define GetProcPtr(obj, ptr) GetCoreDataFromValue(obj, rb_vm_block_t, ptr)
 
-typedef struct {
-    // TODO
-} rb_binding_t;
-
 VALUE rb_cUnboundMethod;
 VALUE rb_cMethod;
 VALUE rb_cBinding;
@@ -202,8 +198,8 @@
 binding_alloc(VALUE klass)
 {
     VALUE obj;
-    rb_binding_t *bind;
-    obj = Data_Make_Struct(klass, rb_binding_t,
+    rb_vm_binding_t *bind;
+    obj = Data_Make_Struct(klass, rb_vm_binding_t,
 			   NULL, NULL, bind);
     return obj;
 }
@@ -232,17 +228,9 @@
 VALUE
 rb_binding_new(void)
 {
-#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;
+    rb_vm_binding_t *bind = rb_vm_current_binding();
+    assert(bind != NULL);
+    return Data_Wrap_Struct(rb_cBinding, NULL, NULL, bind);
 }
 
 /*
@@ -1497,22 +1485,16 @@
 static VALUE
 proc_binding(VALUE self, SEL sel)
 {
-#if 0 // TODO
-    rb_proc_t *proc;
-    VALUE bindval = binding_alloc(rb_cBinding);
-    rb_binding_t *bind;
+    rb_vm_block_t *block;
+    GetProcPtr(self, block);
 
-    GetProcPtr(self, proc);
-    GetBindingPtr(bindval, bind);
+    rb_vm_binding_t *binding = (rb_vm_binding_t *)xmalloc(
+	    sizeof(rb_vm_binding_t));
 
-    if (TYPE(proc->block.iseq) == T_NODE) {
-	rb_raise(rb_eArgError, "Can't create Binding from C level Proc");
-    }
+    GC_WB(&binding->self, self);
+    GC_WB(&binding->locals, block->locals);
 
-    bind->env = proc->envval;
-    return bindval;
-#endif
-    return Qnil;
+    return Data_Wrap_Struct(rb_cBinding, NULL, NULL, binding);
 }
 
 static VALUE curry(VALUE dummy, VALUE args, int argc, VALUE *argv);

Modified: MacRuby/branches/experimental/roxor.cpp
===================================================================
--- 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)
@@ -1,8 +1,8 @@
 /* ROXOR: the new MacRuby VM that rocks! */
 
-#define ROXOR_COMPILER_DEBUG	0
-#define ROXOR_VM_DEBUG		0
-#define ROXOR_DUMP_IR		0
+#define ROXOR_COMPILER_DEBUG		0
+#define ROXOR_VM_DEBUG			0
+#define ROXOR_DUMP_IR_BEFORE_EXIT	0
 
 #include <llvm/Module.h>
 #include <llvm/DerivedTypes.h>
@@ -170,7 +170,7 @@
 	const char *fname;
 
 	std::map<ID, Value *> lvars;
-	std::map<ID, Value *> dvars;
+	std::vector<ID> dvars;
 	std::map<ID, int *> ivar_slots_cache;
 
 #if ROXOR_COMPILER_DEBUG
@@ -203,6 +203,7 @@
 	Function *fastEqqFunc;
 	Function *whenSplatFunc;
 	Function *prepareBlockFunc;
+	Function *pushBindingFunc;
 	Function *getBlockFunc;
 	Function *currentBlockObjectFunc;
 	Function *getConstFunc;
@@ -245,7 +246,8 @@
 	Constant *undefVal;
 	Constant *splatArgFollowsVal;
 	const Type *RubyObjTy; 
-	const Type *RubyObjPtrTy; 
+	const Type *RubyObjPtrTy;
+	const Type *RubyObjPtrPtrTy;
 	const Type *PtrTy;
 	const Type *IntTy;
 
@@ -275,6 +277,7 @@
 	Value *compile_fast_eqq_call(Value *selfVal, Value *comparedToVal);
 	Value *compile_attribute_assign(NODE *node, Value *extra_val);
 	Value *compile_block_create(NODE *node=NULL);
+	Value *compile_binding(void);
 	Value *compile_optimized_dispatch_call(SEL sel, int argc, std::vector<Value *> &params);
 	Value *compile_ivar_read(ID vid);
 	Value *compile_ivar_assignment(ID vid, Value *val);
@@ -284,30 +287,14 @@
 	Value *compile_singleton_class(Value *obj);
 	Value *compile_defined_expression(NODE *node);
 	Value *compile_dstr(NODE *node);
+	Value *compile_dvar_slot(ID name);
+
 	void compile_dead_branch(void);
 	void compile_landing_pad_header(void);
 	void compile_landing_pad_footer(void);
 	void compile_rethrow_exception(void);
+	Value *compile_lvar_slot(ID name);
 
-	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);
-	}
-
 	int *get_slot_cache(ID id) {
 	    if (current_block || !current_instance_method) {
 		// TODO should also return NULL if we are inside a module
@@ -413,6 +400,7 @@
 	VALUE last_status;
 	VALUE errinfo;
 	int safe_level;
+	std::vector<rb_vm_binding_t *> bindings;
 	std::map<NODE *, rb_vm_block_t *> blocks;
 	std::map<double, struct rb_float_cache *> float_cache;
 	unsigned char method_missing_reason;
@@ -520,6 +508,18 @@
 		outers[klass] = class_outer;
 	    }
 	}
+
+	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;
+	}
 };
 
 RoxorVM *RoxorVM::current = NULL;
@@ -551,6 +551,7 @@
     fastEqqFunc = NULL;
     whenSplatFunc = NULL;
     prepareBlockFunc = NULL;
+    pushBindingFunc = NULL;
     getBlockFunc = NULL;
     currentBlockObjectFunc = NULL;
     getConstFunc = NULL;
@@ -595,6 +596,7 @@
     twoVal = ConstantInt::get(IntTy, 2);
 
     RubyObjPtrTy = PointerType::getUnqual(RubyObjTy);
+    RubyObjPtrPtrTy = PointerType::getUnqual(RubyObjPtrTy);
     nilVal = ConstantInt::get(RubyObjTy, Qnil);
     trueVal = ConstantInt::get(RubyObjTy, Qtrue);
     falseVal = ConstantInt::get(RubyObjTy, Qfalse);
@@ -943,7 +945,8 @@
     assert(current_block_func != NULL && current_block_node != NULL);
 
     if (prepareBlockFunc == NULL) {
-	// void *rb_vm_prepare_block(Function *func, NODE *node, VALUE self, int dvars_size, ...);
+	// void *rb_vm_prepare_block(Function *func, NODE *node, VALUE self,
+	//			     int dvars_size, ...);
 	std::vector<const Type *> types;
 	types.push_back(PtrTy);
 	types.push_back(PtrTy);
@@ -959,20 +962,58 @@
     params.push_back(compile_const_pointer(current_block_node));
     params.push_back(current_self);
 
+    // Dvars.
     params.push_back(ConstantInt::get(Type::Int32Ty, (int)dvars.size()));
+    for (std::vector<ID>::iterator iter = dvars.begin();
+	 iter != dvars.end(); ++iter) {
+	params.push_back(compile_lvar_slot(*iter));
+    }
 
-    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;
+    // 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);
+	}
     }
 
-    return CallInst::Create(prepareBlockFunc, params.begin(), params.end(), "", bb);
+    return CallInst::Create(prepareBlockFunc, params.begin(), params.end(),
+	    "", bb);
 }
 
 Value *
+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 *
 RoxorCompiler::compile_ivar_read(ID vid)
 {
     if (getIvarFunc == NULL) {
@@ -1277,6 +1318,34 @@
 }
 
 Value *
+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 *
 RoxorCompiler::compile_class_path(NODE *node)
 {
     if (nd_type(node) == NODE_COLON3) {
@@ -2273,15 +2342,22 @@
 	    {
 		rb_vm_arity_t arity = rb_vm_node_arity(node);
 		const int nargs = bb == NULL ? 0 : arity.real;
+		const bool has_dvars = current_block && current_mid == 0;
 
 		// Get dynamic vars.
-		if (current_block && node->nd_tbl != NULL) {
+		if (has_dvars && node->nd_tbl != NULL) {
 		    const int args_count = (int)node->nd_tbl[0];
 		    const int lvar_count = (int)node->nd_tbl[args_count + 1];
 		    for (int i = 0; i < lvar_count; i++) {
 			ID id = node->nd_tbl[i + args_count + 2];
 			if (lvars.find(id) != lvars.end()) {
-			    dvars[id] = NULL;
+			    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);
+			    }
 			}
 		    }
 		}
@@ -2290,8 +2366,8 @@
 		std::vector<const Type *> types;
 		types.push_back(RubyObjTy);	// self
 		types.push_back(PtrTy);		// sel
-		for (int i = 0, count = dvars.size(); i < count; i++) {
-		    types.push_back(RubyObjPtrTy);
+		if (has_dvars) {
+		    types.push_back(RubyObjPtrPtrTy); // dvars array
 		}
 		for (int i = 0; i < nargs; ++i) {
 		    types.push_back(RubyObjTy);
@@ -2319,19 +2395,9 @@
 		Value *sel = arg++;
 		sel->setName("sel");
 
-		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;
+		if (has_dvars) {
+		    Value *dvars_arg = arg++;
+		    dvars_arg->setName("dvars");
 		}
 
 		if (node->nd_tbl != NULL) {
@@ -2373,12 +2439,14 @@
 			if (lvars.find(id) != lvars.end()) {
 			    continue;
 			}
+			if (std::find(dvars.begin(), dvars.end(), id) == dvars.end()) {
 #if ROXOR_COMPILER_DEBUG
-			printf("var %s\n", rb_id2name(id));
+			    printf("lvar %s\n", rb_id2name(id));
 #endif
-			Value *store = new AllocaInst(RubyObjTy, "", bb);
-			new StoreInst(nilVal, store, bb);
-			lvars[id] = store;
+			    Value *store = new AllocaInst(RubyObjTy, "", bb);
+			    new StoreInst(nilVal, store, bb);
+			    lvars[id] = store;
+			}
 		    }
 
 		    NODE *args_node = node->nd_args;
@@ -2410,9 +2478,12 @@
 			++iter; // skip sel
 			NODE *opt_node = args_node->nd_opt;
 			if (opt_node != NULL) {
-			    int to_skip = dvars.size() + args_node->nd_frml;
+			    int to_skip = args_node->nd_frml;
+			    if (has_dvars) {
+				to_skip++; // dvars array
+			    }
 			    for (i = 0; i < to_skip; i++) {
-				++iter;  // skip dvars and args required on the left-side
+				++iter; // skip dvars and args required on the left-side
 			    }
 			    iter = compile_optional_arguments(iter, opt_node);
 			}
@@ -2448,8 +2519,8 @@
 	case NODE_LVAR:
 	    {
 		assert(node->nd_vid > 0);
-		
-		return new LoadInst(get_lvar(node->nd_vid), "", bb);
+
+		return new LoadInst(compile_lvar_slot(node->nd_vid), "", bb);
 	    }
 	    break;
 
@@ -2577,7 +2648,7 @@
 			case NODE_DASGN:
 			case NODE_DASGN_CURR:
 			    {			    
-				Value *slot = get_lvar(ln->nd_vid);
+				Value *slot = compile_lvar_slot(ln->nd_vid);
 				new StoreInst(elt, slot, bb);
 			    }
 			    break;
@@ -2616,12 +2687,9 @@
 		assert(node->nd_vid > 0);
 		assert(node->nd_value != NULL);
 
-		Value *slot = get_lvar(node->nd_vid);
-
 		Value *new_val = compile_node(node->nd_value);
+		new StoreInst(new_val, compile_lvar_slot(node->nd_vid), bb);
 
-		new StoreInst(new_val, slot, bb);
-
 		return new_val;
 	    }
 	    break;
@@ -3279,9 +3347,23 @@
 		}
 		params[3] = blockVal;
 
+		// 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();
+		}
+
 		// Can we optimize the call?
 		if (!super_call && !splat_args) {
-		    Value *optimizedCall = compile_optimized_dispatch_call(sel, argc, params);
+		    Value *optimizedCall =
+			compile_optimized_dispatch_call(sel, argc, params);
 		    if (optimizedCall != NULL) {
 			return optimizedCall;
 		    }
@@ -4080,7 +4162,7 @@
 	case NODE_FOR:
 	case NODE_ITER:
 	    {
-		std::map<ID, Value *> old_dvars = dvars;
+		std::vector<ID> old_dvars = dvars;
 
 		BasicBlock *old_current_loop_begin_bb = current_loop_begin_bb;
 		BasicBlock *old_current_loop_body_bb = current_loop_body_bb;
@@ -4302,6 +4384,33 @@
     return f;
 }
 
+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;
+}
+
 // VM primitives
 
 #define MAX_ARITY 20
@@ -4872,6 +4981,87 @@
 }
 
 static inline VALUE
+__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
 __rb_vm_rcall(VALUE self, NODE *node, IMP pimp, const rb_vm_arity_t &arity,
 	      int argc, const VALUE *argv)
 {
@@ -4952,7 +5142,6 @@
     }	
     printf("invalid argc %d\n", argc);
     abort();
-    return Qnil;
 }
 
 static inline Method
@@ -5151,8 +5340,11 @@
 		ocache.helper = (struct ocall_helper *)malloc(
 			sizeof(struct ocall_helper));
 		ocache.helper->bs_method = rb_bs_find_method(klass, sel);
-		assert(rb_objc_fill_sig(self, klass, sel, 
-			    &ocache.helper->sig, ocache.helper->bs_method));
+		const bool ok = rb_objc_fill_sig(self, klass, sel, 
+			    &ocache.helper->sig, ocache.helper->bs_method);
+		if (!ok) {
+		    abort();
+		}
 	    }
 	}
 	else {
@@ -5301,6 +5493,12 @@
 
     GET_VM()->current_block = old_b;
     GET_VM()->block_saved = old_block_saved;
+
+    if (!GET_VM()->bindings.empty()) {
+	rb_objc_release(GET_VM()->bindings.back());	
+	GET_VM()->bindings.pop_back();
+    }
+
     return retval;
 }
 
@@ -5428,10 +5626,11 @@
 	GET_VM()->blocks.find(node);
 
     rb_vm_block_t *b;
+    bool cached = false;
 
     if (iter == GET_VM()->blocks.end()) {
 	b = (rb_vm_block_t *)xmalloc(sizeof(rb_vm_block_t)
-		+ (sizeof(VALUE) * dvars_size));
+		+ (sizeof(VALUE *) * dvars_size));
 
 	if (nd_type(node) == NODE_IFUNC) {
 	    assert(llvm_function == NULL);
@@ -5452,24 +5651,85 @@
     else {
 	b = iter->second;
 	assert(b->dvars_size == dvars_size);
+	cached = true;
     }
 
     b->self = self;
     b->node = node;
 
-    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 *);
+    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;
+	    }
 	}
-	va_end(ar);
+	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;
+	}
     }
+    va_end(ar);
 
     return b;
 }
 
 extern "C"
+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"
 VALUE
 rb_vm_call(VALUE self, SEL sel, int argc, const VALUE *argv, bool super)
 {
@@ -5636,10 +5896,9 @@
 	}
     }
 
-    int dvars_size = b->dvars_size;
     rb_vm_arity_t arity = b->arity;    
 
-    if (dvars_size > 0 || argc < arity.min || argc > arity.max) {
+    if (argc < arity.min || argc > arity.max) {
 	VALUE *new_argv;
 	if (argc == 1 && TYPE(argv[0]) == T_ARRAY && (arity.min > 1 || (arity.min == 1 && arity.min != arity.max))) {
 	    // Expand the array
@@ -5650,63 +5909,47 @@
 	    }
 	    argv = new_argv;
 	    argc = ary_len;
-	    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);
+	    if (argc >= arity.min && (argc <= arity.max || b->arity.max == -1)) {
+		goto block_call;
 	    }
 	}
 	int new_argc;
 	if (argc <= arity.min) {
-	    new_argc = dvars_size + arity.min;
+	    new_argc = arity.min;
 	}
 	else if (argc > arity.max && b->arity.max != -1) {
-	    new_argc = dvars_size + arity.max;
+	    new_argc = arity.max;
 	}
 	else {
-	    new_argc = dvars_size + argc;
+	    new_argc = argc;
 	}
 	new_argv = (VALUE *)alloca(sizeof(VALUE) * new_argc);
-	for (int i = 0; i < dvars_size; i++) {
-	    new_argv[i] = (VALUE)b->dvars[i];
+	for (int i = 0; i < new_argc; i++) {
+	    new_argv[i] = i < argc ? argv[i] : Qnil;
 	}
-	for (int i = 0; i < new_argc - dvars_size; i++) {
-	    new_argv[dvars_size + i] = i < argc ? argv[i] : Qnil;
-	}
 	argc = new_argc;
 	argv = new_argv;
-	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;
-	}
     }
 #if ROXOR_VM_DEBUG
-    printf("yield block %p argc %d arity %d dvars %d\n", b, argc,
-	    arity.real, b->dvars_size);
+    printf("yield block %p argc %d arity %d\n", b, argc, arity.real);
 #endif
 
+block_call:
+
     // We need to preserve dynamic variable slots here because our block may
     // call the parent method which may call the block again, and since dvars
     // are currently implemented using alloca() we will painfully die if the 
     // previous slots are not restored.
-
-    VALUE **old_dvars;
-    if (dvars_size > 0) {
-	old_dvars = (VALUE **)alloca(sizeof(VALUE *) * dvars_size);
-	memcpy(old_dvars, b->dvars, sizeof(VALUE) * dvars_size);
+    VALUE *old_dvars[100];
+    assert(b->dvars_size < 100);
+    for (int i = 0; i < b->dvars_size; i++) {
+	old_dvars[i] = b->dvars[i];
     }
-    else {
-	old_dvars = NULL;
-    }
 
-    VALUE v = __rb_vm_rcall(b->self, b->node, b->imp, arity, argc, argv);
+    VALUE v = __rb_vm_bcall(b->self, (VALUE)b->dvars, b->imp, b->arity, argc, argv);
 
-    if (old_dvars != NULL) {
-	memcpy(b->dvars, old_dvars, sizeof(VALUE) * dvars_size);
+    for (int i = 0; i < b->dvars_size; i++) {
+	b->dvars[i] = old_dvars[i];
     }
 
     return v;
@@ -5780,27 +6023,6 @@
     return rb_vm_yield0(argc, argv);
 }
 
-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;
-}
-
 extern IMP basic_respond_to_imp; // vm_method.c
 
 extern "C"
@@ -6065,6 +6287,28 @@
 }
 
 extern "C"
+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"
 IMP
 rb_vm_compile(const char *fname, NODE *node)
 {
@@ -6099,12 +6343,6 @@
     printf("compilation/optimization done, took %lld ns\n",  elapsedNano);
 #endif
 
-#if ROXOR_DUMP_IR
-    printf("IR dump ----------------------------------------------\n");
-    RoxorCompiler::module->dump();
-    printf("------------------------------------------------------\n");
-#endif
-
     delete compiler;
 
     return imp;
@@ -6112,10 +6350,18 @@
 
 extern "C"
 VALUE
-rb_vm_run(const char *fname, NODE *node)
+rb_vm_run(const char *fname, NODE *node, rb_vm_binding_t *binding)
 {
+    if (binding != NULL) {
+	GET_VM()->bindings.push_back(binding);
+    }
+
     IMP imp = rb_vm_compile(fname, node);
 
+    if (binding != NULL) {
+	GET_VM()->bindings.pop_back();
+    }
+
     try {
 	return ((VALUE(*)(VALUE, SEL))imp)(GET_VM()->current_top_object, 0);
     }
@@ -6133,18 +6379,22 @@
 
 extern "C"
 VALUE
-rb_vm_run_under(VALUE klass, VALUE self, const char *fname, NODE *node)
+rb_vm_run_under(VALUE klass, VALUE self, const char *fname, NODE *node,
+		rb_vm_binding_t *binding)
 {
     assert(klass != 0);
 
     VALUE old_top_object = GET_VM()->current_top_object;
+    if (binding != NULL) {
+	self = binding->self;
+    }
     if (self != 0) {
 	GET_VM()->current_top_object = self;
     }
     Class old_class = GET_VM()->current_class;
     GET_VM()->current_class = (Class)klass;
 
-    VALUE val = rb_vm_run(fname, node);
+    VALUE val = rb_vm_run(fname, node, binding);
 
     GET_VM()->current_top_object = old_top_object;
     GET_VM()->current_class = old_class;
@@ -6314,3 +6564,14 @@
     rb_objc_retain((void *)top_self);
     GET_VM()->current_top_object = top_self;
 }
+
+extern "C"
+void
+rb_vm_finalize(void)
+{
+#if ROXOR_DUMP_IR_BEFORE_EXIT
+    printf("IR dump ----------------------------------------------\n");
+    RoxorCompiler::module->dump();
+    printf("------------------------------------------------------\n");
+#endif
+}

Modified: MacRuby/branches/experimental/roxor.h
===================================================================
--- 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)
@@ -5,8 +5,52 @@
 extern "C" {
 #endif
 
-VALUE rb_vm_run(const char *fname, NODE *node);
-VALUE rb_vm_run_under(VALUE klass, VALUE self, const char *fname, NODE *node);
+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);
 IMP rb_vm_compile(const char *fname, NODE *node);
 
 bool rb_vm_running(void);
@@ -79,38 +123,8 @@
     GC_WB(&robj->slots[slot], val);
 }
 
-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;
-
 rb_vm_method_t *rb_vm_get_method(VALUE klass, VALUE obj, ID mid, int scope);
 
-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;
-
 static inline rb_vm_block_t *
 rb_proc_get_block(VALUE proc)
 {
@@ -124,13 +138,10 @@
 void rb_vm_restore_current_block(void);
 VALUE rb_vm_block_eval(rb_vm_block_t *block, int argc, const VALUE *argv);
 
-struct rb_float_cache {
-    unsigned int count;
-    VALUE obj;
-};
+rb_vm_binding_t *rb_vm_current_binding(void);
+void rb_vm_add_binding(rb_vm_binding_t *binding);
+void rb_vm_pop_binding();
 
-struct rb_float_cache *rb_vm_float_cache(double d);
-
 static inline VALUE
 rb_robject_allocate_instance(VALUE klass)
 {
@@ -168,6 +179,8 @@
     } \
     while (0)
 
+void rb_vm_finalize(void);
+
 VALUE rb_iseq_compile(VALUE src, VALUE file, VALUE line);
 VALUE rb_iseq_eval(VALUE iseq);
 VALUE rb_iseq_new(NODE *node, VALUE filename);

Modified: MacRuby/branches/experimental/tool/compile_prelude.rb
===================================================================
--- 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)
@@ -80,7 +80,7 @@
   rb_vm_run(prelude_name<%=i%>, rb_compile_string(
     prelude_name<%=i%>,
     rb_str_new(prelude_code<%=i%>, sizeof(prelude_code<%=i%>) - 1),
-    1));
+    1), NULL);
 
 % }
 }

Modified: MacRuby/branches/experimental/vm_eval.c
===================================================================
--- 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)
@@ -278,7 +278,7 @@
 		   VALUE (*bl_proc) (ANYARGS), VALUE data2)
 {
     NODE *node = NEW_IFUNC(bl_proc, data2);
-    rb_vm_block_t *b = rb_vm_prepare_block(NULL, node, obj, 0);
+    rb_vm_block_t *b = rb_vm_prepare_block(NULL, node, obj, 0, 0);
     rb_vm_change_current_block(b);
     if (cache == NULL) {
 	cache = rb_vm_get_call_cache(sel);
@@ -311,13 +311,34 @@
 }
 
 static VALUE
-eval_string(VALUE self, VALUE klass, VALUE src, VALUE scope, const char *file, int line)
+eval_string(VALUE self, VALUE klass, VALUE src, VALUE scope, const char *file,
+	    const int line)
 {
-    // TODO honor scope
+    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);
+    }
+
     bool old_parse_in_eval = rb_vm_parse_in_eval();
     rb_vm_set_parse_in_eval(true);
+    if (b != NULL) {
+	// Binding must be added because the parser needs it.
+	rb_vm_add_binding(b);
+    }
+
     NODE *node = rb_compile_string(file, src, line);
+
+    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();
+    }
     rb_vm_set_parse_in_eval(old_parse_in_eval);
+
     if (node == NULL) {
 	VALUE exc = rb_vm_current_exception();
 	if (exc != Qnil) {
@@ -327,10 +348,11 @@
 	    rb_raise(rb_eSyntaxError, "compile error");
 	}
     }
+
     if (klass == 0) {
 	klass = rb_cObject;
     }
-    return rb_vm_run_under(klass, self, file, node);
+    return rb_vm_run_under(klass, self, file, node, b);
 }
 
 static VALUE
@@ -417,13 +439,13 @@
     if (!NIL_P(vfile)) {
 	file = RSTRING_PTR(vfile);
     }
-    return eval_string(0, self, src, scope, file, line);
+    return eval_string(self, 0, src, scope, file, line);
 }
 
 VALUE
 rb_eval_string(const char *str)
 {
-    return eval_string(0, rb_vm_top_self(), rb_str_new2(str), Qnil, "(eval)", 1);
+    return eval_string(rb_vm_top_self(), 0, rb_str_new2(str), Qnil, "(eval)", 1);
 }
 
 VALUE
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macruby-changes/attachments/20090402/d2dbbe3f/attachment-0001.html>


More information about the macruby-changes mailing list