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

source_changes at macosforge.org source_changes at macosforge.org
Thu Apr 23 22:32:50 PDT 2009


Revision: 1485
          http://trac.macosforge.org/projects/ruby/changeset/1485
Author:   lsansonetti at apple.com
Date:     2009-04-23 22:32:50 -0700 (Thu, 23 Apr 2009)
Log Message:
-----------
some opaque types work

Modified Paths:
--------------
    MacRuby/branches/experimental/roxor.cpp

Added Paths:
-----------
    MacRuby/branches/experimental/spec/macruby/opaque_spec.rb

Modified: MacRuby/branches/experimental/roxor.cpp
===================================================================
--- MacRuby/branches/experimental/roxor.cpp	2009-04-24 04:28:43 UTC (rev 1484)
+++ MacRuby/branches/experimental/roxor.cpp	2009-04-24 05:32:50 UTC (rev 1485)
@@ -266,7 +266,9 @@
 	Function *dupArrayFunc;
 	Function *newArrayFunc;
 	Function *newStructFunc;
+	Function *newOpaqueFunc;
 	Function *getStructFieldsFunc;
+	Function *getOpaqueDataFunc;
 	Function *checkArityFunc;
 	Function *setStructFunc;
 	Function *newRangeFunc;
@@ -301,6 +303,7 @@
 	const Type *RubyObjPtrTy;
 	const Type *RubyObjPtrPtrTy;
 	const Type *PtrTy;
+	const Type *PtrPtrTy;
 	const Type *IntTy;
 
 	void compile_node_error(const char *msg, NODE *node) {
@@ -351,8 +354,11 @@
 	void compile_rethrow_exception(void);
 	Value *compile_lvar_slot(ID name);
 	Value *compile_new_struct(Value *klass, std::vector<Value *> &fields);
+	Value *compile_new_opaque(Value *klass, Value *val);
 	void compile_get_struct_fields(Value *val, Value *buf,
 		rb_vm_bs_boxed_t *bs_boxed);
+	Value *compile_get_opaque_data(Value *val, rb_vm_bs_boxed_t *bs_boxed,
+		Value *slot);
 	void compile_check_arity(Value *given, Value *requested);
 	void compile_set_struct(Value *rcv, int field, Value *val);
 
@@ -501,6 +507,7 @@
 	bs_element_method_t *find_bs_method(Class klass, SEL sel);
 	rb_vm_bs_boxed_t *find_bs_boxed(std::string type);
 	rb_vm_bs_boxed_t *find_bs_struct(std::string type);
+	rb_vm_bs_boxed_t *find_bs_opaque(std::string type);
 
 #if ROXOR_ULTRA_LAZY_JIT
 	std::map<SEL, std::map<Class, rb_vm_method_source_t *> *>
@@ -664,7 +671,9 @@
     dupArrayFunc = NULL;
     newArrayFunc = NULL;
     newStructFunc = NULL;
+    newOpaqueFunc = NULL;
     getStructFieldsFunc = NULL;
+    getOpaqueDataFunc = NULL;
     checkArityFunc = NULL;
     setStructFunc = NULL;
     newRangeFunc = NULL;
@@ -705,6 +714,7 @@
     splatArgFollowsVal = ConstantInt::get(RubyObjTy, SPLAT_ARG_FOLLOWS);
     cObject = ConstantInt::get(RubyObjTy, (long)rb_cObject);
     PtrTy = PointerType::getUnqual(Type::Int8Ty);
+    PtrPtrTy = PointerType::getUnqual(PtrTy);
 
 #if ROXOR_COMPILER_DEBUG
     level = 0;
@@ -5132,7 +5142,47 @@
     CallInst::Create(getStructFieldsFunc, params.begin(), params.end(), "", bb);
 }
 
