[macruby-changes] [4208] MacRuby/trunk

source_changes at macosforge.org source_changes at macosforge.org
Fri Jun 4 21:14:48 PDT 2010


Revision: 4208
          http://trac.macosforge.org/projects/ruby/changeset/4208
Author:   lsansonetti at apple.com
Date:     2010-06-04 21:14:46 -0700 (Fri, 04 Jun 2010)
Log Message:
-----------
moving the dispatcher bits into the kernel + misc fixes/cleanup

Modified Paths:
--------------
    MacRuby/trunk/bignum.c
    MacRuby/trunk/compiler.cpp
    MacRuby/trunk/compiler.h
    MacRuby/trunk/dispatcher.cpp
    MacRuby/trunk/error.c
    MacRuby/trunk/ext/openssl/extconf.rb
    MacRuby/trunk/ext/openssl/ossl_ssl.c
    MacRuby/trunk/gc.c
    MacRuby/trunk/include/ruby/ruby.h
    MacRuby/trunk/io.c
    MacRuby/trunk/kernel.c
    MacRuby/trunk/object.c
    MacRuby/trunk/perf/perf_method.rb
    MacRuby/trunk/rakelib/builder/options.rb
    MacRuby/trunk/rakelib/builder.rake
    MacRuby/trunk/rational.c
    MacRuby/trunk/ruby.c
    MacRuby/trunk/string.c
    MacRuby/trunk/variable.c
    MacRuby/trunk/vm.cpp
    MacRuby/trunk/vm.h
    MacRuby/trunk/vm_eval.c

Modified: MacRuby/trunk/bignum.c
===================================================================
--- MacRuby/trunk/bignum.c	2010-06-05 04:11:56 UTC (rev 4207)
+++ MacRuby/trunk/bignum.c	2010-06-05 04:14:46 UTC (rev 4208)
@@ -771,7 +771,7 @@
 	big2str_power_cache[base - 2][i] =
 	    i == 0 ? rb_big_pow(rb_int2big(base), INT2FIX(KARATSUBA_DIGITS))
 		   : bigsqr(power_cache_get_power0(base, i - 1));
-	rb_global_variable(&big2str_power_cache[base - 2][i]);
+	GC_RETAIN(big2str_power_cache[base - 2][i]);
     }
     return big2str_power_cache[base - 2][i];
 }

Modified: MacRuby/trunk/compiler.cpp
===================================================================
--- MacRuby/trunk/compiler.cpp	2010-06-05 04:11:56 UTC (rev 4207)
+++ MacRuby/trunk/compiler.cpp	2010-06-05 04:14:46 UTC (rev 4208)
@@ -76,8 +76,9 @@
     return_from_block_ids = 0;
     ensure_pn = NULL;
     block_declaration = false;
+    dispatch_argv = NULL;
 
-    dispatcherFunc = NULL;
+    dispatchFunc = get_function("vm_dispatch");
     fastPlusFunc = get_function("vm_fast_plus");
     fastMinusFunc = get_function("vm_fast_minus");
     fastMultFunc = get_function("vm_fast_mult");
@@ -138,7 +139,7 @@
     newStringFunc = NULL;
     newString2Func = NULL;
     newString3Func = NULL;
-    yieldFunc = NULL;
+    yieldFunc = get_function("vm_yield_args");
     getBrokenFunc = NULL;
     blockEvalFunc = NULL;
     gvarSetFunc = NULL;
@@ -662,24 +663,49 @@
 }
 
 Value *
-RoxorCompiler::compile_dispatch_call(std::vector<Value *> &params)
+RoxorCompiler::recompile_dispatch_argv(std::vector<Value *> &params, int offset)
 {
-    if (dispatcherFunc == NULL) {
-	// VALUE rb_vm_dispatch(VALUE top, VALUE self, SEL sel, void *block,
-	// 	unsigned char opt, int argc, ...);
-	std::vector<const Type *> types;
-	types.push_back(RubyObjTy);
-	types.push_back(RubyObjTy);
-	types.push_back(PtrTy);
-	types.push_back(PtrTy);
-	types.push_back(Int8Ty);
-	types.push_back(Int32Ty);
-	FunctionType *ft = FunctionType::get(RubyObjTy, types, true);
-	dispatcherFunc = cast<Function>
-	    (module->getOrInsertFunction("rb_vm_dispatch", ft));
+    const long argc = params.size() - offset;
+
+    if (argc == 0) {
+	return compile_const_pointer(NULL, RubyObjPtrTy);
     }
 
-    Instruction *insn = compile_protected_call(dispatcherFunc, params);
+    assert(argc > 0);
+
+    Instruction *first = bb->getParent()->getEntryBlock().getFirstNonPHI();
+    if (dispatch_argv == NULL) {
+	dispatch_argv = new AllocaInst(RubyObjTy,
+		ConstantInt::get(Int32Ty, argc), "argv", first);
+    }
+    else {
+	Value *size = dispatch_argv->getArraySize();
+	if (argc > cast<ConstantInt>(size)->getSExtValue()) {
+	    AllocaInst *new_argv = new AllocaInst(RubyObjTy,
+		    ConstantInt::get(Int32Ty, argc), "argv", first);
+	    dispatch_argv->replaceAllUsesWith(new_argv);
+	    dispatch_argv->eraseFromParent();
+	    dispatch_argv = new_argv;
+	}
+    }
+
+    for (int i = 0; i < argc; i++) {
+	Value *idx = ConstantInt::get(Int32Ty, i);
+	Value *slot = GetElementPtrInst::Create(dispatch_argv, idx, "", bb);
+	new StoreInst(params[offset + i], slot, "", bb);
+    }
+
+    return dispatch_argv;
+}
+
+Value *
+RoxorCompiler::compile_dispatch_call(std::vector<Value *> &params)
+{
+    Value *argv = recompile_dispatch_argv(params, 6);
+    params.erase(params.begin() + 6, params.end());
+    params.push_back(argv);
+
+    Instruction *insn = compile_protected_call(dispatchFunc, params);
     attach_current_line_metadata(insn);
     return insn;
 }
@@ -718,8 +744,11 @@
     params.push_back(compile_const_pointer(NULL));
     unsigned char opt = 0;
     if (recv == current_self) {
-	opt = DISPATCH_SELF_ATTRASGN;
+	opt = DISPATCH_FCALL;
     }
+    if (argc < (int)args.size()) {
+	opt |= DISPATCH_SPLAT;
+    }
     params.push_back(ConstantInt::get(Int8Ty, opt));
     params.push_back(ConstantInt::get(Int32Ty, argc));
     for (std::vector<Value *>::iterator i = args.begin();
@@ -728,11 +757,13 @@
 	params.push_back(*i);
     }
 
+    // The return value of these assignments is always the new value.
+    Value *retval = params.back();
+
     if (compile_optimized_dispatch_call(sel, argc, params) == NULL) {
 	compile_dispatch_call(params);
     }
-    // The return value of these assignments is always the new value.
-    return params.back();
+    return retval;
 }
 
 void
@@ -2315,12 +2346,14 @@
     Function *f = Function::Create(ft, GlobalValue::ExternalLinkage,
 	    function_name, module);
 
+    AllocaInst *old_dispatch_argv = dispatch_argv;
     BasicBlock *old_rescue_invoke_bb = rescue_invoke_bb;
     BasicBlock *old_rescue_rethrow_bb = rescue_rethrow_bb;
     BasicBlock *old_entry_bb = entry_bb;
     BasicBlock *old_bb = bb;
     BasicBlock *new_rescue_invoke_bb = NULL;
     BasicBlock *new_rescue_rethrow_bb = NULL;
+    dispatch_argv = NULL;
     rescue_invoke_bb = NULL;
     rescue_rethrow_bb = NULL;
     bb = BasicBlock::Create(context, "MainBlock", f);
@@ -2591,6 +2624,7 @@
     rescue_rethrow_bb = old_rescue_rethrow_bb;
     rescue_invoke_bb = old_rescue_invoke_bb;
 
+    dispatch_argv = old_dispatch_argv;
     bb = old_bb;
     entry_bb = old_entry_bb;
     lvars = old_lvars;
@@ -2603,6 +2637,328 @@
 }
 
 Value *
