Revision: 3970 http://trac.macosforge.org/projects/ruby/changeset/3970 Author: lsansonetti@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 +
participants (1)
-
source_changes@macosforge.org