[macruby-changes] [3199] MacRuby/trunk

source_changes at macosforge.org source_changes at macosforge.org
Wed Jan 6 21:18:40 PST 2010


Revision: 3199
          http://trac.macosforge.org/projects/ruby/changeset/3199
Author:   lsansonetti at apple.com
Date:     2010-01-06 21:18:37 -0800 (Wed, 06 Jan 2010)
Log Message:
-----------
fixed a bunch of super-dispatch bugs

Modified Paths:
--------------
    MacRuby/trunk/compiler.cpp
    MacRuby/trunk/compiler.h
    MacRuby/trunk/dispatcher.cpp

Modified: MacRuby/trunk/compiler.cpp
===================================================================
--- MacRuby/trunk/compiler.cpp	2010-01-07 00:31:58 UTC (rev 3198)
+++ MacRuby/trunk/compiler.cpp	2010-01-07 05:18:37 UTC (rev 3199)
@@ -66,6 +66,7 @@
     return_from_block = -1;
     return_from_block_ids = 0;
     ensure_pn = NULL;
+    block_declaration = false;
 
     dispatcherFunc = NULL;
     fastPlusFunc = NULL;
@@ -664,7 +665,8 @@
 
 void
 RoxorCompiler::compile_prepare_method(Value *classVal, Value *sel,
-	bool singleton, Function *new_function, rb_vm_arity_t &arity, NODE *body)
+	bool singleton, Function *new_function, rb_vm_arity_t &arity,
+	NODE *body)
 {
     if (prepareMethodFunc == NULL) {
 	// void rb_vm_prepare_method(Class klass, unsigned char dynamic_class,
@@ -693,7 +695,8 @@
 
 void
 RoxorAOTCompiler::compile_prepare_method(Value *classVal, Value *sel,
-	bool singleton, Function *new_function, rb_vm_arity_t &arity, NODE *body)
+	bool singleton, Function *new_function, rb_vm_arity_t &arity,
+	NODE *body)
 {
     if (prepareMethodFunc == NULL) {
 	// void rb_vm_prepare_method2(Class klass, unsigned char dynamic_class,
@@ -1704,7 +1707,7 @@
 	&& current_loop_body_bb != NULL
 	&& current_loop_end_bb != NULL;
 
-    const bool within_block = current_block && current_mid == 0;
+    const bool within_block = block_declaration;
 
     Value *val = nd_type(node) == NODE_RETRY
 	? nilVal
@@ -3058,8 +3061,7 @@
 	    {
 		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 && !class_declaration;
-		class_declaration = false;
+		const bool has_dvars = block_declaration;
 
 		// Get dynamic vars.
 		if (has_dvars && node->nd_tbl != NULL) {
@@ -3998,14 +4000,18 @@
 
 			compile_set_current_scope(classVal, publicScope);
 
+			bool old_block_declaration = block_declaration;
+			block_declaration = false;
+
 			DEBUG_LEVEL_INC();
-			class_declaration = true;
 			Value *val = compile_node(body);
 			assert(Function::classof(val));
 			Function *f = cast<Function>(val);
 			GET_CORE()->optimize(f);
 			DEBUG_LEVEL_DEC();
 
+			block_declaration = old_block_declaration;
+
 			std::vector<Value *> params;
 			params.push_back(classVal);
 			params.push_back(compile_const_pointer(NULL));
@@ -4065,15 +4071,16 @@
 		    assert(mid > 0);
 		}
 
-		Function::ArgumentListType &fargs =
-		    bb->getParent()->getArgumentList();
-		const int fargs_arity = fargs.size() - 2;
-
 		bool splat_args = false;
 		bool positive_arity = false;
 		if (nd_type(node) == NODE_ZSUPER) {
 		    assert(args == NULL);
-		    positive_arity = fargs_arity > 0;
+		    int arity = bb->getParent()->getArgumentList().size();
+		    arity -= 2; // skip self and sel
+		    if (block_declaration) {
+			arity -= 2; // skip dvar and current_block
+		    }
+		    positive_arity = arity > 0;
 		}
 		else {
 		    NODE *n = args;
@@ -4105,9 +4112,10 @@
 		    }
 		}
 
-		// Recursive method call optimization.
+		// Recursive method call optimization. Not for everyone.
 		if (!block_given && !super_call && !splat_args
-		    && positive_arity && mid == current_mid && recv == NULL) {
+		    && !block_declaration && positive_arity
+		    && mid == current_mid && recv == NULL) {
 
 		    Function *f = bb->getParent();
 		    const unsigned long argc =
@@ -4127,6 +4135,7 @@
 
 			CallInst *inst = CallInst::Create(f, params.begin(),
 				params.end(), "", bb);
+			// Promote for tail call elimitation.
 			inst->setTailCall(true);
 			return cast<Value>(inst);
 		    }
@@ -4147,20 +4156,40 @@
 		SEL sel;
 		if (mid != 0) {
 		    sel = mid_to_sel(mid, positive_arity ? 1 : 0);
-		    params.push_back(compile_mcache(sel, super_call));
 		    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);
+			params.push_back(compile_get_mcache(sel_val, true));
+		    }
+		    else {
+			params.push_back(compile_mcache(sel, super_call));
+		    }
 		}
 		else {
 		    assert(super_call);
+		    // A super call outside a method definition. Compile a
+		    // null selector, the runtime will raise an exception.
 		    sel = 0;
-		    // A super call outside a method definition (probably
-		    // in a block). Retrieve the SEL as the second parameter
-		    // of the current function.
-		    Function *f = bb->getParent();
-		    Function::arg_iterator arg = f->arg_begin();
-		    arg++; // skip self
-		    sel_val = arg;
-		    params.push_back(compile_get_mcache(sel_val, true));
+		    params.push_back(compile_const_pointer(NULL));
+		    sel_val = compile_const_pointer(NULL);
 		}
 
 		// Top.
@@ -4194,14 +4223,17 @@
 		// Arguments.
 		int argc = 0;
 		if (nd_type(node) == NODE_ZSUPER) {
-		    const int arity = mid == 0
+		    Function::ArgumentListType &fargs =
+			bb->getParent()->getArgumentList();
+		    const int fargs_arity = fargs.size() - 2;
+		    const int arity = block_declaration
 			? fargs_arity - 2 // skip dvars and current_block
 			: fargs_arity;
 		    params.push_back(ConstantInt::get(Int32Ty, arity));
 		    Function::ArgumentListType::iterator iter = fargs.begin();
 		    iter++; // skip self
 		    iter++; // skip sel
-		    if (mid == 0) {
+		    if (block_declaration) {
 			iter++; // skip dvars
 			iter++; // skip current_block
 		    }
@@ -4254,7 +4286,8 @@
 		    if (block_given) {
 			blockVal = compile_block_create();
 		    }
-		    else if (nd_type(node) == NODE_ZSUPER && current_block_arg != NULL) {
+		    else if (nd_type(node) == NODE_ZSUPER
+			    && current_block_arg != NULL) {
 			blockVal = compile_block_get(current_block_arg);	
 		    }
 		    else {
@@ -4267,12 +4300,13 @@
 		// 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) {
+		if (!super_call
+			&& (sel == selEval
+			    || sel == selInstanceEval
+			    || sel == selClassEval
+			    || sel == selModuleEval
+			    || sel == selLocalVariables
+			    || sel == selBinding)) {
 		    compile_binding();
 		}
 
@@ -4599,10 +4633,13 @@
 
 		const bool singleton_method = nd_type(node) == NODE_DEFS;
 
+		const ID old_current_mid = current_mid;
 		current_mid = mid;
 		current_instance_method = !singleton_method;
 		const bool old_current_block_chain = current_block_chain;
 		current_block_chain = false;
+		const bool old_block_declaration = block_declaration;
+		block_declaration = false;
 
 		DEBUG_LEVEL_INC();
 		Value *val = compile_node(body);
@@ -4610,8 +4647,9 @@
 		Function *new_function = cast<Function>(val);
 		DEBUG_LEVEL_DEC();
 
+		block_declaration = old_block_declaration;
 		current_block_chain = old_current_block_chain;
-		current_mid = 0;
+		current_mid = old_current_mid;
 		current_instance_method = false;
 
 		Value *classVal;
@@ -5035,21 +5073,22 @@
 		current_loop_begin_bb = current_loop_end_bb = NULL;
 		Function *old_current_block_func = current_block_func;
 		NODE *old_current_block_node = current_block_node;
-		ID old_current_mid = current_mid;
 		bool old_current_block = current_block;
 		bool old_current_block_chain = current_block_chain;
 		int old_return_from_block = return_from_block;
 		bool old_dynamic_class = dynamic_class;
+		bool old_block_declaration = block_declaration;
 
-		current_mid = 0;
 		current_block = true;
 		current_block_chain = true;
 		dynamic_class = true;
+		block_declaration = true;
 
 		assert(node->nd_body != NULL);
 		Value *block = compile_node(node->nd_body);	
 		assert(Function::classof(block));
 
+		block_declaration = old_block_declaration;
 		dynamic_class = old_dynamic_class;
 
 		BasicBlock *return_from_block_bb = NULL;
@@ -5066,7 +5105,6 @@
 		current_loop_begin_bb = old_current_loop_begin_bb;
 		current_loop_body_bb = old_current_loop_body_bb;
 		current_loop_end_bb = old_current_loop_end_bb;
-		current_mid = old_current_mid;
 		current_block = old_current_block;
 		current_block_chain = old_current_block_chain;
 

Modified: MacRuby/trunk/compiler.h
===================================================================
--- MacRuby/trunk/compiler.h	2010-01-07 00:31:58 UTC (rev 3198)
+++ MacRuby/trunk/compiler.h	2010-01-07 05:18:37 UTC (rev 3199)
@@ -116,7 +116,7 @@
 	int return_from_block;
 	int return_from_block_ids;
 	PHINode *ensure_pn;
-	bool class_declaration;
+	bool block_declaration;
 
 	Function *dispatcherFunc;
 	Function *fastPlusFunc;

Modified: MacRuby/trunk/dispatcher.cpp
===================================================================
--- MacRuby/trunk/dispatcher.cpp	2010-01-07 00:31:58 UTC (rev 3198)
+++ MacRuby/trunk/dispatcher.cpp	2010-01-07 05:18:37 UTC (rev 3199)
@@ -224,6 +224,11 @@
     IMP self;
     while (true) {
 	Method m = class_getInstanceMethod(k, sel);
+	if (m == NULL) {
+	    // The given selector does not exist, let's go through
+	    // #method_missing...
+	    return NULL; 
+	}
 	assert(m != NULL);
 	self = method_getImplementation(m);
 	if (UNAVAILABLE_IMP(self)) {
@@ -547,7 +552,12 @@
 	Class klass, SEL sel, rb_vm_block_t *block, unsigned char opt,
 	int argc, const VALUE *argv)
 {
-    assert(cache != NULL);
+    if (cache == NULL) {
+	if (sel == 0 && opt == DISPATCH_SUPER) {
+	    rb_raise(rb_eNoMethodError, "super called outside of method");
+	}
+	abort(); 
+    }
 
     if (klass == NULL) {
 	klass = (Class)CLASS_OF(self);
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macruby-changes/attachments/20100106/9bd3fdf9/attachment-0001.html>


More information about the macruby-changes mailing list