+RoxorCompiler::compile_call(NODE *node)
+{
+    NODE *recv = node->nd_recv;
+    NODE *args = node->nd_args;
+    ID mid = node->nd_mid;
+
+    if (nd_type(node) == NODE_CALL) {
+	assert(recv != NULL);
+    }
+    else {
+	assert(recv == NULL);
+    }
+
+    const bool block_given = current_block_func != NULL
+	&& current_block_node != NULL;
+    const bool super_call = nd_type(node) == NODE_SUPER
+	|| nd_type(node) == NODE_ZSUPER;
+
+    if (super_call) {
+	mid = current_mid;
+    }
+    else {
+	assert(mid > 0);
+    }
+
+    bool splat_args = false;
+    bool positive_arity = false;
+    if (nd_type(node) == NODE_ZSUPER) {
+	assert(args == NULL);
+	assert(current_non_block_func != NULL);
+	const long s = current_non_block_func->getArgumentList().size();
+	positive_arity = s - 2 > 0; /* skip self and sel */
+    }
+    else {
+	NODE *n = args;
+rescan_args:
+	if (n != NULL) {
+	    switch (nd_type(n)) {
+		case NODE_ARRAY:
+		    positive_arity = n->nd_alen > 0;
+		    break;
+
+		case NODE_SPLAT:
+		case NODE_ARGSPUSH:
+		case NODE_ARGSCAT:
+		    splat_args = true;
+		    positive_arity = true;
+		    break;
+
+		case NODE_BLOCK_PASS:
+		    n = n->nd_head;
+		    if (n != NULL) {
+			goto rescan_args;
+		    }
+		    positive_arity = false;
+		    break;
+
+		default:
+		    compile_node_error("invalid call args", n);
+	    }
+	}
+    }
+
+    // Recursive method call optimization. Not for everyone.
+    if (!block_given && !super_call && !splat_args && !block_declaration
+	    && positive_arity && mid == current_mid && recv == NULL) {
+
+	Function *f = bb->getParent();
+	const unsigned long argc = args == NULL ? 0 : args->nd_alen;
+
+	if (f->arg_size() - 2 == argc) {
+	    std::vector<Value *> params;
+
+	    Function::arg_iterator arg = f->arg_begin();
+
+	    params.push_back(arg++); // self
+	    params.push_back(arg++); // sel 
+
+	    for (NODE *n = args; n != NULL; n = n->nd_next) {
+		params.push_back(compile_node(n->nd_head));
+	    }
+
+	    CallInst *inst = CallInst::Create(f, params.begin(), params.end(),
+		    "", bb);
+	    // Promote for tail call elimitation.
+	    inst->setTailCall(true);
+	    return cast<Value>(inst);
+	}
+    }
+
+    // Let's set the block state as NULL temporarily, when we
+    // compile the receiver and the arguments. 
+    Function *old_current_block_func = current_block_func;
+    NODE *old_current_block_node = current_block_node;
+    current_block_func = NULL;
+    current_block_node = NULL;
+
+    // Prepare the dispatcher parameters.
+    std::vector<Value *> params;
+
+    // Prepare the selector.
+    Value *sel_val;
+    SEL sel;
+    if (mid != 0) {
+	sel = mid_to_sel(mid, positive_arity ? 1 : 0);
+	sel_val = compile_sel(sel);
+	if (block_declaration && super_call) {
+	    // A super call inside a block. The selector cannot
+	    // be determined at compilation time, but at runtime:
+	    //
+	    //  VALUE my_block(VALUE rcv, SEL sel, ...)
+	    //	// ...
+	    //	SEL super_sel = sel;
+	    //  if (super_sel == 0)
+	    //	    super_sel = <hardcoded-mid>;
+	    //	rb_vm_dispatch(..., super_sel, ...);
+	    Function *f = bb->getParent();
+	    Function::arg_iterator arg = f->arg_begin();
+	    arg++; // skip self
+	    Value *dyn_sel = arg;
+	    Value *is_null = new ICmpInst(*bb, ICmpInst::ICMP_EQ, dyn_sel,
+		    compile_const_pointer(NULL));
+	    sel_val = SelectInst::Create(is_null, sel_val, dyn_sel, "", bb);
+	}
+    }	
+    else {
+	assert(super_call);
+	// A super call outside a method definition. Compile a
+	// null selector, the runtime will raise an exception.
+	sel = 0;
+	sel_val = compile_const_pointer(NULL);
+    }
+
+    // Top.
+    params.push_back(current_self);
+
+    // Self.
+    params.push_back(recv == NULL ? current_self : compile_node(recv));
+
+    // Selector.
+    params.push_back(sel_val);
+
+    // RubySpec requires that we compile the block *after* the arguments, so we
+    // do pass NULL as the block for the moment.
+    params.push_back(compile_const_pointer(NULL));
+    NODE *real_args = args;
+    if (real_args != NULL && nd_type(real_args) == NODE_BLOCK_PASS) {
+	real_args = args->nd_head;
+    }
+
+    // Call option.
+    unsigned char call_opt = 0;
+    if (super_call) {
+	call_opt |= DISPATCH_SUPER; 
+    }
+    else if (nd_type(node) == NODE_VCALL) {
+	call_opt |= DISPATCH_VCALL;
+    }
+    else if (nd_type(node) == NODE_FCALL) {
+	call_opt |= DISPATCH_FCALL;
+    }
+    params.push_back(ConstantInt::get(Int8Ty, call_opt));
+
+    // Arguments.
+    int argc = 0;
+    if (nd_type(node) == NODE_ZSUPER) {
+	Function::ArgumentListType &fargs =
+	    current_non_block_func->getArgumentList();
+	const int fargs_arity = fargs.size() - 2;
+	params.push_back(ConstantInt::get(Int32Ty, fargs_arity));
+	Function::ArgumentListType::iterator iter = fargs.begin();
+	iter++; // skip self
+	iter++; // skip sel
+	const int rest_pos = current_arity.max == -1
+	    ? (current_arity.left_req
+		    + (current_arity.real - current_arity.min - 1))
+	    : -1;
+	int i = 0;
+	while (iter != fargs.end()) {
+	    if (i == rest_pos) {
+		params.push_back(splatArgFollowsVal);
+		splat_args = true;
+	    }
+
+	    // We can't simply push the direct argument address
+	    // because if may have a default value.
+	    ID argid = rb_intern(iter->getName().data());
+	    Value *argslot;
+	    if (block_declaration) {
+		if (std::find(dvars.begin(), dvars.end(), argid)
+			== dvars.end()) {
+		    // Dvar does not exist yet, so we create it
+		    // on demand!
+		    dvars.push_back(argid);
+		}
+		argslot = compile_dvar_slot(argid);			
+	    }
+	    else {
+		argslot = compile_lvar_slot(argid);
+	    }
+
+	    params.push_back(new LoadInst(argslot, "", bb));
+
+	    ++i;
+	    ++iter;
+	}
+	argc = fargs_arity;
+    }
+    else if (real_args != NULL) {
+	std::vector<Value *> arguments;
+	compile_dispatch_arguments(real_args, arguments, &argc);
+	params.push_back(ConstantInt::get(Int32Ty, argc));
+	for (std::vector<Value *>::iterator i = arguments.begin();
+		i != arguments.end(); ++i) {
+	    params.push_back(*i);
+	}
+    }
+    else {
+	params.push_back(ConstantInt::get(Int32Ty, 0));
+    }
+
+    // In case we have splat args, modify the call option.
+    if (splat_args) {
+	call_opt |= DISPATCH_SPLAT;
+	params[4] = ConstantInt::get(Int8Ty, call_opt);
+    }
+
+    // Restore the block state.
+    current_block_func = old_current_block_func;
+    current_block_node = old_current_block_node;
+
+    // Now compile the block and insert it in the params list!
+    Value *blockVal;
+    if (args != NULL && nd_type(args) == NODE_BLOCK_PASS) {
+	assert(!block_given);
+	assert(args->nd_body != NULL);
+	blockVal = compile_block_get(compile_node(args->nd_body));
+    }
+    else {
+	if (block_given) {
+	    blockVal = compile_block_create();
+	}
+	else if (nd_type(node) == NODE_ZSUPER && current_block_arg != NULL) {
+	    blockVal = compile_block_get(current_block_arg);	
+	}
+	else {
+	    blockVal = compile_const_pointer(NULL);
+	}
+    }
+    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 (debug_mode
+	    || (!super_call
+		&& (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 *opt_call = compile_optimized_dispatch_call(sel, argc, params);
+	if (opt_call != NULL) {
+	    return opt_call;
+	}
+    }
+
+    // Looks like we can't, just do a regular dispatch then.
+    return compile_dispatch_call(params);
+}
+
+Value *
+RoxorCompiler::compile_yield(NODE *node)
+{
+    std::vector<Value *> args;
+    int argc = 0;
+    if (node->nd_head != NULL) {
+	compile_dispatch_arguments(node->nd_head, args, &argc);
+    }
+    Value *argv = recompile_dispatch_argv(args, 0);
+
+    std::vector<Value *> params;
+    params.push_back(ConstantInt::get(Int32Ty, argc));
+    unsigned char opt = 0;
+    if (argc < (int)args.size()) {
+	opt |= DISPATCH_SPLAT;
+    }
+    params.push_back(ConstantInt::get(Int8Ty, opt));
+    params.push_back(argv);    
+
+    Value *val = compile_protected_call(yieldFunc, params);
+
+    if (getBrokenFunc == NULL) {
+	// VALUE rb_vm_get_broken_value(void)
+	getBrokenFunc = cast<Function>(module->getOrInsertFunction(
+		    "rb_vm_get_broken_value",
+		    RubyObjTy, NULL));
+    }
+
+    Value *broken = CallInst::Create(getBrokenFunc, "", bb);
+    Value *is_broken = new ICmpInst(*bb, ICmpInst::ICMP_NE, broken, undefVal);
+
+    Function *f = bb->getParent();
+    BasicBlock *broken_bb = BasicBlock::Create(context, "broken", f);
+    BasicBlock *next_bb = BasicBlock::Create(context, "next", f);
+
+    BranchInst::Create(broken_bb, next_bb, is_broken, bb);
+
+    bb = broken_bb;
+    ReturnInst::Create(context, broken, bb);
+
+    bb = next_bb;
+    return val;
+}
+
+Value *
 RoxorCompiler::compile_node(NODE *node)
 {
 #if ROXOR_COMPILER_DEBUG
@@ -2847,7 +3203,6 @@
 		params.push_back(recv);
 		params.push_back(compile_sel(sel));
 		params.push_back(compile_const_pointer(NULL));
-		params.push_back(ConstantInt::get(Int8Ty, 0));
 
 		int argc = 0;
 		std::vector<Value *> arguments;
@@ -2857,6 +3212,13 @@
 			    arguments,
 			    &argc);
 		}
+
+		unsigned char opt = 0;
+		if (argc < (int)arguments.size()) {
+		    opt |= DISPATCH_SPLAT;
+		}
+		params.push_back(ConstantInt::get(Int8Ty, opt));
+
 		params.push_back(ConstantInt::get(Int32Ty, argc));
 		for (std::vector<Value *>::iterator i = arguments.begin();
 			i != arguments.end(); ++i) {
@@ -3311,287 +3673,8 @@
 	case NODE_CALL:
 	case NODE_FCALL:
 	case NODE_VCALL:
-	    {
-		NODE *recv;
-		NODE *args;
-		ID mid;
+	    return compile_call(node);
 
-		recv = node->nd_recv;
-		args = node->nd_args;
-		mid = node->nd_mid;
-
-		if (nd_type(node) == NODE_CALL) {
-		    assert(recv != NULL);
-		}
-		else {
-		    assert(recv == NULL);
-		}
-
-		const bool block_given = current_block_func != NULL
-		    && current_block_node != NULL;
-		const bool super_call = nd_type(node) == NODE_SUPER
-		    || nd_type(node) == NODE_ZSUPER;
-
-		if (super_call) {
-		    mid = current_mid;
-		}
-		else {
-		    assert(mid > 0);
-		}
-
-		bool splat_args = false;
-		bool positive_arity = false;
-		if (nd_type(node) == NODE_ZSUPER) {
-		    assert(args == NULL);
-		    assert(current_non_block_func != NULL);
-		    positive_arity = 
-			current_non_block_func->getArgumentList().size()
-			    - 2 /* skip self and sel */ > 0;
-		}
-		else {
-		    NODE *n = args;
-rescan_args:
-		    if (n != NULL) {
-			switch (nd_type(n)) {
-			    case NODE_ARRAY:
-				positive_arity = n->nd_alen > 0;
-				break;
-
-			    case NODE_SPLAT:
-			    case NODE_ARGSPUSH:
-			    case NODE_ARGSCAT:
-				splat_args = true;
-				positive_arity = true;
-				break;
-
-			    case NODE_BLOCK_PASS:
-				n = n->nd_head;
-				if (n != NULL) {
-				    goto rescan_args;
-				}
-				positive_arity = false;
-				break;
-
-			    default:
-				compile_node_error("invalid call args", n);
-			}
-		    }
-		}
-
-		// Recursive method call optimization. Not for everyone.
-		if (!block_given && !super_call && !splat_args
-		    && !block_declaration && positive_arity
-		    && mid == current_mid && recv == NULL) {
-
-		    Function *f = bb->getParent();
-		    const unsigned long argc =
-			args == NULL ? 0 : args->nd_alen;
-
-		    if (f->arg_size() - 2 == argc) {
-			std::vector<Value *> params;
-
-			Function::arg_iterator arg = f->arg_begin();
-
-			params.push_back(arg++); // self
-			params.push_back(arg++); // sel 
-
-			for (NODE *n = args; n != NULL; n = n->nd_next) {
-			    params.push_back(compile_node(n->nd_head));
-			}
-
-			CallInst *inst = CallInst::Create(f, params.begin(),
-				params.end(), "", bb);
-			// Promote for tail call elimitation.
-			inst->setTailCall(true);
-			return cast<Value>(inst);
-		    }
-		}
-
-		// Let's set the block state as NULL temporarily, when we
-		// compile the receiver and the arguments. 
-		Function *old_current_block_func = current_block_func;
-		NODE *old_current_block_node = current_block_node;
-		current_block_func = NULL;
-		current_block_node = NULL;
-
-		// Prepare the dispatcher parameters.
-		std::vector<Value *> params;
-
-		// Prepare the selector.
-		Value *sel_val;
-		SEL sel;
-		if (mid != 0) {
-		    sel = mid_to_sel(mid, positive_arity ? 1 : 0);
-		    sel_val = compile_sel(sel);
-		    if (block_declaration && super_call) {
-			// A super call inside a block. The selector cannot
-			// be determined at compilation time, but at runtime:
-			//
-			//  VALUE my_block(VALUE rcv, SEL sel, ...)
-			//  {
-			//	// ...
-			//	SEL super_sel = sel;
-			//  	if (super_sel == 0) {
-			//	    super_sel = <hardcoded-mid>;
-			//	}
-			//	rb_vm_dispatch(..., super_sel, ...);
-			Function *f = bb->getParent();
-			Function::arg_iterator arg = f->arg_begin();
-			arg++; // skip self
-			Value *dyn_sel = arg;
-			Value *is_null = new ICmpInst(*bb, ICmpInst::ICMP_EQ,
-				dyn_sel, compile_const_pointer(NULL));
-			sel_val = SelectInst::Create(is_null, sel_val, dyn_sel,
-				"", bb);
-		    }
-		}
-		else {
-		    assert(super_call);
-		    // A super call outside a method definition. Compile a
-		    // null selector, the runtime will raise an exception.
-		    sel = 0;
-		    sel_val = compile_const_pointer(NULL);
-		}
-
-		// Top.
-		params.push_back(current_self);
-
-		// Self.
-		params.push_back(recv == NULL ? current_self
-			: compile_node(recv));
-
-		// Selector.
-		params.push_back(sel_val);
-
-		// RubySpec requires that we compile the block *after* the
-		// arguments, so we do pass NULL as the block for the moment.
-		params.push_back(compile_const_pointer(NULL));
-		NODE *real_args = args;
-		if (real_args != NULL
-		    && nd_type(real_args) == NODE_BLOCK_PASS) {
-		    real_args = args->nd_head;
-		}
-
-		// Call option.
-		const unsigned char call_opt = super_call 
-		    ? DISPATCH_SUPER
-		    : (nd_type(node) == NODE_VCALL)
-			? DISPATCH_VCALL
-			: (nd_type(node) == NODE_FCALL)
-			    ? DISPATCH_FCALL : 0;	
-		params.push_back(ConstantInt::get(Int8Ty, call_opt));
-
-		// Arguments.
-		int argc = 0;
-		if (nd_type(node) == NODE_ZSUPER) {
-		    Function::ArgumentListType &fargs =
-			current_non_block_func->getArgumentList();
-		    const int fargs_arity = fargs.size() - 2;
-		    params.push_back(ConstantInt::get(Int32Ty, fargs_arity));
-		    Function::ArgumentListType::iterator iter = fargs.begin();
-		    iter++; // skip self
-		    iter++; // skip sel
-		    const int rest_pos = current_arity.max == -1
-			? (current_arity.left_req
-				+ (current_arity.real - current_arity.min - 1))
-			: -1;
-		    int i = 0;
-		    while (iter != fargs.end()) {
-			if (i == rest_pos) {
-			    params.push_back(splatArgFollowsVal); 
-			}
-
-			// We can't simply push the direct argument address
-			// because if may have a default value.
-			ID argid = rb_intern(iter->getName().data());
-			Value *argslot;
-			if (block_declaration) {
-			    if (std::find(dvars.begin(), dvars.end(), argid)
-				    == dvars.end()) {
-				// Dvar does not exist yet, so we create it
-				// on demand!
-				dvars.push_back(argid);
-			    }
-			    argslot = compile_dvar_slot(argid);			
-			}
-			else {
-			    argslot = compile_lvar_slot(argid);
-			}
-
-			params.push_back(new LoadInst(argslot, "", bb));
-
-			++i;
-			++iter;
-		    }
-		    argc = fargs_arity;
-		}
-		else if (real_args != NULL) {
-		    std::vector<Value *> arguments;
-		    compile_dispatch_arguments(real_args, arguments, &argc);
-		    params.push_back(ConstantInt::get(Int32Ty, argc));
-		    for (std::vector<Value *>::iterator i = arguments.begin();
-			 i != arguments.end(); ++i) {
-			params.push_back(*i);
-		    }
-		}
-		else {
-		    params.push_back(ConstantInt::get(Int32Ty, 0));
-		}
-
-		// Restore the block state.
-		current_block_func = old_current_block_func;
-		current_block_node = old_current_block_node;
-
-		// Now compile the block and insert it in the params list!
-		Value *blockVal;
-		if (args != NULL && nd_type(args) == NODE_BLOCK_PASS) {
-		    assert(!block_given);
-		    assert(args->nd_body != NULL);
-		    blockVal = compile_block_get(compile_node(args->nd_body));
-		}
-		else {
-		    if (block_given) {
-			blockVal = compile_block_create();
-		    }
-		    else if (nd_type(node) == NODE_ZSUPER
-			    && current_block_arg != NULL) {
-			blockVal = compile_block_get(current_block_arg);	
-		    }
-		    else {
-			blockVal = compile_const_pointer(NULL);
-		    }
-		}
-		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 (debug_mode
-		    || (!super_call
-			&& (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);
-		    if (optimizedCall != NULL) {
-			return optimizedCall;
-		    }
-		}
-
-		// Looks like we can't, just do a regular dispatch then.
-		return compile_dispatch_call(params);
-	    }
-	    break;
-
 	case NODE_ATTRASGN:
 	    return compile_attribute_assign(node, NULL);
 
@@ -4427,53 +4510,8 @@
 	    break;
 
 	case NODE_YIELD:
-	    {
-		if (yieldFunc == NULL) {
-		    // VALUE rb_vm_yield_args(int argc, ...)
-		    std::vector<const Type *> types;
-		    types.push_back(Int32Ty);
-		    FunctionType *ft =
-			FunctionType::get(RubyObjTy, types, true);
-		    yieldFunc = cast<Function>(module->getOrInsertFunction(
-				"rb_vm_yield_args", ft));
-		}
+	    return compile_yield(node);
 
-		std::vector<Value *> params;
-		int argc = 0;
-		if (node->nd_head != NULL) {
-		    compile_dispatch_arguments(node->nd_head, params, &argc);
-		}
-		params.insert(params.begin(),
-			ConstantInt::get(Int32Ty, argc));
-
-		Value *val = compile_protected_call(yieldFunc, params);
-
-		if (getBrokenFunc == NULL) {
-		    // VALUE rb_vm_get_broken_value(void)
-		    getBrokenFunc = cast<Function>(module->getOrInsertFunction(
-				"rb_vm_get_broken_value",
-				RubyObjTy, NULL));
-		}
-
-		Value *broken = CallInst::Create(getBrokenFunc, "", bb);
-		Value *is_broken = new ICmpInst(*bb, ICmpInst::ICMP_NE, broken,
-			undefVal);
-
-		Function *f = bb->getParent();
-		BasicBlock *broken_bb = BasicBlock::Create(context, "broken",
-			f);
-		BasicBlock *next_bb = BasicBlock::Create(context, "next", f);
-
-		BranchInst::Create(broken_bb, next_bb, is_broken, bb);
-
-		bb = broken_bb;
-		ReturnInst::Create(context, broken, bb);
-		
-		bb = next_bb;
-		return val;
-	    }
-	    break;
-
 	case NODE_COLON2:
 	    {
 		assert(node->nd_mid > 0);
@@ -6264,6 +6302,7 @@
     rescue_invoke_bb = old_rescue_invoke_bb;
 #endif
 
+#if 0 // XXX
     if (ruby_func != NULL) {
 	// Now that the function is finished, we can inline the Ruby method.
 	if (CallInst::classof(ruby_call_insn)) {
@@ -6271,6 +6310,7 @@
 	    InlineFunction(insn);
 	}
     }
+#endif
 
     return f;
 }

Modified: MacRuby/trunk/compiler.h
===================================================================
--- MacRuby/trunk/compiler.h	2010-06-05 04:11:56 UTC (rev 4207)
+++ MacRuby/trunk/compiler.h	2010-06-05 04:14:46 UTC (rev 4208)
@@ -10,10 +10,10 @@
 #define __COMPILER_H_
 
 // For the dispatcher.
-#define DISPATCH_VCALL		1  // no receiver, no argument
-#define DISPATCH_FCALL		2  // no receiver, one or more arguments
-#define DISPATCH_SUPER		3  // super call
-#define DISPATCH_SELF_ATTRASGN	4  // self attribute assignment
+#define DISPATCH_VCALL		0x1  // no receiver, no argument
+#define DISPATCH_FCALL		0x2  // no receiver, one or more arguments
+#define DISPATCH_SUPER		0x4  // super call
+#define DISPATCH_SPLAT		0x8  // has splat
 #define SPLAT_ARG_FOLLOWS	0xdeadbeef
 
 // For const lookup.
@@ -127,8 +127,9 @@
 	int return_from_block_ids;
 	PHINode *ensure_pn;
 	bool block_declaration;
+	AllocaInst *dispatch_argv;
 
-	Function *dispatcherFunc;
+	Function *dispatchFunc;
 	Function *fastPlusFunc;
 	Function *fastMinusFunc;
 	Function *fastMultFunc;
@@ -308,10 +309,13 @@
 	bool should_inline_function(Function *f);
 
 	Function *compile_scope(NODE *node);
+	Value *compile_call(NODE *node);
+	Value *compile_yield(NODE *node);
 	Instruction *compile_protected_call(Value *imp, Value **args_begin,
 		Value **args_end);
-	Instruction *compile_protected_call(Value *imp,
-		std::vector<Value *> &params);
+	Instruction *compile_protected_call(Value *imp, std::vector<Value *>
+		&params);
+	Value *recompile_dispatch_argv(std::vector<Value *> &params, int idx);
 	void compile_dispatch_arguments(NODE *args,
 		std::vector<Value *> &arguments, int *pargc);
 	Function::ArgumentListType::iterator compile_optional_arguments(

Modified: MacRuby/trunk/dispatcher.cpp
===================================================================
--- MacRuby/trunk/dispatcher.cpp	2010-06-05 04:11:56 UTC (rev 4207)
+++ MacRuby/trunk/dispatcher.cpp	2010-06-05 04:14:46 UTC (rev 4208)
@@ -23,8 +23,8 @@
 #define MAX_DISPATCH_ARGS 	100
 
 static force_inline void
-__rb_vm_fix_args(const VALUE *argv, VALUE *new_argv,
-	const rb_vm_arity_t &arity, int argc)
+vm_fix_args(const VALUE *argv, VALUE *new_argv, const rb_vm_arity_t &arity,
+	int argc)
 {
     assert(argc >= arity.min);
     assert((arity.max == -1) || (argc <= arity.max));
@@ -74,9 +74,16 @@
 __rb_vm_bcall(VALUE self, SEL sel, VALUE dvars, rb_vm_block_t *b,
 	IMP pimp, const rb_vm_arity_t &arity, int argc, const VALUE *argv)
 {
-    if ((arity.real != argc) || (arity.max == -1)) {
-	VALUE *new_argv = (VALUE *)xmalloc_ptrs(sizeof(VALUE) * arity.real);
-	__rb_vm_fix_args(argv, new_argv, arity, argc);
+    VALUE buf[100];
+    if (arity.real != argc || arity.max == -1) {
+	VALUE *new_argv;
+	if (arity.real < 100) {
+	    new_argv = buf;
+	}
+	else {
+	    new_argv = (VALUE *)xmalloc_ptrs(sizeof(VALUE) * arity.real);
+	}
+	vm_fix_args(argv, new_argv, arity, argc);
 	argv = new_argv;
 	argc = arity.real;
     }
@@ -124,9 +131,16 @@
 __rb_vm_rcall(VALUE self, SEL sel, IMP pimp, const rb_vm_arity_t &arity,
 	int argc, const VALUE *argv)
 {
-    if ((arity.real != argc) || (arity.max == -1)) {
-	VALUE *new_argv = (VALUE *)xmalloc_ptrs(sizeof(VALUE) * arity.real);
-	__rb_vm_fix_args(argv, new_argv, arity, argc);
+    VALUE buf[100];
+    if (arity.real != argc || arity.max == -1) {
+	VALUE *new_argv;
+	if (arity.real < 100) {
+	    new_argv = buf;
+	}
+	else {
+	    new_argv = (VALUE *)xmalloc_ptrs(sizeof(VALUE) * arity.real);
+	}
+	vm_fix_args(argv, new_argv, arity, argc);
 	argv = new_argv;
 	argc = arity.real;
     }
@@ -369,9 +383,8 @@
 }
 
 static force_inline VALUE
-__rb_vm_ruby_dispatch(VALUE top, VALUE self, SEL sel,
-	rb_vm_method_node_t *node, unsigned char opt,
-	int argc, const VALUE *argv)
+ruby_dispatch(VALUE top, VALUE self, SEL sel, rb_vm_method_node_t *node,
+	unsigned char opt, int argc, const VALUE *argv)
 {
     const rb_vm_arity_t &arity = node->arity;
     if ((argc < arity.min) || ((arity.max != -1) && (argc > arity.max))) {
@@ -538,34 +551,14 @@
     return x_imp == y_imp;
 }
 
-static int
-mcache_hash(Class klass, SEL sel)
-{
-    return (((unsigned long)klass >> 3) ^ (unsigned long)sel)
-	& (VM_MCACHE_SIZE - 1);
-}
-
-static struct mcache *
-mcache_get(RoxorVM *vm, Class klass, SEL sel, bool super)
-{
-    struct mcache *cache;
-    if (super) {
-	const int hash = mcache_hash(klass, sel) + 1;
-	cache = &vm->get_mcache()[hash];
-	cache->flag = 0; // TODO
-    }
-    else {
-	const int hash = mcache_hash(klass, sel);
-	cache = &vm->get_mcache()[hash];
-    }
-    return cache;
-}
-
-static force_inline VALUE
-vm_call_with_cache(RoxorVM *vm, struct mcache *cache, VALUE top, VALUE self,
+extern "C"
+VALUE
+rb_vm_dispatch(void *_vm, struct mcache *cache, VALUE top, VALUE self,
 	Class klass, SEL sel, rb_vm_block_t *block, unsigned char opt,
 	int argc, const VALUE *argv)
 {
+    RoxorVM *vm = (RoxorVM *)_vm;
+
 #if ROXOR_VM_DEBUG
     bool cached = true;
 #endif
@@ -574,6 +567,11 @@
     Class current_super_class = vm->get_current_super_class();
     SEL current_super_sel = vm->get_current_super_sel();
 
+    if (opt & DISPATCH_SUPER) {
+	// TODO
+	goto recache;
+    }
+
     if (cache->sel != sel || cache->klass != klass || cache->flag == 0) {
 recache:
 #if ROXOR_VM_DEBUG
@@ -581,7 +579,7 @@
 #endif
 
 	Method method;
-	if (opt == DISPATCH_SUPER) {
+	if (opt & DISPATCH_SUPER) {
 	    if (!sel_equal(klass, current_super_sel, sel)) {
 		current_super_sel = sel;
 		current_super_class = klass;
@@ -614,7 +612,7 @@
 		fill_ocache(cache, self, klass, imp, sel, method, argc);
 	    }
 
-	    if (opt == DISPATCH_SUPER) {
+	    if (opt & DISPATCH_SUPER) {
 		cache->flag |= MCACHE_SUPER;
 	    }
 	}
@@ -628,7 +626,7 @@
 	    }
 
 	    // Does the receiver implements -forwardInvocation:?
-	    if (opt != DISPATCH_SUPER
+	    if ((opt & DISPATCH_SUPER) == 0
 		    && rb_objc_supports_forwarding(self, sel)) {
 		fill_ocache(cache, self, klass, (IMP)objc_msgSend, sel, NULL,
 			argc);
@@ -786,6 +784,7 @@
 		vm->pop_broken_with();
 		vm->set_current_super_class(current_super_class);
 		vm->set_current_super_sel(current_super_sel);
+		vm->pop_current_binding();
 	    }
 	} finalizer(block_already_current, current_klass,
 		old_current_super_class, old_current_super_sel, vm);
@@ -801,7 +800,7 @@
 	    MACRUBY_METHOD_ENTRY(class_name, method_name, file, line);
 	}
 
-	VALUE v = __rb_vm_ruby_dispatch(top, self, sel, cache->as.rcall.node,
+	VALUE v = ruby_dispatch(top, self, sel, cache->as.rcall.node,
 		opt, argc, argv);
 
 	// DTrace probe: method__return
@@ -967,153 +966,19 @@
 	}
     }
 
-    rb_vm_method_missing_reason_t status =
-	opt == DISPATCH_VCALL
-	    ? METHOD_MISSING_VCALL : opt == DISPATCH_SUPER
-		? METHOD_MISSING_SUPER : METHOD_MISSING_DEFAULT;
-    return method_missing((VALUE)self, sel, block, argc, argv, status);
-}
-
-static force_inline VALUE
-vm_call(RoxorVM *vm, VALUE top, VALUE self, Class klass, SEL sel,
-	rb_vm_block_t *block, unsigned char opt, int argc, const VALUE *argv)
-{
-    struct mcache *cache = mcache_get(vm, klass, sel, opt == DISPATCH_SUPER);
-    return vm_call_with_cache(vm, cache, top, self, klass, sel, block, opt,
-	    argc, argv);
-}
-
-static force_inline void
-__rb_vm_resolve_args(VALUE **pargv, size_t argv_size, int *pargc, va_list ar)
-{
-    // TODO we should only determine the real argc here (by taking into
-    // account the length splat arguments) and do the real unpacking of
-    // splat arguments in __rb_vm_rcall(). This way we can optimize more
-    // things (for ex. no need to unpack splats that are passed as a splat
-    // argument in the method being called!).
-    unsigned int i, argc = *pargc, real_argc = 0;
-    VALUE *argv = *pargv;
-    bool splat_arg_follows = false;
-    for (i = 0; i < argc; i++) {
-	VALUE arg = va_arg(ar, VALUE);
-	if (arg == SPLAT_ARG_FOLLOWS) {
-	    splat_arg_follows = true;
-	    i--;
-	}
-	else {
-	    if (splat_arg_follows) {
-		VALUE ary = rb_check_convert_type(arg, T_ARRAY, "Array",
-			"to_a");
-		if (NIL_P(ary)) {
-		    ary = rb_ary_new3(1, arg);
-		}
-		int count = RARRAY_LEN(ary);
-		if (real_argc + count >= argv_size) {
-		    const size_t new_argv_size = real_argc + count + 100;
-		    VALUE *new_argv = (VALUE *)xmalloc_ptrs(sizeof(VALUE)
-			    * new_argv_size);
-		    memcpy(new_argv, argv, sizeof(VALUE) * argv_size);
-		    argv = new_argv;
-		    argv_size = new_argv_size;
-		}
-		for (int j = 0; j < count; j++) {
-		    argv[real_argc++] = RARRAY_AT(ary, j);
-		}
-		splat_arg_follows = false;
-	    }
-	    else {
-		if (real_argc >= argv_size) {
-		    const size_t new_argv_size = real_argc + 100;
-		    VALUE *new_argv = (VALUE *)xmalloc_ptrs(sizeof(VALUE)
-			    * new_argv_size);
-		    memcpy(new_argv, argv, sizeof(VALUE) * argv_size);
-		    argv = new_argv;
-		    argv_size = new_argv_size;
-		}
-		argv[real_argc++] = arg;
-	    }
-	}
+    rb_vm_method_missing_reason_t status;
+    if (opt & DISPATCH_VCALL) {
+	status = METHOD_MISSING_VCALL;
     }
-
-    *pargv = argv;
-    *pargc = real_argc;
-}
-
-extern "C"
-VALUE
-rb_vm_dispatch(VALUE top, VALUE self, SEL sel, rb_vm_block_t *block,
-	unsigned char opt, int argc, ...)
-{
-    if (sel == 0) {
-	if (opt == DISPATCH_SUPER) {
-	    rb_raise(rb_eNoMethodError, "super called outside of method");
-	}
-	abort(); 
+    else if (opt & DISPATCH_SUPER) {
+	status = METHOD_MISSING_SUPER;
     }
-
-    VALUE base_argv[MAX_DISPATCH_ARGS];
-    VALUE *argv = base_argv;
-    if (argc > 0) {
-	va_list ar;
-	va_start(ar, argc);
-	__rb_vm_resolve_args(&argv, MAX_DISPATCH_ARGS, &argc, ar);
-	va_end(ar);
-
-	if (argc == 0) {
-	    const char *selname = sel_getName(sel);
-	    const size_t selnamelen = strlen(selname);
-	    if (selname[selnamelen - 1] == ':') {
-		// Because
-		//   def foo; end; foo(*[])
-		// creates foo but dispatches foo:.
-		char buf[100];
-		strncpy(buf, selname, sizeof buf);
-		buf[selnamelen - 1] = '\0';
-		sel = sel_registerName(buf);
-	    }
-	}
+    else {
+	status = METHOD_MISSING_DEFAULT;
     }
-
-    RoxorVM *vm = GET_VM();
-
-    struct Finally {
-	RoxorVM *vm;
-	Finally(RoxorVM *_vm) { vm = _vm; }
-	~Finally() { vm->pop_current_binding(); }
-    } finalizer(vm);
-
-    return vm_call(vm, top, self, (Class)CLASS_OF(self), sel, block,
-	    opt, argc, argv);
+    return method_missing((VALUE)self, sel, block, argc, argv, status);
 }
 
-extern "C"
-VALUE
-rb_vm_call(VALUE self, SEL sel, int argc, const VALUE *argv)
-{
-    return vm_call(GET_VM(), 0, self, (Class)CLASS_OF(self), sel, NULL,
-	    DISPATCH_FCALL, argc, argv);
-}
-
-extern "C"
-VALUE
-rb_vm_call_super(VALUE self, SEL sel, int argc, const VALUE *argv)
-{
-    return vm_call(GET_VM(), 0, self, (Class)CLASS_OF(self), sel, NULL,
-	    DISPATCH_SUPER, argc, argv);
-}
-
-extern "C"
-VALUE
-rb_vm_call2(rb_vm_block_t *block, VALUE self, VALUE klass, SEL sel, int argc,
-	const VALUE *argv)
-{
-    if (klass == 0) {
-	klass = CLASS_OF(self);
-    }
-    return vm_call(GET_VM(), 0, self, (Class)klass, sel, block,
-	    DISPATCH_FCALL, argc, argv);
-}
-
 static rb_vm_block_t *
 dup_block(rb_vm_block_t *src_b)
 {
@@ -1177,8 +1042,8 @@
 }
 
 static force_inline VALUE
-rb_vm_block_eval0(rb_vm_block_t *b, SEL sel, VALUE self, int argc,
-	const VALUE *argv)
+vm_block_eval(RoxorVM *vm, rb_vm_block_t *b, SEL sel, VALUE self,
+	int argc, const VALUE *argv)
 {
     if ((b->flags & VM_BLOCK_IFUNC) == VM_BLOCK_IFUNC) {
 	// Special case for blocks passed with rb_objc_block_call(), to
@@ -1258,7 +1123,6 @@
     }
     b->flags |= VM_BLOCK_ACTIVE;
 
-    RoxorVM *vm = GET_VM();
     Class old_current_class = vm->get_current_class();
     vm->set_current_class((Class)b->klass);
 
@@ -1279,7 +1143,7 @@
 
     if (b->flags & VM_BLOCK_METHOD) {
 	rb_vm_method_t *m = (rb_vm_method_t *)b->imp;
-	return vm_call_with_cache(vm, (struct mcache *)m->cache, 0, m->recv,
+	return rb_vm_dispatch(vm, (struct mcache *)m->cache, 0, m->recv,
 		(Class)m->oclass, m->sel, NULL, DISPATCH_FCALL, argc, argv);
     }
     return __rb_vm_bcall(self, sel, (VALUE)b->dvars, b, b->imp, b->arity,
@@ -1290,7 +1154,7 @@
 VALUE
 rb_vm_block_eval(rb_vm_block_t *b, int argc, const VALUE *argv)
 {
-    return rb_vm_block_eval0(b, NULL, b->self, argc, argv);
+    return vm_block_eval(GET_VM(), b, NULL, b->self, argc, argv);
 }
 
 extern "C"
@@ -1299,13 +1163,15 @@
 	const VALUE *argv)
 {
     // TODO check given arity and raise exception
-    return rb_vm_block_eval0(b, sel, self, argc, argv);
+    return vm_block_eval(GET_VM(), b, sel, self, argc, argv);
 }
 
-static force_inline VALUE
-rb_vm_yield0(int argc, const VALUE *argv)
+extern "C"
+VALUE
+rb_vm_yield_args(void *_vm, int argc, const VALUE *argv)
 {
-    RoxorVM *vm = GET_VM();
+    RoxorVM *vm = (RoxorVM *)_vm;
+
     rb_vm_block_t *b = vm->current_block();
     if (b == NULL) {
 	rb_raise(rb_eLocalJumpError, "no block given");
@@ -1336,18 +1202,11 @@
 	}
     } finalizer(vm, b);
 
-    return rb_vm_block_eval0(b, NULL, b->self, argc, argv);
+    return vm_block_eval(vm, b, NULL, b->self, argc, argv);
 }
 
 extern "C"
 VALUE
-rb_vm_yield(int argc, const VALUE *argv)
-{
-    return rb_vm_yield0(argc, argv);
-}
-
-extern "C"
-VALUE
 rb_vm_yield_under(VALUE klass, VALUE self, int argc, const VALUE *argv)
 {
     RoxorVM *vm = GET_VM();
@@ -1382,24 +1241,9 @@
 	}
     } finalizer(vm, b, old_class, old_self);
 
-    return rb_vm_block_eval0(b, NULL, b->self, argc, argv);
+    return vm_block_eval(vm, b, NULL, b->self, argc, argv);
 }
 
-extern "C"
-VALUE 
-rb_vm_yield_args(int argc, ...)
-{
-    VALUE base_argv[MAX_DISPATCH_ARGS];
-    VALUE *argv = &base_argv[0];
-    if (argc > 0) {
-	va_list ar;
-	va_start(ar, argc);
-	__rb_vm_resolve_args(&argv, MAX_DISPATCH_ARGS, &argc, ar);
-	va_end(ar);
-    }
-    return rb_vm_yield0(argc, argv);
-}
-
 force_inline rb_vm_block_t *
 RoxorVM::uncache_or_create_block(void *key, bool *cached, int dvars_size)
 {

Modified: MacRuby/trunk/error.c
===================================================================
--- MacRuby/trunk/error.c	2010-06-05 04:11:56 UTC (rev 4207)
+++ MacRuby/trunk/error.c	2010-06-05 04:14:46 UTC (rev 4208)
@@ -1095,7 +1095,7 @@
     rb_eConverterNotFoundError = rb_define_class_under(rb_cEncoding, "ConverterNotFoundError", rb_eEncodingError);
 
     syserr_tbl = st_init_numtable();
-    GC_ROOT(&syserr_tbl);
+    GC_RETAIN(syserr_tbl);
     rb_eSystemCallError = rb_define_class("SystemCallError", rb_eStandardError);
     rb_objc_define_method(rb_eSystemCallError, "initialize", syserr_initialize, -1);
     rb_objc_define_method(rb_eSystemCallError, "errno", syserr_errno, 0);

Modified: MacRuby/trunk/ext/openssl/extconf.rb
===================================================================
--- MacRuby/trunk/ext/openssl/extconf.rb	2010-06-05 04:11:56 UTC (rev 4207)
+++ MacRuby/trunk/ext/openssl/extconf.rb	2010-06-05 04:14:46 UTC (rev 4208)
@@ -124,6 +124,8 @@
 
 message "=== Checking done. ===\n"
 
+$INCFLAGS << ' -I../..'
+
 create_header
 create_makefile("openssl")
 message "Done.\n"

Modified: MacRuby/trunk/ext/openssl/ossl_ssl.c
===================================================================
--- MacRuby/trunk/ext/openssl/ossl_ssl.c	2010-06-05 04:11:56 UTC (rev 4207)
+++ MacRuby/trunk/ext/openssl/ossl_ssl.c	2010-06-05 04:14:46 UTC (rev 4208)
@@ -12,6 +12,10 @@
  */
 #include "ossl.h"
 
+// for rb_vm_call_super()
+#include "ruby/node.h"
+#include "vm.h"
+
 #if defined(HAVE_UNISTD_H)
 #  include <unistd.h> /* for read(), and write() */
 #endif

Modified: MacRuby/trunk/gc.c
===================================================================
--- MacRuby/trunk/gc.c	2010-06-05 04:11:56 UTC (rev 4207)
+++ MacRuby/trunk/gc.c	2010-06-05 04:14:46 UTC (rev 4208)
@@ -45,12 +45,6 @@
 static bool dont_gc = false;
 
 void
-rb_global_variable(VALUE *var)
-{
-    rb_gc_register_address(var);
-}
-
-void
 rb_memerror(void)
 {
     rb_exc_raise(nomem_error);
@@ -289,12 +283,6 @@
 }
 
 void
-rb_gc_register_address(VALUE *addr)
-{
-    rb_objc_root(addr);
-}
-
-void
 rb_register_mark_object(VALUE obj)
 {
     GC_RETAIN(obj);
@@ -1061,8 +1049,8 @@
 
     rb_objc_define_module_function(rb_mObSpace, "_id2ref", id2ref, 1);
 
-    rb_global_variable(&nomem_error);
     nomem_error = rb_exc_new2(rb_eNoMemError, "failed to allocate memory");
+    GC_RETAIN(nomem_error);
 
     rb_objc_define_method(rb_mKernel, "__id__", rb_obj_id, 0);
     rb_objc_define_method(rb_mKernel, "object_id", rb_obj_id, 0);

Modified: MacRuby/trunk/include/ruby/ruby.h
===================================================================
--- MacRuby/trunk/include/ruby/ruby.h	2010-06-05 04:11:56 UTC (rev 4207)
+++ MacRuby/trunk/include/ruby/ruby.h	2010-06-05 04:14:46 UTC (rev 4208)
@@ -802,8 +802,6 @@
 VALUE rb_funcall2(VALUE, ID, int, const VALUE*);
 VALUE rb_funcall3(VALUE, ID, int, const VALUE*);
 int rb_scan_args(int, const VALUE*, const char*, ...);
-VALUE rb_vm_call(VALUE self, SEL sel, int argc, const VALUE *args);
-VALUE rb_vm_call_super(VALUE self, SEL sel, int argc, const VALUE *args);
 
 VALUE rb_gv_set(const char*, VALUE);
 VALUE rb_gv_get(const char*);
@@ -841,25 +839,7 @@
 
 VALUE rb_each(VALUE);
 
-VALUE rb_vm_yield(int argc, const VALUE *argv);
-
-static inline VALUE
-rb_yield(VALUE val)
-{
-    if (val == Qundef) {
-	return rb_vm_yield(0, 0);
-    }
-    else {
-	return rb_vm_yield(1, &val);
-    }
-}
-
-static inline VALUE
-rb_yield_values2(int argc, const VALUE *argv)
-{
-    return rb_vm_yield(argc, argv);
-}
-
+VALUE rb_yield(VALUE val);
 VALUE rb_yield_values(int n, ...);
 VALUE rb_yield_values2(int n, const VALUE *argv);
 VALUE rb_yield_splat(VALUE);
@@ -1088,15 +1068,6 @@
     } \
     while (0)
 
-static inline void
-rb_objc_root(void *addr)
-{
-    if (addr != NULL) {
-	auto_zone_add_root(__auto_zone, addr, *(void **)addr);
-    }
-}
-#define GC_ROOT(addr) (rb_objc_root((void *)addr))
-
 static inline void *
 rb_objc_retain(void *addr)
 {

Modified: MacRuby/trunk/io.c
===================================================================
--- MacRuby/trunk/io.c	2010-06-05 04:11:56 UTC (rev 4207)
+++ MacRuby/trunk/io.c	2010-06-05 04:14:46 UTC (rev 4208)
@@ -4536,12 +4536,15 @@
     }
 }
 
-
 static void
 stdout_setter(VALUE val, ID id, VALUE *variable)
 {
     must_respond_to(id_write, val, id);
-    *variable = val;
+    if (*variable != val) {
+	GC_RELEASE(*variable);
+	*variable = val;
+	GC_RETAIN(*variable);
+    }
 }
 
 void
@@ -4602,9 +4605,9 @@
     rb_output_fs = Qnil;
     rb_define_hooked_variable("$,", &rb_output_fs, 0, rb_str_setter);
 
-    rb_global_variable(&rb_default_rs);
     rb_rs = rb_default_rs = rb_str_new2("\n");
-    rb_objc_retain((void *)rb_rs);
+    GC_RETAIN(rb_default_rs);
+    GC_RETAIN(rb_rs);
     rb_output_rs = Qnil;
     OBJ_FREEZE(rb_default_rs);	/* avoid modifying RS_default */
     rb_define_hooked_variable("$/", &rb_rs, 0, rb_str_setter);

Modified: MacRuby/trunk/kernel.c
===================================================================
--- MacRuby/trunk/kernel.c	2010-06-05 04:11:56 UTC (rev 4207)
+++ MacRuby/trunk/kernel.c	2010-06-05 04:14:46 UTC (rev 4208)
@@ -166,9 +166,129 @@
     rb_const_set(outer, id, obj);
 }
 
-VALUE rb_vm_dispatch(VALUE top, VALUE self, void *sel, void *block,
-	unsigned char opt, int argc, ...);
+static void __attribute__((noinline))
+vm_resolve_args(VALUE **pargv, size_t argv_size, int *pargc, VALUE *args)
+{
+    unsigned int i, argc = *pargc, real_argc = 0, j = 0;
+    VALUE *argv = *pargv;
+    bool splat_arg_follows = false;
+    for (i = 0; i < argc; i++) {
+	VALUE arg = args[j++];
+	if (arg == SPLAT_ARG_FOLLOWS) {
+	    splat_arg_follows = true;
+	    i--;
+	}
+	else {
+	    if (splat_arg_follows) {
+		VALUE ary = rb_check_convert_type(arg, T_ARRAY, "Array",
+			"to_a");
+		if (NIL_P(ary)) {
+		    ary = rb_ary_new3(1, arg);
+		}
+		int count = RARRAY_LEN(ary);
+		if (real_argc + count >= argv_size) {
+		    const size_t new_argv_size = real_argc + count + 100;
+		    VALUE *new_argv = (VALUE *)xmalloc_ptrs(sizeof(VALUE)
+			    * new_argv_size);
+		    memcpy(new_argv, argv, sizeof(VALUE) * argv_size);
+		    argv = new_argv;
+		    argv_size = new_argv_size;
+		}
+		int j;
+		for (j = 0; j < count; j++) {
+		    argv[real_argc++] = RARRAY_AT(ary, j);
+		}
+		splat_arg_follows = false;
+	    }
+	    else {
+		if (real_argc >= argv_size) {
+		    const size_t new_argv_size = real_argc + 100;
+		    VALUE *new_argv = (VALUE *)xmalloc_ptrs(sizeof(VALUE)
+			    * new_argv_size);
+		    memcpy(new_argv, argv, sizeof(VALUE) * argv_size);
+		    argv = new_argv;
+		    argv_size = new_argv_size;
+		}
+		argv[real_argc++] = arg;
+	    }
+	}
+    }
+    *pargv = argv;
+    *pargc = real_argc;
+}
 
+static inline VALUE
+vm_class_of(VALUE obj)
+{
+    // TODO: separate the const bits of CLASS_OF to make sure they will get
+    // reduced by the optimizer.
+    return CLASS_OF(obj);
+}
+
+inline VALUE
+vm_dispatch(VALUE top, VALUE self, void *sel, void *block, unsigned char opt,
+	int argc, VALUE *argv)
+{
+    if (opt & DISPATCH_SUPER) {
+	if (sel == 0) {
+	    rb_raise(rb_eNoMethodError, "super called outside of method");
+	}
+    }
+
+    VALUE buf[100];
+    if (opt & DISPATCH_SPLAT) {
+	if (argc == 1 && !SPECIAL_CONST_P(argv[1])
+		&& *(VALUE *)argv[1] == rb_cRubyArray) {
+	    argc = RARY(argv[1])->len;
+	    argv = rary_ptr(argv[1]);
+	}
+	else {
+	    VALUE *new_argv = buf;
+	    vm_resolve_args(&new_argv, 100, &argc, argv);
+	    argv = new_argv;
+	}
+	if (argc == 0) {
+	    const char *selname = sel_getName(sel);
+	    const size_t selnamelen = strlen(selname);
+	    if (selname[selnamelen - 1] == ':') {
+		// Because
+		//   def foo; end; foo(*[])
+		// creates foo but dispatches foo:.
+		char buf[100];
+		strncpy(buf, selname, sizeof buf);
+		buf[selnamelen - 1] = '\0';
+		sel = sel_registerName(buf);
+	    }
+	}
+    }
+
+    void *vm = rb_vm_current_vm();
+    VALUE klass = vm_class_of(self);
+    return rb_vm_call0(vm, top, self, (Class)klass, (SEL)sel,
+	    (rb_vm_block_t *)block, opt, argc, argv);
+}
+
+inline VALUE
+vm_yield_args(int argc, unsigned char opt, VALUE *argv)
+{
+    VALUE buf[100];
+    if (opt & DISPATCH_SPLAT) {
+	if (argc == 1 && !SPECIAL_CONST_P(argv[1])
+		&& *(VALUE *)argv[1] == rb_cRubyArray) {
+	    argc = RARY(argv[1])->len;
+	    argv = rary_ptr(argv[1]);
+	}
+	else {
+	    VALUE *new_argv = buf;
+	    vm_resolve_args(&new_argv, 100, &argc, argv);
+	    argv = new_argv;
+	}
+    }
+
+    void *vm = rb_vm_current_vm();
+    return rb_vm_yield_args(vm, argc, argv);
+}
+
 // Only numeric immediates have their lsb at 1.
 #define NUMERIC_IMM_P(x) ((x & 0x1) == 0x1)
 
@@ -189,7 +309,7 @@
 	    return DBL2FIXFLOAT(res);
 	}
     }
-    return rb_vm_dispatch(0, left, selPLUS, NULL, 0, 1, right);
+    return vm_dispatch(0, left, selPLUS, NULL, 0, 1, &right);
 }
 
 inline VALUE
@@ -207,7 +327,7 @@
 	    return DBL2FIXFLOAT(res);
 	}
     }
-    return rb_vm_dispatch(0, left, selMINUS, NULL, 0, 1, right);
+    return vm_dispatch(0, left, selMINUS, NULL, 0, 1, &right);
 }
 
 inline VALUE
@@ -225,7 +345,7 @@
 	    return DBL2FIXFLOAT(res);
 	}
     }
-    return rb_vm_dispatch(0, left, selMULT, NULL, 0, 1, right);
+    return vm_dispatch(0, left, selMULT, NULL, 0, 1, &right);
 }
 
 inline VALUE
@@ -251,7 +371,7 @@
 	    return DBL2FIXFLOAT(res);
 	}
     }