+extern "C"
+void *
+rb_vm_get_opaque_data(VALUE rval, rb_vm_bs_boxed_t *bs_boxed, void **ocval)
+{
+    if (rval == Qnil) {
+	return *ocval = NULL;
+    }
+    else {
+	if (!rb_obj_is_kind_of(rval, bs_boxed->klass)) {
+	    rb_raise(rb_eTypeError,
+		    "cannot convert `%s' (%s) to opaque type %s",
+		    RSTRING_PTR(rb_inspect(rval)),
+		    rb_obj_classname(rval),
+		    rb_class2name(bs_boxed->klass));
+	}
+	VALUE *data;
+	Data_Get_Struct(rval, VALUE, data);
+	return *ocval = (void *)data;
+    }
+}
+
 Value *
+RoxorCompiler::compile_get_opaque_data(Value *val, rb_vm_bs_boxed_t *bs_boxed,
+				       Value *slot)
+{
+    if (getOpaqueDataFunc == NULL) {
+	getOpaqueDataFunc = cast<Function>(module->getOrInsertFunction(
+		    "rb_vm_get_opaque_data",
+		    PtrTy, RubyObjTy, PtrTy, PtrPtrTy, NULL));
+    }
+
+    std::vector<Value *> params;
+    params.push_back(val);
+    params.push_back(compile_const_pointer(bs_boxed));
+    params.push_back(slot);
+
+    return CallInst::Create(getOpaqueDataFunc, params.begin(), params.end(),
+	    "", bb);
+}
+
+Value *
 RoxorCompiler::compile_conversion_to_c(const char *type, Value *val,
 				       Value *slot)
 {
@@ -5242,6 +5292,15 @@
 		}
 	    }
 	    break;
+
+	case _C_PTR:
+	    {
+		rb_vm_bs_boxed_t *bs_boxed = GET_VM()->find_bs_opaque(type);
+		if (bs_boxed != NULL) {
+		    return compile_get_opaque_data(val, bs_boxed, slot);
+		}
+	    }
+	    break;
     }
 
     if (func_name == NULL) {
@@ -5321,6 +5380,13 @@
     return Data_Wrap_Struct(klass, NULL, NULL, data);
 }
 
+extern "C"
+VALUE
+rb_vm_new_opaque(VALUE klass, void *val)
+{
+    return Data_Wrap_Struct(klass, NULL, NULL, val);
+}
+
 Value *
 RoxorCompiler::compile_new_struct(Value *klass, std::vector<Value *> &fields)
 {
@@ -5343,6 +5409,22 @@
 }
 
 Value *
