[macruby-changes] [619] MacRuby/trunk/objc.m

source_changes at macosforge.org source_changes at macosforge.org
Wed Sep 24 18:37:23 PDT 2008


Revision: 619
          http://trac.macosforge.org/projects/ruby/changeset/619
Author:   lsansonetti at apple.com
Date:     2008-09-24 18:37:23 -0700 (Wed, 24 Sep 2008)
Log Message:
-----------
faster struct accessors

Modified Paths:
--------------
    MacRuby/trunk/objc.m

Modified: MacRuby/trunk/objc.m
===================================================================
--- MacRuby/trunk/objc.m	2008-09-24 07:28:33 UTC (rev 618)
+++ MacRuby/trunk/objc.m	2008-09-25 01:37:23 UTC (rev 619)
@@ -2074,108 +2074,7 @@
     return Data_Wrap_Struct(recv, NULL, NULL, data);
 }
 
-static ID
-rb_bs_struct_field_ivar_id(void)
-{
-    const char *frame_str;
-    char ivar_name[128];
-    size_t len;
-
-    frame_str = rb_id2name(rb_frame_this_func());
-    len = snprintf(ivar_name, sizeof ivar_name, "@%s", frame_str);
-	
-    if (ivar_name[len - 1] == ':')
-	len--;
-    if (ivar_name[len - 1] == '=')
-	len--;
-    ivar_name[len] = '\0';
-
-    return rb_intern(ivar_name);
-}
-
 static VALUE
-rb_bs_struct_get(VALUE recv)
-{
-    bs_element_boxed_t *bs_boxed = rb_klass_get_bs_boxed(CLASS_OF(recv));
-    bs_element_struct_t *bs_struct = (bs_element_struct_t *)bs_boxed->value;
-    unsigned i;
-    const char *ivar_id_str;
-    VALUE *data;
-
-    /* FIXME we should cache the ivar IDs somewhere in the 
-     * bs_element_struct_fields 
-     */
-
-    ivar_id_str = rb_id2name(rb_bs_struct_field_ivar_id());
-    ivar_id_str++; /* skip first '@' */
-
-    Data_Get_Struct(recv, VALUE, data);
-    assert(data != NULL);
-
-    for (i = 0; i < bs_struct->fields_count; i++) {
-	bs_element_struct_field_t *bs_field =
-	    (bs_element_struct_field_t *)&bs_struct->fields[i];
-
-	if (strcmp(ivar_id_str, bs_field->name) == 0) {
-	    return data[i];
-	}
-    }
-
-    rb_bug("can't find field `%s' in recv `%s'", ivar_id_str,
-	   RSTRING_PTR(rb_inspect(recv)));
-
-    return Qnil;
-}
-
-static VALUE
-rb_bs_struct_set(VALUE recv, VALUE value)
-{
-    bs_element_boxed_t *bs_boxed = rb_klass_get_bs_boxed(CLASS_OF(recv));
-    bs_element_struct_t *bs_struct = (bs_element_struct_t *)bs_boxed->value;
-    unsigned i;
-    const char *ivar_id_str;
-    VALUE *data;
-    size_t pos;
-
-    /* FIXME we should cache the ivar IDs somewhere in the 
-     * bs_element_struct_fields 
-     */
-
-    ivar_id_str = rb_id2name(rb_bs_struct_field_ivar_id());
-    ivar_id_str++; /* skip first '@' */
-
-    Data_Get_Struct(recv, VALUE, data);
-    assert(data != NULL);
-
-    for (i = 0, pos = 0; i < bs_struct->fields_count; i++) {
-	bs_element_struct_field_t *bs_field =
-	    (bs_element_struct_field_t *)&bs_struct->fields[i];
-
-	if (strcmp(ivar_id_str, bs_field->name) == 0) {
-	    size_t fdata_size;
-	    void *fdata;
-	    VALUE fval;
-
-	    fdata_size = rb_objc_octype_to_ffitype(bs_field->type)->size;
-	    fdata = alloca(fdata_size);
-
-	    rb_objc_rval_to_ocval(value, bs_field->type, fdata);
-	    rb_objc_ocval_to_rval(fdata, bs_field->type, &fval);
-
-	    GC_WB(&data[i], fval);	
-
-	    return value;
-	}
-        pos += rb_objc_octype_to_ffitype(bs_field->type)->size;
-    }
-
-    rb_bug("can't find field `%s' in recv `%s'", ivar_id_str,
-	   RSTRING_PTR(rb_inspect(recv)));
-
-    return Qnil;
-}
-
-static VALUE
 rb_bs_struct_to_a(VALUE recv)
 {
     bs_element_boxed_t *bs_boxed = rb_klass_get_bs_boxed(CLASS_OF(recv));
@@ -2325,7 +2224,108 @@
     return ary;
 }
 
+static ffi_cif *struct_reader_cif = NULL;
+static ffi_cif *struct_writer_cif = NULL;
+
+struct rb_struct_accessor_context {
+    bs_element_struct_field_t *field;
+    int num;
+};
+
 static void