-    return rb_vm_dispatch(0, left, selDIV, NULL, 0, 1, right);
+    return vm_dispatch(0, left, selDIV, NULL, 0, 1, &right);
 }
 
 inline VALUE
@@ -265,7 +385,7 @@
 	    return IMM2DBL(left) < IMM2DBL(right) ? Qtrue : Qfalse;
 	}
     }
-    return rb_vm_dispatch(0, left, selLT, NULL, 0, 1, right);
+    return vm_dispatch(0, left, selLT, NULL, 0, 1, &right);
 }
 
 inline VALUE
@@ -279,7 +399,7 @@
 	    return IMM2DBL(left) <= IMM2DBL(right) ? Qtrue : Qfalse;
 	}
     }
-    return rb_vm_dispatch(0, left, selLE, NULL, 0, 1, right);
+    return vm_dispatch(0, left, selLE, NULL, 0, 1, &right);
 }
 
 inline VALUE
@@ -293,7 +413,7 @@
 	    return IMM2DBL(left) > IMM2DBL(right) ? Qtrue : Qfalse;
 	}
     }
-    return rb_vm_dispatch(0, left, selGT, NULL, 0, 1, right);
+    return vm_dispatch(0, left, selGT, NULL, 0, 1, &right);
 }
 
 inline VALUE