+RoxorCompiler::compile_new_opaque(Value *klass, Value *val)
+{
+    if (newOpaqueFunc == NULL) {
+	newOpaqueFunc = cast<Function>(module->getOrInsertFunction(
+		    "rb_vm_new_opaque", RubyObjTy, RubyObjTy, PtrTy, NULL));
+    }
+
+    std::vector<Value *> params;
+    params.push_back(klass);
+    params.push_back(val);
+
+    return CallInst::Create(newOpaqueFunc, params.begin(), params.end(),
+	    "", bb); 
+}
+
+Value *
 RoxorCompiler::compile_conversion_to_ruby(const char *type,
 					  const Type *llvm_type, Value *val)
 {
@@ -5413,25 +5495,37 @@
 	    break;
 
 	case _C_STRUCT_B:
-	    rb_vm_bs_boxed_t *bs_boxed = GET_VM()->find_bs_struct(type);
-	    if (bs_boxed != NULL) {
-		std::vector<Value *> params;
+	    {
+		rb_vm_bs_boxed_t *bs_boxed = GET_VM()->find_bs_struct(type);
+		if (bs_boxed != NULL) {
+		    std::vector<Value *> params;
 
-		for (unsigned i = 0; i < bs_boxed->as.s->fields_count;
-			i++) {
-			
-		    const char *ftype = bs_boxed->as.s->fields[i].type;
-		    const Type *llvm_ftype = convert_type(ftype);
-		    Value *fval = ExtractValueInst::Create(val, i, "", bb);
+		    for (unsigned i = 0; i < bs_boxed->as.s->fields_count;
+			    i++) {
 
-		    params.push_back(compile_conversion_to_ruby(ftype,
-				llvm_ftype, fval));
+			const char *ftype = bs_boxed->as.s->fields[i].type;
+			const Type *llvm_ftype = convert_type(ftype);
+			Value *fval = ExtractValueInst::Create(val, i, "", bb);
+
+			params.push_back(compile_conversion_to_ruby(ftype,
+				    llvm_ftype, fval));
+		    }
+
+		    Value *klass = ConstantInt::get(RubyObjTy, bs_boxed->klass);
+		    return compile_new_struct(klass, params);
 		}
+	    }
+	    break;
 
-		Value *klass = ConstantInt::get(RubyObjTy, bs_boxed->klass);
-		return compile_new_struct(klass, params);
+	case _C_PTR:
+	    {
+		rb_vm_bs_boxed_t *bs_boxed = GET_VM()->find_bs_opaque(type);
+		if (bs_boxed != NULL) {
+		    Value *klass = ConstantInt::get(RubyObjTy, bs_boxed->klass);
+		    return compile_new_opaque(klass, val);
+		}
 	    }
-	    break;
+	    break; 
     }
 
     if (func_name == NULL) {
@@ -8546,7 +8640,7 @@
 #include "bs_struct_readers.c"
 
 static VALUE
-rb_vm_struct_equal(VALUE rcv, SEL sel, VALUE val)
+rb_vm_boxed_equal(VALUE rcv, SEL sel, VALUE val)
 {
     if (rcv == val) {
 	return Qtrue;
@@ -8556,19 +8650,21 @@
 	return Qfalse;
     }
 
-    rb_vm_bs_boxed_t *bs_boxed = locate_bs_boxed(klass, true);
+    rb_vm_bs_boxed_t *bs_boxed = locate_bs_boxed(klass);
 
-    VALUE *rcv_data;
-    VALUE *val_data;
-    Data_Get_Struct(rcv, VALUE, rcv_data);
-    Data_Get_Struct(val, VALUE, val_data);
+    VALUE *rcv_data; Data_Get_Struct(rcv, VALUE, rcv_data);
+    VALUE *val_data; Data_Get_Struct(val, VALUE, val_data);
 
-    for (unsigned i = 0; i < bs_boxed->as.s->fields_count; i++) {
-	if (!rb_equal(rcv_data[i], val_data[i])) {
-	    return Qfalse;
+    if (bs_boxed->bs_type == BS_ELEMENT_STRUCT) {
+	for (unsigned i = 0; i < bs_boxed->as.s->fields_count; i++) {
+	    if (!rb_equal(rcv_data[i], val_data[i])) {
+		return Qfalse;
+	    }
 	}
+	return Qtrue;
     }
-    return Qtrue;
+
+    return rcv_data == val_data ? Qtrue : Qfalse;
 }
 
 static VALUE
@@ -8614,6 +8710,29 @@
     return Data_Wrap_Struct(klass, NULL, NULL, new_data);
 }
 
+static VALUE
+rb_boxed_fields(VALUE rcv, SEL sel)
+{
+    rb_vm_bs_boxed_t *bs_boxed = locate_bs_boxed(rcv);
+    VALUE ary = rb_ary_new();
+    if (bs_boxed->bs_type == BS_ELEMENT_STRUCT) {
+	for (unsigned i = 0; i < bs_boxed->as.s->fields_count; i++) {
+	    VALUE field = ID2SYM(rb_intern(bs_boxed->as.s->fields[i].name));
+	    rb_ary_push(ary, field);
+	}
+    }
+    return ary;
+}
+
+static VALUE
+rb_vm_opaque_new(VALUE rcv, SEL sel)
+{
+    // XXX instead of doing this, we should perhaps simply delete the new
+    // method on the class...
+    rb_raise(rb_eRuntimeError, "can't allocate opaque type `%s'",
+	    rb_class2name(rcv)); 
+}
+
 static bool
 register_bs_boxed(bs_element_type_t type, void *value)
 {
@@ -8656,8 +8775,8 @@
 	}
 
 	// Define other utility methods.
-	rb_objc_define_method(boxed->klass, "==",
-		(void *)rb_vm_struct_equal, 1);
+	rb_objc_define_method(*(VALUE *)boxed->klass, "fields",
+		(void *)rb_boxed_fields, 0);
 	rb_objc_define_method(boxed->klass, "dup",
 		(void *)rb_vm_struct_dup, 0);
 	rb_objc_define_method(boxed->klass, "clone",
@@ -8665,6 +8784,13 @@
 	rb_objc_define_method(boxed->klass, "inspect",
 		(void *)rb_vm_struct_inspect, 0);
     }
+    else {
+	// Opaque methods.
+	rb_objc_define_method(*(VALUE *)boxed->klass, "new",
+		(void *)rb_vm_opaque_new, -1);
+    }
+    // Common methods.
+    rb_objc_define_method(boxed->klass, "==", (void *)rb_vm_boxed_equal, 1);
 
     GET_VM()->bs_boxed[octype] = boxed;
 
@@ -8684,20 +8810,6 @@
     return bs_boxed->bs_type == BS_ELEMENT_OPAQUE ? Qtrue : Qfalse;
 }
 
-static VALUE
-rb_boxed_fields(VALUE rcv, SEL sel)
-{
-    rb_vm_bs_boxed_t *bs_boxed = locate_bs_boxed(rcv);
-    VALUE ary = rb_ary_new();
-    if (bs_boxed->bs_type == BS_ELEMENT_STRUCT) {
-	for (unsigned i = 0; i < bs_boxed->as.s->fields_count; i++) {
-	    VALUE field = ID2SYM(rb_intern(bs_boxed->as.s->fields[i].name));
-	    rb_ary_push(ary, field);
-	}
-    }
-    return ary;
-}
-
 VALUE rb_cBoxed;
 
 static void
@@ -8710,8 +8822,6 @@
 	    (void *)rb_boxed_objc_type, 0);
     rb_objc_define_method(*(VALUE *)rb_cBoxed, "opaque?",
 	    (void *)rb_boxed_is_opaque, 0);
-    rb_objc_define_method(*(VALUE *)rb_cBoxed, "fields",
-	    (void *)rb_boxed_fields, 0);
 }
 
 static inline void
@@ -8787,6 +8897,13 @@
     return boxed->is_struct() ? boxed : NULL;
 }
 
