[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