@@ -307,7 +427,7 @@
 	    return IMM2DBL(left) >= IMM2DBL(right) ? Qtrue : Qfalse;
 	}
     }
-    return rb_vm_dispatch(0, left, selGE, NULL, 0, 1, right);
+    return vm_dispatch(0, left, selGE, NULL, 0, 1, &right);
 }
 
 inline VALUE
@@ -327,7 +447,7 @@
 	}
 	// TODO: opt for non-immediate types
     }
-    return rb_vm_dispatch(0, left, selEq, NULL, 0, 1, right);
+    return vm_dispatch(0, left, selEq, NULL, 0, 1, &right);
 }
 
 inline VALUE
@@ -347,7 +467,7 @@
 	}
 	// TODO: opt for non-immediate types
     }
-    return rb_vm_dispatch(0, left, selEqq, NULL, 0, 1, right);
+    return vm_dispatch(0, left, selEqq, NULL, 0, 1, &right);
 }
 
 inline VALUE
@@ -367,7 +487,7 @@
 	}
 	// TODO: opt for non-immediate types
     }
-    return rb_vm_dispatch(0, left, selNeq, NULL, 0, 1, right);
+    return vm_dispatch(0, left, selNeq, NULL, 0, 1, &right);
 }
 
 inline VALUE