+rb_struct_reader_closure_handler(ffi_cif *cif, void *resp, void **args,
+				 void *userdata)
+{
+    struct rb_struct_accessor_context *ctx;
+    VALUE recv, *data;
+
+    recv = (*(VALUE **)args)[0];
+    Data_Get_Struct(recv, VALUE, data);
+    assert(data != NULL);
+
+    ctx = (struct rb_struct_accessor_context *)userdata;
+    *(VALUE *)resp = data[ctx->num];
+}
+
+static void
+rb_struct_writer_closure_handler(ffi_cif *cif, void *resp, void **args,
+                                 void *userdata)
+{
+    struct rb_struct_accessor_context *ctx;
+    VALUE recv, value, *data, fval;
+    size_t fdata_size;
+    void *fdata;
+
+    recv = (*(VALUE **)args)[0];
+    value = (*(VALUE **)args)[1];
+    Data_Get_Struct(recv, VALUE, data);
+    assert(data != NULL);
+
+    ctx = (struct rb_struct_accessor_context *)userdata;
+
+    fdata_size = rb_objc_octype_to_ffitype(ctx->field->type)->size;
+    fdata = alloca(fdata_size);
+
+    rb_objc_rval_to_ocval(value, ctx->field->type, fdata);
+    rb_objc_ocval_to_rval(fdata, ctx->field->type, &fval);
+
+    GC_WB(&data[ctx->num], fval);
+
+    *(VALUE *)resp = fval;
+}
+
+static void
+rb_struct_gen_accessors(VALUE klass, bs_element_struct_field_t *field, int num)
+{
+    ffi_closure *closure;
+    struct rb_struct_accessor_context *ctx;
+    char buf[100];
+
+    ctx = (struct rb_struct_accessor_context *)
+	malloc(sizeof(struct rb_struct_accessor_context));
+    ctx->field = field;
+    ctx->num = num;
+
+    if (struct_reader_cif == NULL) {
+	ffi_type **args;
+
+	struct_reader_cif = (ffi_cif *)malloc(sizeof(ffi_cif));
+	args = (ffi_type **)malloc(sizeof(ffi_type *) * 1);
+	args[0] = &ffi_type_pointer;
+	if (ffi_prep_cif(struct_reader_cif, FFI_DEFAULT_ABI, 1, 
+			 &ffi_type_pointer, args) != FFI_OK)
+	    rb_fatal("can't prepare struct_reader_cif");
+    }
+    closure = (ffi_closure *)malloc(sizeof(ffi_closure));
+    if (ffi_prep_closure(closure, struct_reader_cif, 
+		         rb_struct_reader_closure_handler, ctx)
+	!= FFI_OK)
+	rb_fatal("can't prepare struct reader closure");
+
+    rb_define_method(klass, field->name, (VALUE(*)(ANYARGS))closure, 0);
+
+    if (struct_writer_cif == NULL) {
+	ffi_type **args;
+
+	struct_writer_cif = (ffi_cif *)malloc(sizeof(ffi_cif));
+	args = (ffi_type **)malloc(sizeof(ffi_type *) * 2);
+	args[0] = &ffi_type_pointer;
+	args[1] = &ffi_type_pointer;
+	if (ffi_prep_cif(struct_writer_cif, FFI_DEFAULT_ABI, 2, 
+			 &ffi_type_pointer, args) != FFI_OK)
+	    rb_fatal("can't prepare struct_writer_cif");
+    }
+    closure = (ffi_closure *)malloc(sizeof(ffi_closure));
+    if (ffi_prep_closure(closure, struct_writer_cif, 
+			 rb_struct_writer_closure_handler, ctx)
+	!= FFI_OK)
+	rb_fatal("can't prepare struct writer closure");
+
+    snprintf(buf, sizeof buf, "%s=", field->name);
+    rb_define_method(klass, buf, (VALUE(*)(ANYARGS))closure, 1);
+}
+
+static void
 setup_bs_boxed_type(bs_element_type_t type, void *value)
 {
     bs_element_boxed_t *bs_boxed;
@@ -2344,7 +2344,6 @@
 
     if (type == BS_ELEMENT_STRUCT) {
 	bs_element_struct_t *bs_struct = (bs_element_struct_t *)value;
-	char buf[128];
 	int i;
 
 	/* Needs to be lazily created, because the type of some fields
@@ -2355,10 +2354,7 @@
 	if (!bs_struct->opaque) {
 	    for (i = 0; i < bs_struct->fields_count; i++) {
 		bs_element_struct_field_t *field = &bs_struct->fields[i];
-		rb_define_method(klass, field->name, rb_bs_struct_get, 0);
-		strlcpy(buf, field->name, sizeof buf);
-		strlcat(buf, "=", sizeof buf);
-		rb_define_method(klass, buf, rb_bs_struct_set, 1);
+		rb_struct_gen_accessors(klass, field, i);
 	    }
 	    rb_define_method(klass, "to_a", rb_bs_struct_to_a, 0);
 	}
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.macosforge.org/pipermail/macruby-changes/attachments/20080924/a5b5996a/attachment.html 


More information about the macruby-changes mailing list