+inline rb_vm_bs_boxed_t *
+RoxorVM::find_bs_opaque(std::string type)
+{
+    rb_vm_bs_boxed_t *boxed = find_bs_boxed(type);
+    return boxed->is_struct() ? NULL : boxed;
+}
+
 static inline void
 register_bs_class(bs_element_class_t *bs_class)
 {

Added: MacRuby/branches/experimental/spec/macruby/opaque_spec.rb
===================================================================
--- MacRuby/branches/experimental/spec/macruby/opaque_spec.rb	                        (rev 0)
+++ MacRuby/branches/experimental/spec/macruby/opaque_spec.rb	2009-04-24 05:32:50 UTC (rev 1485)
@@ -0,0 +1,31 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+
+framework 'Foundation'
+
+describe "A BridgeSupport opaque type" do
+  it "is an instance of Boxed" do
+    NSZone.superclass.should == Boxed
+  end
+
+  it "cannot be created with #new" do
+    lambda { NSZone.new }.should raise_error(RuntimeError)
+  end
+
+  it "can be created from an Objective-C API, and passed back to Objective-C" do
+    z = 123.zone
+    z.class.should == NSZone
+    lambda { Object.allocWithZone(z).init }.should_not raise_error
+  end
+
+  it "can be compared to an exact same instance using #==" do
+    123.zone.should == 456.zone
+  end
+
+  it "returns true when the #opaque? class method is called" do
+    NSZone.opaque?.should == true
+  end 
+
+  it "returns its Objective-C encoding type when then #type class method is called" do
+    NSZone.type.should == '^{_NSZone=}'
+  end
+end
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macruby-changes/attachments/20090423/4db4b41f/attachment-0001.html>


More information about the macruby-changes mailing list