@@ -384,7 +504,7 @@
 	    return rhash_aref(obj, 0, other);
 	}
     }
-    return rb_vm_dispatch(0, obj, selAREF, NULL, 0, 1, other);
+    return vm_dispatch(0, obj, selAREF, NULL, 0, 1, &other);
 }
 
 inline VALUE
@@ -402,7 +522,8 @@
 	    return rhash_aset(obj, 0, other1, other2);
 	}
     }
-    return rb_vm_dispatch(0, obj, selASET, NULL, 0, 2, other1, other2);
+    VALUE args[] = {other1, other2};
+    return vm_dispatch(0, obj, selASET, NULL, 0, 2, args);
 }
 
 inline VALUE
@@ -419,7 +540,7 @@
 	    return rstr_concat(obj, 0, other);
 	}
     }
-    return rb_vm_dispatch(0, obj, selLTLT, NULL, 0, 1, other);
+    return vm_dispatch(0, obj, selLTLT, NULL, 0, 1, &other);
 }
 
 inline VALUE

Modified: MacRuby/trunk/object.c
===================================================================
--- MacRuby/trunk/object.c	2010-06-05 04:11:56 UTC (rev 4207)
+++ MacRuby/trunk/object.c	2010-06-05 04:14:46 UTC (rev 4208)
@@ -1077,7 +1077,7 @@
 immediate:
 	    if (!immediate_frozen_tbl) {
 		immediate_frozen_tbl = st_init_numtable();
-		GC_ROOT(&immediate_frozen_tbl);
+		GC_RETAIN(immediate_frozen_tbl);
 	    }
 	    st_insert(immediate_frozen_tbl, obj, (st_data_t)Qtrue);
 	}

