[macruby-changes] [3970] MacRuby/trunk

source_changes at macosforge.org source_changes at macosforge.org
Wed Apr 28 20:54:51 PDT 2010


Revision: 3970
          http://trac.macosforge.org/projects/ruby/changeset/3970
Author:   lsansonetti at apple.com
Date:     2010-04-28 20:54:50 -0700 (Wed, 28 Apr 2010)
Log Message:
-----------
added simple compiler support for bit fields and C-style arrays, improved support of opaque structures

Modified Paths:
--------------
    MacRuby/trunk/bridgesupport.cpp
    MacRuby/trunk/compiler.cpp
    MacRuby/trunk/compiler.h
    MacRuby/trunk/spec/macruby/core/struct_spec.rb

Modified: MacRuby/trunk/bridgesupport.cpp
===================================================================
--- MacRuby/trunk/bridgesupport.cpp	2010-04-29 02:42:04 UTC (rev 3969)
+++ MacRuby/trunk/bridgesupport.cpp	2010-04-29 03:54:50 UTC (rev 3970)
@@ -480,7 +480,7 @@
 
     rb_ivar_set(boxed->klass, boxed_ivar_type, rb_str_new2(octype.c_str()));
 
-    if (type == BS_ELEMENT_STRUCT) {
+    if (type == BS_ELEMENT_STRUCT && !boxed->as.s->opaque) {
 	// Define the fake #new method.
 	rb_objc_define_method(*(VALUE *)boxed->klass, "new",
 		(void *)rb_vm_struct_fake_new, -1);

Modified: MacRuby/trunk/compiler.cpp
===================================================================
--- MacRuby/trunk/compiler.cpp	2010-04-29 02:42:04 UTC (rev 3969)
+++ MacRuby/trunk/compiler.cpp	2010-04-29 03:54:50 UTC (rev 3970)
@@ -117,6 +117,7 @@
     getStructFieldsFunc = NULL;
     getOpaqueDataFunc = NULL;
     getPointerPtrFunc = NULL;
+    xmallocFunc = NULL;
     checkArityFunc = NULL;
     setStructFunc = NULL;
     newRangeFunc = NULL;
@@ -187,6 +188,7 @@
     PtrTy = PointerType::getUnqual(Int8Ty);
     PtrPtrTy = PointerType::getUnqual(PtrTy);
     Int32PtrTy = PointerType::getUnqual(Int32Ty);
+    BitTy = Type::getInt1Ty(context);
 
 #if ROXOR_COMPILER_DEBUG
     level = 0;
@@ -6259,10 +6261,8 @@
 void *
 rb_vm_get_opaque_data(VALUE rval, rb_vm_bs_boxed_t *bs_boxed, void **ocval)
 {
-    if (rval == Qnil) {
-	return *ocval = NULL;
-    }
-    else {
+    void *data = NULL;
+    if (rval != Qnil) {
 	if (!rb_obj_is_kind_of(rval, bs_boxed->klass)) {
 	    rb_raise(rb_eTypeError,
 		    "cannot convert `%s' (%s) to opaque type %s",
@@ -6270,17 +6270,21 @@
 		    rb_obj_classname(rval),
 		    rb_class2name(bs_boxed->klass));
 	}
-	VALUE *data;
 	Data_Get_Struct(rval, VALUE, data);
-	return *ocval = (void *)data;
     }
+    if (ocval != NULL) {
+	*ocval = data;
+    }
+    return data;
 }
 
 Value *
 RoxorCompiler::compile_get_opaque_data(Value *val, rb_vm_bs_boxed_t *bs_boxed,
-				       Value *slot)
+	Value *slot)
 {
     if (getOpaqueDataFunc == NULL) {
+	// void *rb_vm_get_opaque_data(VALUE rval, rb_vm_bs_boxed_t *bs_boxed,
+	//	void **ocval)
 	getOpaqueDataFunc = cast<Function>(module->getOrInsertFunction(
 		    "rb_vm_get_opaque_data",
 		    PtrTy, RubyObjTy, PtrTy, PtrPtrTy, NULL));
@@ -6393,33 +6397,46 @@
 	    {
 		rb_vm_bs_boxed_t *bs_boxed = GET_CORE()->find_bs_struct(type);
 		if (bs_boxed != NULL) {
-		    Value *fields = new AllocaInst(RubyObjTy,
-			    ConstantInt::get(Int32Ty,
-				bs_boxed->as.s->fields_count), "", bb);
+		    if (bs_boxed->as.s->opaque) {
+			// Structure is opaque, we just copy the data from
+			// the opaque object into the slot.
+			Value *data = compile_get_opaque_data(val, bs_boxed,
+				ConstantPointerNull::get(PtrPtrTy));
+			data = new BitCastInst(data,
+				PointerType::getUnqual(convert_type(type)), 
+				"", bb);
+			new StoreInst(new LoadInst(data, "", bb), slot, bb);
+		    }
+		    else {
+			// Retrieve all fields (as Ruby objects).
+			Value *fields = new AllocaInst(RubyObjTy,
+				ConstantInt::get(Int32Ty,
+				    bs_boxed->as.s->fields_count), "", bb);
+			compile_get_struct_fields(val, fields, bs_boxed);
 
-		    compile_get_struct_fields(val, fields, bs_boxed);
+			// Convert each field to C inside the slot memory.
+			for (unsigned i = 0; i < bs_boxed->as.s->fields_count;
+				i++) {
 
-		    for (unsigned i = 0; i < bs_boxed->as.s->fields_count;
-			    i++) {
+			    const char *ftype = bs_boxed->as.s->fields[i].type;
 
-			const char *ftype = bs_boxed->as.s->fields[i].type;
+			    // Load field VALUE.
+			    Value *fval = GetElementPtrInst::Create(fields,
+				    ConstantInt::get(Int32Ty, i), "", bb);
+			    fval = new LoadInst(fval, "", bb);
 
-			// Load field VALUE.
-			Value *fval = GetElementPtrInst::Create(fields,
-				ConstantInt::get(Int32Ty, i), "", bb);
-			fval = new LoadInst(fval, "", bb);
+			    // Get a pointer to the struct field. The extra 0
+			    // is needed because we are dealing with a pointer
+			    // to the structure.
+			    std::vector<Value *> slot_idx;
+			    slot_idx.push_back(ConstantInt::get(Int32Ty, 0));
+			    slot_idx.push_back(ConstantInt::get(Int32Ty, i));
+			    Value *fslot = GetElementPtrInst::Create(slot,
+				    slot_idx.begin(), slot_idx.end(), "", bb);
 
-			// Get a pointer to the struct field. The extra 0 is
-			// needed because we are dealing with a pointer to the
-			// structure.
-			std::vector<Value *> slot_idx;
-			slot_idx.push_back(ConstantInt::get(Int32Ty, 0));
-			slot_idx.push_back(ConstantInt::get(Int32Ty, i));
-			Value *fslot = GetElementPtrInst::Create(slot,
-				slot_idx.begin(), slot_idx.end(), "", bb);
-
-			RoxorCompiler::compile_conversion_to_c(ftype, fval,
-				fslot);
+			    RoxorCompiler::compile_conversion_to_c(ftype, fval,
+				    fslot);
+			}
 		    }
 
 		    if (GET_CORE()->is_large_struct_type(bs_boxed->type)) {
@@ -6646,6 +6663,7 @@
 RoxorCompiler::compile_new_struct(Value *klass, std::vector<Value *> &fields)
 {
     if (newStructFunc == NULL) {
+	// VALUE rb_vm_new_struct(VALUE klass, int argc, ...)
 	std::vector<const Type *> types;
 	types.push_back(RubyObjTy);
 	types.push_back(Int32Ty);
@@ -6667,6 +6685,7 @@
 RoxorCompiler::compile_new_opaque(Value *klass, Value *val)
 {
     if (newOpaqueFunc == NULL) {
+	// VALUE rb_vm_new_opaque(VALUE klass, void *val)
 	newOpaqueFunc = cast<Function>(module->getOrInsertFunction(
 		    "rb_vm_new_opaque", RubyObjTy, RubyObjTy, PtrTy, NULL));
     }
@@ -6704,6 +6723,22 @@
 }
 
 Value *
+RoxorCompiler::compile_xmalloc(size_t len)
+{
+    if (xmallocFunc == NULL) {
+	// void *ruby_xmalloc(size_t len);
+	xmallocFunc = cast<Function>(module->getOrInsertFunction(
+		    "ruby_xmalloc", PtrTy, Int64Ty, NULL));
+    }
+
+    std::vector<Value *> params;
+    params.push_back(ConstantInt::get(Int64Ty, len));
+
+    return CallInst::Create(xmallocFunc, params.begin(), params.end(),
+	    "", bb);
+}
+
+Value *
 RoxorCompiler::compile_conversion_to_ruby(const char *type,
 	const Type *llvm_type, Value *val)
 {
@@ -6800,21 +6835,32 @@
 	    {
 		rb_vm_bs_boxed_t *bs_boxed = GET_CORE()->find_bs_struct(type);
 		if (bs_boxed != NULL) {
-		    std::vector<Value *> params;
+		    Value *klass = ConstantInt::get(RubyObjTy, bs_boxed->klass);
+		    if (bs_boxed->as.s->opaque) {
+			// Structure is opaque, we make a copy.
+			const size_t s = GET_CORE()->get_sizeof(llvm_type);
+			Value *slot = compile_xmalloc(s);
+			slot = new BitCastInst(slot,
+				PointerType::getUnqual(llvm_type), "", bb);
+			new StoreInst(val, slot, bb);
+			slot = new BitCastInst(slot, PtrTy, "", bb);
+			return compile_new_opaque(klass, slot);
+		    }
+		    else {
+			// Convert every field into a Ruby type, then box them.
+			std::vector<Value *> params;
+			for (unsigned i = 0; i < bs_boxed->as.s->fields_count;
+				i++) {
 
-		    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);
-
-			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));
+			}
+			return compile_new_struct(klass, params);
 		    }
-
-		    Value *klass = ConstantInt::get(RubyObjTy, bs_boxed->klass);
-		    return compile_new_struct(klass, params);
 		}
 	    }
 	    break;
@@ -6895,6 +6941,46 @@
 	case _C_ULNG_LNG:
 	    return Int64Ty;
 
+	case _C_BFLD:
+	    {
+		// Syntax is `b3' for `unsigned foo:3'. 
+		const long size = atol(type + 1);
+		assert(size > 0);
+		return ArrayType::get(BitTy, size);
+	    }
+	    break;
+
+	case _C_ARY_B:
+	    {
+		// Syntax is [8S] for `short foo[8]'.
+		// First, let's grab the size.
+		char buf[100];
+		unsigned int n = 0;
+		const char *p = type + 1;
+		while (isdigit(*p)) {
+		    assert(n < (sizeof buf) - 1);
+		    buf[n++] = *p;
+		    p++;
+		}
+		assert(n > 0);
+		buf[n] = '\0';
+		const long size = atol(buf);
+		assert(size > 0);
+		// Second, the element type.
+		n = 0;
+		while (*p != _C_ARY_E) {
+		    assert(n < (sizeof buf) - 1);
+		    buf[n++] = *p;
+		    p++;
+		}
+		assert(n > 0);
+		buf[n] = '\0';
+		const Type *type = convert_type(buf);
+		// Now, we can return the array type.
+		return ArrayType::get(type, size);
+	    }
+	    break;
+
 	case _C_FPTR_B:
 	    return PtrTy;
 

Modified: MacRuby/trunk/compiler.h
===================================================================
--- MacRuby/trunk/compiler.h	2010-04-29 02:42:04 UTC (rev 3969)
+++ MacRuby/trunk/compiler.h	2010-04-29 03:54:50 UTC (rev 3970)
@@ -168,6 +168,7 @@
 	Function *getStructFieldsFunc;
 	Function *getOpaqueDataFunc;
 	Function *getPointerPtrFunc;
+	Function *xmallocFunc;
 	Function *checkArityFunc;
 	Function *setStructFunc;
 	Function *newRangeFunc;
@@ -232,6 +233,7 @@
 	const PointerType *PtrPtrTy;
 	const Type *IntTy;
 	const PointerType *Int32PtrTy;
+	const Type *BitTy;
 
 	unsigned dbg_mdkind;
 
@@ -348,6 +350,7 @@
 	Value *compile_get_cptr(Value *val, const char *type, Value *slot);
 	void compile_check_arity(Value *given, Value *requested);
 	void compile_set_struct(Value *rcv, int field, Value *val);
+	Value *compile_xmalloc(size_t len);
 
 	Value *compile_conversion_to_c(const char *type, Value *val,
 				       Value *slot);

Modified: MacRuby/trunk/spec/macruby/core/struct_spec.rb
===================================================================
--- MacRuby/trunk/spec/macruby/core/struct_spec.rb	2010-04-29 02:42:04 UTC (rev 3969)
+++ MacRuby/trunk/spec/macruby/core/struct_spec.rb	2010-04-29 03:54:50 UTC (rev 3970)
@@ -8,6 +8,10 @@
     NSRange.superclass.should == Boxed
   end
 
+  it "if opaque, cannot be directly allocated" do
+    lambda { NSDecimal.new }.should raise_error(RuntimeError)
+  end
+
   it "can be created with null values using the #new method with no argument" do
     o = NSPoint.new
     o.x.class.should == Float
@@ -262,3 +266,12 @@
     r.size.should == NSSize.new(3, 4)
   end
 end
+
+describe "The NSDecimal structure (contains bit fields and C-style arrays)" do
+  it "can be created from -[NSNumber decimalValue] and re-used later" do
+    o = NSNumber.numberWithFloat(3.1415).decimalValue
+    o.class.should == NSDecimal
+    NSDecimalNumber.decimalNumberWithDecimal(o).should be_close(3.1415, TOLERANCE)
+  end
+end
+
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macruby-changes/attachments/20100428/57caf218/attachment-0001.html>


More information about the macruby-changes mailing list