Permalink
Browse files

added support for overwriting an ObjC method that accepts a pointer

  • Loading branch information...
lrz committed Jun 12, 2009
1 parent f85f317 commit ff75d601d972a03d5800cffb01bcbaf672931512
Showing with 91 additions and 12 deletions.
  1. +21 −12 bridgesupport.cpp
  2. +2 −0 bridgesupport.h
  3. +34 −0 compiler.cpp
  4. +2 −0 compiler.h
  5. +20 −0 spec/macruby/fixtures/method.m
  6. +2 −0 spec/macruby/fixtures/method.rb
  7. +10 −0 spec/macruby/language/objc_method_spec.rb
View
@@ -500,15 +500,9 @@ typedef struct {
static const char *convert_ffi_type(VALUE type,
bool raise_exception_if_unknown);
-static VALUE
-rb_pointer_new(VALUE rcv, SEL sel, int argc, VALUE *argv)
+VALUE
+rb_pointer_new(const char *type_str, void *val)
{
- VALUE type, len;
- rb_scan_args(argc, argv, "11", &type, &len);
- const size_t rlen = NIL_P(len) ? 1 : FIX2LONG(len);
-
- const char *type_str = convert_ffi_type(type, false);
-
rb_vm_pointer_t *ptr = (rb_vm_pointer_t *)xmalloc(sizeof(rb_vm_pointer_t));
GC_WB(&ptr->type, rb_str_new2(type_str));
@@ -519,11 +513,26 @@ rb_pointer_new(VALUE rcv, SEL sel, int argc, VALUE *argv)
ptr->type_size = GET_VM()->get_sizeof(type_str);
assert(ptr->type_size > 0);
- GC_WB(&ptr->val, xmalloc(ptr->type_size * rlen));
+
+ GC_WB(&ptr->val, val);
return Data_Wrap_Struct(rb_cPointer, NULL, NULL, ptr);
}
+static VALUE
+rb_pointer_s_new(VALUE rcv, SEL sel, int argc, VALUE *argv)
+{
+ VALUE type, len;
+
+ rb_scan_args(argc, argv, "11", &type, &len);
+
+ const size_t rlen = NIL_P(len) ? 1 : FIX2LONG(len);
+ const char *type_str = convert_ffi_type(type, false);
+
+ return rb_pointer_new(type_str,
+ xmalloc(GET_VM()->get_sizeof(type_str) * rlen));
+}
+
extern "C"
void *
rb_pointer_get_data(VALUE rcv, const char *type)
@@ -942,9 +951,9 @@ Init_BridgeSupport(void)
// Pointer
rb_cPointer = rb_define_class("Pointer", rb_cObject);
rb_objc_define_method(*(VALUE *)rb_cPointer, "new",
- (void *)rb_pointer_new, -1);
+ (void *)rb_pointer_s_new, -1);
rb_objc_define_method(*(VALUE *)rb_cPointer, "new_with_type",
- (void *)rb_pointer_new, -1);
+ (void *)rb_pointer_s_new, -1);
rb_objc_define_method(rb_cPointer, "[]",
(void *)rb_pointer_aref, 1);
rb_objc_define_method(rb_cPointer, "[]=",
@@ -1016,7 +1025,7 @@ convert_ffi_type(VALUE type, bool raise_exception_if_unknown)
// MacRuby extensions.
- if (strcmp(typestr, "object") == 0) {
+ if (strcmp(typestr, "object") == 0 || strcmp(typestr, "id") == 0) {
return "@";
}
View
@@ -25,6 +25,8 @@ typedef struct rb_vm_bs_boxed {
VALUE klass;
} rb_vm_bs_boxed_t;
+VALUE rb_pointer_new(const char *type_str, void *val);
+
#endif /* __cplusplus */
#endif /* __BRIDGESUPPORT_H_ */
View
@@ -86,6 +86,7 @@ RoxorCompiler::RoxorCompiler(const char *_fname)
newArrayFunc = NULL;
newStructFunc = NULL;
newOpaqueFunc = NULL;
+ newPointerFunc = NULL;
getStructFieldsFunc = NULL;
getOpaqueDataFunc = NULL;
getPointerPtrFunc = NULL;
@@ -4793,6 +4794,13 @@ rb_vm_new_opaque(VALUE klass, void *val)
return Data_Wrap_Struct(klass, NULL, NULL, val);
}
+extern "C"
+VALUE
+rb_vm_new_pointer(const char *type, void *val)
+{
+ return val == NULL ? Qnil : rb_pointer_new(type, val);
+}
+
Value *
RoxorCompiler::compile_new_struct(Value *klass, std::vector<Value *> &fields)
{
@@ -4830,6 +4838,30 @@ RoxorCompiler::compile_new_opaque(Value *klass, Value *val)
"", bb);
}
+Value *
+RoxorCompiler::compile_new_pointer(const char *type, Value *val)
+{
+ if (newPointerFunc == NULL) {
+ newPointerFunc = cast<Function>(module->getOrInsertFunction(
+ "rb_vm_new_pointer", RubyObjTy, PtrTy, PtrTy, NULL));
+ }
+
+ std::vector<Value *> params;
+
+ GlobalVariable *gvar = compile_const_global_string(type);
+ std::vector<Value *> idxs;
+ idxs.push_back(ConstantInt::get(Type::Int32Ty, 0));
+ idxs.push_back(ConstantInt::get(Type::Int32Ty, 0));
+ Instruction *load = GetElementPtrInst::Create(gvar,
+ idxs.begin(), idxs.end(), "", bb);
+ params.push_back(load);
+
+ params.push_back(val);
+
+ return CallInst::Create(newPointerFunc, params.begin(), params.end(),
+ "", bb);
+}
+
Value *
RoxorCompiler::compile_conversion_to_ruby(const char *type,
const Type *llvm_type, Value *val)
@@ -4941,6 +4973,8 @@ RoxorCompiler::compile_conversion_to_ruby(const char *type,
Value *klass = ConstantInt::get(RubyObjTy, bs_boxed->klass);
return compile_new_opaque(klass, val);
}
+
+ return compile_new_pointer(type + 1, val);
}
break;
}
View
@@ -116,6 +116,7 @@ class RoxorCompiler {
Function *newArrayFunc;
Function *newStructFunc;
Function *newOpaqueFunc;
+ Function *newPointerFunc;
Function *getStructFieldsFunc;
Function *getOpaqueDataFunc;
Function *getPointerPtrFunc;
@@ -229,6 +230,7 @@ class RoxorCompiler {
bool compile_lvars(ID *tbl);
Value *compile_new_struct(Value *klass, std::vector<Value *> &fields);
Value *compile_new_opaque(Value *klass, Value *val);
+ Value *compile_new_pointer(const char *type, 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,
@@ -618,6 +618,26 @@ + (BOOL)testMethodAcceptingNSRange:(TestMethod *)o
return [o methodAcceptingNSRange:NSMakeRange(0, 42)];
}
+- (BOOL)methodAcceptingObjPtr:(id *)p
+{
+ return *p == self;
+}
+
++ (BOOL)testMethodAcceptingObjPtr:(TestMethod *)o
+{
+ return [o methodAcceptingObjPtr:&o];
+}
+
+- (BOOL)methodAcceptingObjPtr2:(id *)p
+{
+ return p == NULL;
+}
+
++ (BOOL)testMethodAcceptingObjPtr2:(TestMethod *)o
+{
+ return [o methodAcceptingObjPtr2:NULL];
+}
+
- (BOOL)methodAcceptingInt:(int)a1 float:(float)a2 double:(double)a3
short:(short)a4 NSPoint:(NSPoint)a5 NSRect:(NSRect)a6 char:(char)a7
{
@@ -55,6 +55,8 @@ def methodAcceptingNSPoint(a); super; end
def methodAcceptingNSSize(a); super; end
def methodAcceptingNSRect(a); super; end
def methodAcceptingNSRange(a); super; end
+ def methodAcceptingObjPtr(a); super; end
+ def methodAcceptingObjPtr2(a); super; end
def methodAcceptingInt(a, float:a2, double:a3, short:a4, NSPoint:a5,
NSRect:a6, char:a7); super; end
end
@@ -623,6 +623,16 @@ def o2.to_str; 'foo' end
TestMethodOverride.testMethodAcceptingNSRange(@o).should == 1
end
+ it "can overwrite an Objective-C method accepting a Pointer to an Object" do
+ p = Pointer.new(:object)
+ p[0] = @o
+ @o.methodAcceptingObjPtr(p).should == 1
+ TestMethodOverride.testMethodAcceptingObjPtr(@o).should == 1
+
+ @o.methodAcceptingObjPtr2(nil).should == 1
+ TestMethodOverride.testMethodAcceptingObjPtr2(@o).should == 1
+ end
+
it "can overwrite a complex Objective-C method" do
@o.methodAcceptingInt(42, float:42, double:42, short:42, NSPoint:NSPoint.new(42, 42), NSRect:NSRect.new(NSPoint.new(42, 42), NSSize.new(42, 42)), char:42).should == 1
TestMethodOverride.testMethodAcceptingComplexTypes(@o).should == 1

0 comments on commit ff75d60

Please sign in to comment.