Modified: MacRuby/trunk/perf/perf_method.rb
===================================================================
--- MacRuby/trunk/perf/perf_method.rb	2010-06-05 04:11:56 UTC (rev 4207)
+++ MacRuby/trunk/perf/perf_method.rb	2010-06-05 04:14:46 UTC (rev 4208)
@@ -56,7 +56,7 @@
   end
 end
 
-perf_test('splat') do
+perf_test('msplat') do
   o = TestMethod.new
   i = 0
   while i < 200000
@@ -73,6 +73,19 @@
   end
 end
 
+perf_test('dsplat') do
+  o = TestMethod.new
+  i = 0
+  a = [1,2,3,4,5,6]
+  while i < 1000000
+    o.args_method(*a); o.args_method(*a); o.args_method(*a)
+    o.args_method(*a); o.args_method(*a); o.args_method(*a)
+    o.args_method(*a); o.args_method(*a); o.args_method(*a)
+    o.args_method(*a); o.args_method(*a); o.args_method(*a)
+    i += 1
+  end
+end
+
 perf_test('opt') do
   o = TestMethod.new
   i = 0

Modified: MacRuby/trunk/rakelib/builder/options.rb
===================================================================
--- MacRuby/trunk/rakelib/builder/options.rb	2010-06-05 04:11:56 UTC (rev 4207)
+++ MacRuby/trunk/rakelib/builder/options.rb	2010-06-05 04:14:46 UTC (rev 4208)
@@ -121,7 +121,7 @@
 EXPORTED_SYMBOLS_LIST = "./exported_symbols_list"
 
 OPTZFLAG = "-O#{OPTZ_LEVEL}"
