[macruby-changes] [5163] MacRuby/trunk

source_changes at macosforge.org source_changes at macosforge.org
Thu Jan 13 18:21:47 PST 2011


Revision: 5163
          http://trac.macosforge.org/projects/ruby/changeset/5163
Author:   lsansonetti at apple.com
Date:     2011-01-13 18:21:41 -0800 (Thu, 13 Jan 2011)
Log Message:
-----------
fix the compilation of C blocks closures to not use a global variable to store/load the Proc object to call, but instead retrieve a reference to it from the block literal argument

Modified Paths:
--------------
    MacRuby/trunk/compiler.cpp
    MacRuby/trunk/compiler.h
    MacRuby/trunk/kernel.c
    MacRuby/trunk/spec/macruby/language/objc_method_spec.rb

Modified: MacRuby/trunk/compiler.cpp
===================================================================
--- MacRuby/trunk/compiler.cpp	2011-01-13 15:31:57 UTC (rev 5162)
+++ MacRuby/trunk/compiler.cpp	2011-01-14 02:21:41 UTC (rev 5163)
@@ -274,6 +274,7 @@
     rvalToSelFunc = get_function("vm_rval_to_sel");
     rvalToCharPtrFunc = get_function("vm_rval_to_charptr");
     initBlockFunc = get_function("vm_init_c_block");
+    blockProcFunc = get_function("vm_ruby_block_literal_proc");
     setCurrentMRIMethodContext = NULL;
 
     VoidTy = Type::getVoidTy(context);
@@ -5249,11 +5250,17 @@
 RoxorCompiler::compile_lambda_to_funcptr(const char *type,
 	Value *val, Value *slot, bool is_block)
 {
-    GlobalVariable *proc_gvar =
-	new GlobalVariable(*RoxorCompiler::module,
+    GlobalVariable *proc_gvar = NULL;
+    if (!is_block) {
+	// When compiling a function pointer closure, the Proc object we
+	// want to call must be preserved as a global variable.
+	// This isn't needed for C blocks because we can retrieve the Proc
+	// object from the block literal argument.
+	proc_gvar = new GlobalVariable(*RoxorCompiler::module,
 		RubyObjTy, false, GlobalValue::InternalLinkage,
 		nilVal, "");
-    new StoreInst(val, proc_gvar, bb);
+	new StoreInst(val, proc_gvar, bb);
+    }
 
     const size_t buf_len = strlen(type + 1) + 1;
     assert(buf_len > 1);
@@ -5267,8 +5274,7 @@
     std::vector<const Type *> arg_types;
 
     if (is_block) {
-	// The Block ABI specifies that the first argument is a pointer
-	// to the block literal, which we don't really care about.
+	// The block literal argument.
 	arg_types.push_back(PtrTy);	
     }
 
@@ -5295,6 +5301,10 @@
     bb = BasicBlock::Create(context, "EntryBlock", f);
 
     Function::arg_iterator arg = f->arg_begin();
+    Value *block_lit = NULL;
+    if (is_block) {
+	block_lit = arg++;
+    }
 
     Value *argv;
     if (argc == 0) {
@@ -5304,12 +5314,7 @@
     else {
 	argv = new AllocaInst(RubyObjTy, ConstantInt::get(Int32Ty, argc),
 		"", bb);
-	int off = 0;
-	if (is_block) {
-	    // Skip block literal argument.
-	    off++;
-	    arg++;
-	}
+	const int off = is_block ? 1 : 0;
 	for (int i = 0; i < argc; i++) {
 	    Value *index = ConstantInt::get(Int32Ty, i);
 	    Value *aslot = GetElementPtrInst::Create(argv, index, "", bb);
@@ -5319,6 +5324,16 @@
 	}
     }
 
+    Value *proc;
+    if (is_block) {
+	block_lit = new BitCastInst(block_lit,
+		PointerType::getUnqual(BlockLiteralTy), "", bb);
+	proc = CallInst::Create(blockProcFunc, block_lit, "", bb);
+    }
+    else {
+	proc = new LoadInst(proc_gvar, "", bb);
+    }
+
     // VALUE rb_proc_check_and_call(
     //	VALUE self, int argc, VALUE *argv
     // )
@@ -5329,7 +5344,7 @@
 		    RubyObjTy, Int32Ty, RubyObjPtrTy, NULL));
 
     Value *args[] = {
-	new LoadInst(proc_gvar, "", bb),
+	proc,
 	ConstantInt::get(Int32Ty, argc),
 	argv
     };

Modified: MacRuby/trunk/compiler.h
===================================================================
--- MacRuby/trunk/compiler.h	2011-01-13 15:31:57 UTC (rev 5162)
+++ MacRuby/trunk/compiler.h	2011-01-14 02:21:41 UTC (rev 5163)
@@ -263,6 +263,7 @@
 	Function *rvalToSelFunc;
 	Function *rvalToCharPtrFunc;
 	Function *initBlockFunc;
+	Function *blockProcFunc;
 	Function *setCurrentMRIMethodContext;
 
 	Constant *zeroVal;

Modified: MacRuby/trunk/kernel.c
===================================================================
--- MacRuby/trunk/kernel.c	2011-01-13 15:31:57 UTC (rev 5162)
+++ MacRuby/trunk/kernel.c	2011-01-14 02:21:41 UTC (rev 5163)
@@ -1089,3 +1089,9 @@
     b->descriptor = &ruby_block_descriptor_value;
     GC_WB(&b->ruby_proc, proc);
 }
+
+PRIMITIVE VALUE
+vm_ruby_block_literal_proc(struct ruby_block_literal *b)
+{
+    return b->ruby_proc;
+}

Modified: MacRuby/trunk/spec/macruby/language/objc_method_spec.rb
===================================================================
--- MacRuby/trunk/spec/macruby/language/objc_method_spec.rb	2011-01-13 15:31:57 UTC (rev 5162)
+++ MacRuby/trunk/spec/macruby/language/objc_method_spec.rb	2011-01-14 02:21:41 UTC (rev 5163)
@@ -816,6 +816,21 @@
     res.should == ['zero', 'one', 'two'] 
   end
 
+  it "can be used when an Objective-C method takes a Block as argument (nested)" do
+    ary1 = ['zero', 'one', 'two', 'three', 'four']
+    ary2 = ['zero', 'un', 'deux', 'trois', 'quatre']
+    res = []
+    ary1.enumerateObjectsUsingBlock(Proc.new { |obj, idx, stop|
+      res << obj
+      ary2.enumerateObjectsUsingBlock(Proc.new { |obj, idx, stop|
+        res << obj
+        stop.assign(true) if idx == 1
+      })
+      stop.assign(true) if idx == 2
+    })
+    res.should == ['zero', 'zero', 'un', 'one', 'zero', 'un', 'two', 'zero', 'un'] 
+  end
+
   it "is properly retained/released when transformed as a Block" do
     o = TestMethod.new
     o.methodSavingBlockReference(Proc.new { |x, y| x * y })
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macruby-changes/attachments/20110113/9ad97386/attachment.html>


More information about the macruby-changes mailing list