-CFLAGS = "-I. -I./include -I/usr/include/libxml2 #{ARCHFLAGS} -fno-common -pipe -g -Wall -fexceptions #{OPTZFLAG}"
+CFLAGS = "-I. -I./include #{ARCHFLAGS} -fno-common -pipe -g -Wall -fexceptions #{OPTZFLAG}"
 CFLAGS << " -Wno-deprecated-declarations -Werror" if NO_WARN_BUILD
 OBJC_CFLAGS = CFLAGS + " -fobjc-gc-only"
 CXXFLAGS = `#{LLVM_CONFIG} --cxxflags #{LLVM_MODULES}`.sub(/-DNDEBUG/, '').sub(/-fno-exceptions/, '').strip
@@ -148,8 +148,8 @@
 end
 
 OBJS_CFLAGS = {
-  # Make sure everything gets inlined properly + compile as Objective-C++.
-  'dispatcher' => '--param inline-unit-growth=10000 --param large-function-growth=10000 -x objective-c++',
+  'dispatcher' => '-x objective-c++', # compile as Objective-C++.
+  'bs' => '-I/usr/include/libxml2'    # need to access libxml2
 }
 
 # We monkey-patch the method that Rake uses to display the tasks so we can add

Modified: MacRuby/trunk/rakelib/builder.rake
===================================================================
--- MacRuby/trunk/rakelib/builder.rake	2010-06-05 04:11:56 UTC (rev 4207)
+++ MacRuby/trunk/rakelib/builder.rake	2010-06-05 04:14:46 UTC (rev 4208)
@@ -43,7 +43,7 @@
     ARCHS.each do |x| 
       output = "kernel-#{x}.bc"
       # Compile the IR for the kernel.c source file & optimize it.
-      sh "#{llvm_gcc} -arch #{x} -fexceptions #{includes} --emit-llvm -c kernel.c -o #{output}"
+      sh "#{llvm_gcc} -arch #{x} -fexceptions -fno-stack-protector #{includes} --emit-llvm -c kernel.c -o #{output}"
       sh "#{opt} -O3 #{output} -o=#{output}"
       # Convert the bitcode into a C static array. We append a null byte to the bitcode file because
       # xxd doesn't, and it's needed by the bitcode reader later at runtime.

Modified: MacRuby/trunk/rational.c
===================================================================
--- MacRuby/trunk/rational.c	2010-06-05 04:11:56 UTC (rev 4207)
+++ MacRuby/trunk/rational.c	2010-06-05 04:14:46 UTC (rev 4208)
@@ -6,6 +6,9 @@
 */
 
 #include "ruby.h"
+#include "ruby/node.h"
+#include "vm.h"
+
 #include <math.h>
 #include <float.h>
 
@@ -1979,25 +1982,20 @@
     if (rat_pat) return;
 
     rat_pat = rb_reg_new(rat_pat_source, sizeof rat_pat_source - 1, 0);
-    rb_global_variable(&rat_pat);
-//    rb_gc_register_mark_object(rat_pat);
+    GC_RETAIN(rat_pat);
 
     an_e_pat = rb_reg_new(an_e_pat_source, sizeof an_e_pat_source - 1, 0);
-    rb_global_variable(&an_e_pat);
-//    rb_gc_register_mark_object(an_e_pat);
+    GC_RETAIN(an_e_pat);
 
     a_dot_pat = rb_reg_new(a_dot_pat_source, sizeof a_dot_pat_source - 1, 0);
-    rb_global_variable(&a_dot_pat);
-//    rb_gc_register_mark_object(a_dot_pat);
+    GC_RETAIN(a_dot_pat);
 
     underscores_pat = rb_reg_new(underscores_pat_source,
-				 sizeof underscores_pat_source - 1, 0);
-    rb_global_variable(&underscores_pat);
-//    rb_gc_register_mark_object(underscores_pat);
+	    sizeof underscores_pat_source - 1, 0);
+    GC_RETAIN(underscores_pat);
 
     an_underscore = rb_usascii_str_new2("_");
-    rb_global_variable(&an_underscore);
-//    rb_gc_register_mark_object(an_underscore);
+    GC_RETAIN(an_underscore);
 }
 
 #define id_match rb_intern("match")

Modified: MacRuby/trunk/ruby.c
===================================================================
--- MacRuby/trunk/ruby.c	2010-06-05 04:11:56 UTC (rev 4207)
+++ MacRuby/trunk/ruby.c	2010-06-05 04:14:46 UTC (rev 4208)
@@ -1356,7 +1356,6 @@
     rb_define_hooked_variable("$PROGRAM_NAME", &rb_progname, 0, set_arg0);
 
     rb_define_global_const("ARGV", rb_argv);
-    rb_global_variable(&rb_argv0);
 
     rb_vm_set_running(true);
 }
@@ -1410,6 +1409,7 @@
     MEMZERO(opt, opt, 1);
     ruby_script(argv[0]);	/* for the time being */
     rb_argv0 = rb_progname;
+    GC_RETAIN(rb_argv0);
     args->argc = argc;
     args->argv = argv;
     args->opt = opt;

Modified: MacRuby/trunk/string.c
===================================================================
--- MacRuby/trunk/string.c	2010-06-05 04:11:56 UTC (rev 4207)
+++ MacRuby/trunk/string.c	2010-06-05 04:14:46 UTC (rev 4208)
@@ -6216,7 +6216,11 @@
     if (!NIL_P(val) && TYPE(val) != T_STRING) {
 	rb_raise(rb_eTypeError, "value of %s must be String", rb_id2name(id));
     }
-    *var = val;
+    if (*var != val) {
+	GC_RELEASE(*var);
+	*var = val;
+	GC_RETAIN(*var);
+    }
 }
 
 ID

Modified: MacRuby/trunk/variable.c
===================================================================
--- MacRuby/trunk/variable.c	2010-06-05 04:11:56 UTC (rev 4207)
+++ MacRuby/trunk/variable.c	2010-06-05 04:14:46 UTC (rev 4208)
@@ -536,10 +536,6 @@
     gvar->getter = getter != NULL ? getter : var_getter;
     gvar->setter = setter != NULL ? setter : var_setter;
     gvar->marker = var_marker;
-
-    if (var != NULL) {
-	GC_ROOT(var);
-    }
 }
 
 void

Modified: MacRuby/trunk/vm.cpp
===================================================================
--- MacRuby/trunk/vm.cpp	2010-06-05 04:11:56 UTC (rev 4207)
+++ MacRuby/trunk/vm.cpp	2010-06-05 04:14:46 UTC (rev 4208)
@@ -302,7 +302,7 @@
 {
     running = false;
     abort_on_exception = false;
-    inlining_enabled = getenv("VM_DISABLE_INLINING") == NULL;
+    inlining_enabled = false; //XXX getenv("VM_DISABLE_INLINING") == NULL;
 
     pthread_assert(pthread_mutex_init(&gl, 0));
 
@@ -539,6 +539,16 @@
     fpm->run(*func);
 }
 
+extern "C"
+void
+rb_verify_module(void)
+{
+    if (verifyModule(*RoxorCompiler::module, PrintMessageAction)) {
+	printf("Error during module verification\n");
+	abort();
+    }
+}
+
 IMP
 RoxorCore::compile(Function *func, bool run_optimize)
 {
@@ -551,10 +561,7 @@
     // in AOT mode, the verifier is already called
     // (and calling it here would check functions not fully compiled yet)
     if (!ruby_aot_compile) {
-	if (verifyModule(*RoxorCompiler::module, PrintMessageAction)) {
-	    printf("Error during module verification\n");
-	    abort();
-	}
+	rb_verify_module();
     }
 
     uint64_t start = mach_absolute_time();
@@ -2507,16 +2514,18 @@
     ruby_methods.erase(iter);
 #endif
 
-    ID mid = sanitize_mid(sel);
-    if (mid != 0) {
-	VALUE sym = ID2SYM(mid);
-	if (RCLASS_SINGLETON(klass)) {
-	    VALUE sk = rb_iv_get((VALUE)klass, "__attached__");
-	    rb_vm_call(sk, selSingletonMethodUndefined, 1, &sym);
+    if (get_running()) {
+	ID mid = sanitize_mid(sel);
+	if (mid != 0) {
+	    VALUE sym = ID2SYM(mid);
+	    if (RCLASS_SINGLETON(klass)) {
+		VALUE sk = rb_iv_get((VALUE)klass, "__attached__");
+		rb_vm_call(sk, selSingletonMethodUndefined, 1, &sym);
+	    }
+	    else {
+		rb_vm_call((VALUE)klass, selMethodUndefined, 1, &sym);
+	    }
 	}
-	else {
-	    rb_vm_call((VALUE)klass, selMethodUndefined, 1, &sym);
-	}
     }
 }
 
@@ -2966,14 +2975,14 @@
 void
 rb_vm_add_binding(rb_vm_binding_t *binding)
 {
-    GET_VM()->push_current_binding(binding, false);
+    GET_VM()->push_current_binding(binding);
 }
 
 extern "C"
 void
 rb_vm_pop_binding(void)
 {
-    GET_VM()->pop_current_binding(false);
+    GET_VM()->pop_current_binding();
 }
 
 // Should be used inside a method implementation.
@@ -3638,7 +3647,7 @@
 
     // Compile IR.
     if (binding != NULL) {
-	vm->push_current_binding(binding, false);
+	vm->push_current_binding(binding);
     }
     bool old_inside_eval = compiler->is_inside_eval();
     compiler->set_inside_eval(inside_eval);
@@ -3647,7 +3656,7 @@
     compiler->set_fname(NULL);
     compiler->set_inside_eval(old_inside_eval);
     if (binding != NULL) {
-	vm->pop_current_binding(false);
+	vm->pop_current_binding();
     }
 
     // Optimize & compile the function.
@@ -3733,10 +3742,7 @@
     f->setName(RSTRING_PTR(ruby_aot_init_func));
 
     // Force a module verification.
-    if (verifyModule(*RoxorCompiler::module, PrintMessageAction)) {
-	printf("Error during module verification\n");
-	abort();
-    }
+    rb_verify_module();
 
     // Optimize the IR.
     GET_CORE()->optimize(f);
@@ -4119,6 +4125,20 @@
     return (void *)new RoxorVM(*GET_VM());
 }
 
+extern "C"
+void *
+rb_vm_current_vm(void)
+{
+    return (void *)GET_VM();
+}
+
+extern "C"
+struct mcache *
+rb_vm_get_mcache(void *vm)
+{
+    return ((RoxorVM *)vm)->get_mcache();
+} 
+
 void
 RoxorCore::register_thread(VALUE thread)
 {
@@ -4854,10 +4874,7 @@
 
 
     if (getenv("VM_VERIFY_IR") != NULL) {
-	if (verifyModule(*RoxorCompiler::module, PrintMessageAction)) {
-	    printf("Error during module verification\n");
-	    abort();
-	}
+	rb_verify_module();
 	printf("IR verified!\n");
     }
 

Modified: MacRuby/trunk/vm.h
===================================================================
--- MacRuby/trunk/vm.h	2010-06-05 04:11:56 UTC (rev 4207)
+++ MacRuby/trunk/vm.h	2010-06-05 04:14:46 UTC (rev 4208)
@@ -317,11 +317,6 @@
 void rb_vm_alias(VALUE klass, ID name, ID def);
 bool rb_vm_copy_method(Class klass, Method method);
 void rb_vm_copy_methods(Class from_class, Class to_class);
-VALUE rb_vm_call(VALUE self, SEL sel, int argc, const VALUE *args);
-VALUE rb_vm_call2(rb_vm_block_t *block, VALUE self, VALUE klass, SEL sel,
-	int argc, const VALUE *argv);
-VALUE rb_vm_call_super(VALUE self, SEL sel, int argc, const VALUE *args);
-VALUE rb_vm_yield(int argc, const VALUE *argv);
 VALUE rb_vm_yield_under(VALUE klass, VALUE self, int argc, const VALUE *argv);
 bool rb_vm_respond_to(VALUE obj, SEL sel, bool priv);
 bool rb_vm_respond_to2(VALUE obj, VALUE klass, SEL sel, bool priv, bool check_override);
@@ -527,6 +522,7 @@
 typedef VALUE rb_vm_c_stub_t(IMP imp, int argc, const VALUE *argv);
 
 #include "bridgesupport.h"
+#include "compiler.h"
 
 struct mcache {
 #define MCACHE_RCALL 0x1 // Ruby call
@@ -555,6 +551,66 @@
 
 #define VM_MCACHE_SIZE	0x1000
 
+VALUE rb_vm_dispatch(void *_vm, struct mcache *cache, VALUE top, VALUE self,
+	Class klass, SEL sel, rb_vm_block_t *block, unsigned char opt,
+	int argc, const VALUE *argv);
+
+void *rb_vm_current_vm(void) __attribute__((const));
+struct mcache *rb_vm_get_mcache(void *vm) __attribute__((const));
+
+static inline int
+rb_vm_mcache_hash(Class klass, SEL sel)
+{
+    return (((unsigned long)klass >> 3) ^ (unsigned long)sel)
+	& (VM_MCACHE_SIZE - 1);
+}
+
+static inline VALUE
+rb_vm_call0(void *vm, VALUE top, VALUE self, Class klass, SEL sel,
+	rb_vm_block_t *block, unsigned char opt, int argc, const VALUE *argv)
+{
+    int hash = rb_vm_mcache_hash(klass, sel);
+    if (opt & DISPATCH_SUPER) {
+	hash++;
+    }
+    struct mcache *cache = &rb_vm_get_mcache(vm)[hash];
+    return rb_vm_dispatch(vm, cache, top, self, klass, sel, block, opt,
+	    argc, argv);
+}
+
+static inline VALUE
+rb_vm_call(VALUE self, SEL sel, int argc, const VALUE *argv)
+{
+    return rb_vm_call0(rb_vm_current_vm(), 0, self, (Class)CLASS_OF(self), sel,
+	    NULL, DISPATCH_FCALL, argc, argv);
+}
+
+static inline VALUE
+rb_vm_call_super(VALUE self, SEL sel, int argc, const VALUE *argv)
+{
+    return rb_vm_call0(rb_vm_current_vm(), 0, self, (Class)CLASS_OF(self), sel,
+	    NULL, DISPATCH_SUPER, argc, argv);
+}
+
+static inline VALUE
+rb_vm_call2(rb_vm_block_t *block, VALUE self, VALUE klass, SEL sel, int argc,
+	const VALUE *argv)
+{
+    if (klass == 0) {
+	klass = CLASS_OF(self);
+    }
+    return rb_vm_call0(rb_vm_current_vm(), 0, self, (Class)klass, sel, block,
+	    DISPATCH_FCALL, argc, argv);
+}
+
+VALUE rb_vm_yield_args(void *vm, int argc, const VALUE *argv);
+
+static inline VALUE
+rb_vm_yield(int argc, const VALUE *argv)
+{
+    return rb_vm_yield_args(rb_vm_current_vm(), argc, argv);
+}
+
 #if defined(__cplusplus)
 }
 
@@ -981,18 +1037,14 @@
 	    return NULL;
 	}
 
-	void push_current_binding(rb_vm_binding_t *binding, bool retain=true) {
-	    if (retain) {
-		rb_objc_retain(binding);
-	    }
+	void push_current_binding(rb_vm_binding_t *binding) {
+	    GC_RETAIN(binding);
 	    bindings.push_back(binding);
 	}
 
-	void pop_current_binding(bool release=true) {
+	void pop_current_binding() {
 	    if (!bindings.empty()) {
-		if (release) {
-		    rb_objc_release(bindings.back());
-		}
+		GC_RELEASE(bindings.back());
 		bindings.pop_back();
 	    }
 	}

Modified: MacRuby/trunk/vm_eval.c
===================================================================
--- MacRuby/trunk/vm_eval.c	2010-06-05 04:11:56 UTC (rev 4207)
+++ MacRuby/trunk/vm_eval.c	2010-06-05 04:14:46 UTC (rev 4208)
@@ -188,6 +188,21 @@
 /* yield */
 
 VALUE
+rb_yield(VALUE val)
+{
+    if (val == Qundef) {
+        return rb_vm_yield(0, NULL);
+    }
+    return rb_vm_yield(1, &val);
+}
+
+VALUE
+rb_yield_values2(int argc, const VALUE *argv)
+{
+    return rb_vm_yield(argc, argv);
+}
+
+VALUE
 rb_yield_values(int n, ...)
 {
     if (n == 0) {
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macruby-changes/attachments/20100604/ea171372/attachment-0001.html>


More information about the macruby-changes mailing list