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

source_changes at macosforge.org source_changes at macosforge.org
Mon Apr 20 19:11:24 PDT 2009


Revision: 1433
          http://trac.macosforge.org/projects/ruby/changeset/1433
Author:   lsansonetti at apple.com
Date:     2009-04-20 19:11:23 -0700 (Mon, 20 Apr 2009)
Log Message:
-----------
some work on C structures support

Modified Paths:
--------------
    MacRuby/branches/experimental/include/ruby/ruby.h
    MacRuby/branches/experimental/objc.m
    MacRuby/branches/experimental/roxor.cpp
    MacRuby/branches/experimental/roxor.h
    MacRuby/branches/experimental/spec/frozen/macruby/fixtures/method.m
    MacRuby/branches/experimental/spec/frozen/macruby/method_spec.rb
    MacRuby/branches/experimental/variable.c

Modified: MacRuby/branches/experimental/include/ruby/ruby.h
===================================================================
--- MacRuby/branches/experimental/include/ruby/ruby.h	2009-04-20 23:30:02 UTC (rev 1432)
+++ MacRuby/branches/experimental/include/ruby/ruby.h	2009-04-21 02:11:23 UTC (rev 1433)
@@ -1064,6 +1064,7 @@
 RUBY_EXTERN VALUE rb_cNSSet;
 RUBY_EXTERN VALUE rb_cNSMutableSet;
 RUBY_EXTERN VALUE rb_cCFNumber;
+RUBY_EXTERN VALUE rb_cBoxed;
 
 bool _CFArrayIsMutable(void *);
 #define RARRAY_IMMUTABLE(o) (*(VALUE *)o == rb_cCFArray && !_CFArrayIsMutable((void *)o))

Modified: MacRuby/branches/experimental/objc.m
===================================================================
--- MacRuby/branches/experimental/objc.m	2009-04-20 23:30:02 UTC (rev 1432)
+++ MacRuby/branches/experimental/objc.m	2009-04-21 02:11:23 UTC (rev 1433)
@@ -62,7 +62,7 @@
     struct st_table *imethods;
 } bs_element_indexed_class_t;
 
-static VALUE rb_cBoxed;
+VALUE rb_cBoxed;
 static ID rb_ivar_type;
 
 static VALUE bs_const_magic_cookie = Qnil;
@@ -2203,6 +2203,7 @@
     return NULL;
 }
 
+#if 0
 static VALUE
 rb_bs_struct_new(int argc, VALUE *argv, VALUE recv)
 {
@@ -2341,6 +2342,7 @@
 
     return str;
 }
+#endif
 
 static VALUE
 rb_boxed_objc_type(VALUE recv, SEL sel)
@@ -2389,14 +2391,17 @@
     return ary;
 }
 
+#if 0
 static ffi_cif *struct_reader_cif = NULL;
 static ffi_cif *struct_writer_cif = NULL;
+#endif
 
 struct rb_struct_accessor_context {
     bs_element_struct_field_t *field;
     int num;
 };
 
+#if 0
 static void
 rb_struct_reader_closure_handler(ffi_cif *cif, void *resp, void **args,
 				 void *userdata)
@@ -2438,7 +2443,9 @@
 
     *(VALUE *)resp = fval;
 }
+#endif
 
+#if 0
 static void
 rb_struct_gen_accessors(VALUE klass, bs_element_struct_field_t *field, int num)
 {
@@ -2503,7 +2510,9 @@
     snprintf(buf, sizeof buf, "%s=", field->name);
     rb_define_method(klass, buf, (VALUE(*)(ANYARGS))closure, 1);
 }
+#endif
 
+#if 0
 static void
 setup_bs_boxed_type(bs_element_type_t type, void *value)
 {
@@ -2559,282 +2568,12 @@
 
     st_insert(bs_boxeds, (st_data_t)p->type, (st_data_t)bs_boxed);
 }
-
-static inline ID
-generate_const_name(char *name)
-{
-    ID id;
-    if (islower(name[0])) {
-	name[0] = toupper(name[0]);
-	id = rb_intern(name);
-	name[0] = tolower(name[0]);
-	return id;
-    }
-    else {
-	return rb_intern(name);
-    }
-}
-
-static void
-bs_parse_cb(bs_parser_t *parser, const char *path, bs_element_type_t type, 
-            void *value, void *ctx)
-{
-    bool do_not_free = false;
-    CFMutableDictionaryRef rb_cObject_dict = (CFMutableDictionaryRef)ctx;
-
-    switch (type) {
-	case BS_ELEMENT_ENUM:
-	{
-	    bs_element_enum_t *bs_enum = (bs_element_enum_t *)value;
-	    ID name = generate_const_name(bs_enum->name);
-	    if (!CFDictionaryGetValueIfPresent(
-		(CFDictionaryRef)rb_cObject_dict, (const void *)name, NULL)) {
-		VALUE val = strchr(bs_enum->value, '.') != NULL
-		    ? rb_float_new(rb_cstr_to_dbl(bs_enum->value, 1))
-		    : rb_cstr_to_inum(bs_enum->value, 10, 1);
-		CFDictionarySetValue(rb_cObject_dict, (const void *)name, 
-			(const void *)val);
-	    }
-	    else {
-		rb_warning("bs: enum `%s' already defined", rb_id2name(name));
-	    }
-	    break;
-	}
-
-	case BS_ELEMENT_CONSTANT:
-	{
-	    bs_element_constant_t *bs_const = (bs_element_constant_t *)value;
-	    ID name = generate_const_name(bs_const->name);
-	    if (!CFDictionaryGetValueIfPresent(
-		(CFDictionaryRef)rb_cObject_dict, (const void *)name, NULL)) {
-		st_insert(bs_constants, (st_data_t)name, (st_data_t)bs_const);
-		CFDictionarySetValue(rb_cObject_dict, (const void *)name, 
-			(const void *)bs_const_magic_cookie);
-		do_not_free = true;
-	    }
-	    else {
-		rb_warning("bs: constant `%s' already defined", 
-			   rb_id2name(name));
-	    }
-	    break;
-	}
-
-	case BS_ELEMENT_STRING_CONSTANT:
-	{
-	    bs_element_string_constant_t *bs_strconst = 
-		(bs_element_string_constant_t *)value;
-	    ID name = generate_const_name(bs_strconst->name);
-	    if (!CFDictionaryGetValueIfPresent(
-		(CFDictionaryRef)rb_cObject_dict, (const void *)name, NULL)) {
-		VALUE val;
-	    	if (bs_strconst->nsstring) {
-		    CFStringRef string;
-		    string = CFStringCreateWithCString(
-			NULL, bs_strconst->value, kCFStringEncodingUTF8);
-		    val = (VALUE)string;
-	    	}
-	    	else {
-		    val = rb_str_new2(bs_strconst->value);
-	    	}
-		CFDictionarySetValue(rb_cObject_dict, (const void *)name, 
-			(const void *)val);
-	    }
-	    else {
-		rb_warning("bs: string constant `%s' already defined", 
-			   rb_id2name(name));
-	    }
-	    break;
-	}
-
-	case BS_ELEMENT_FUNCTION:
-	{
-	    bs_element_function_t *bs_func = (bs_element_function_t *)value;
-	    ID name = rb_intern(bs_func->name);
-	    if (!st_lookup(bs_functions, (st_data_t)name, NULL)) {
-		st_insert(bs_functions, (st_data_t)name, (st_data_t)bs_func);
-		do_not_free = true;
-	    }
-	    else {
-		rb_warning("bs: function `%s' already defined", bs_func->name);
-	    }
-	    break;
-	}
-
-	case BS_ELEMENT_FUNCTION_ALIAS:
-	{
-	    bs_element_function_alias_t *bs_func_alias = 
-		(bs_element_function_alias_t *)value;
-	    bs_element_function_t *bs_func_original;
-	    if (st_lookup(bs_functions, 
-		(st_data_t)rb_intern(bs_func_alias->original), 
-		(st_data_t *)&bs_func_original)) {
-		st_insert(bs_functions, 
-			(st_data_t)rb_intern(bs_func_alias->name), 
-			(st_data_t)bs_func_original);
-	    }
-	    else {
-		rb_raise(rb_eRuntimeError, 
-			"cannot alias '%s' to '%s' because it doesn't exist", 
-			bs_func_alias->name, bs_func_alias->original);
-	    }
-	    break;
-	}
-
-	case BS_ELEMENT_OPAQUE:
-	case BS_ELEMENT_STRUCT:
-	{
-	    setup_bs_boxed_type(type, value);
-	    do_not_free = true;
-	    break;
-	}
-
-	case BS_ELEMENT_CLASS:
-	{
-	    bs_element_class_t *bs_class = (bs_element_class_t *)value;
-	    bs_element_indexed_class_t *bs_class_new;
-	    unsigned i;
-
-	    if (!st_lookup(bs_classes, (st_data_t)bs_class->name, 
-		(st_data_t *)&bs_class_new)) {
-		bs_class_new = (bs_element_indexed_class_t *)
-		    malloc(sizeof(bs_element_indexed_class_t));
-
-		bs_class_new->name = bs_class->name;
-		bs_class_new->cmethods = bs_class_new->imethods = NULL;
-
-		st_insert(bs_classes, (st_data_t)bs_class_new->name, 
-		    (st_data_t)bs_class_new);
-	    }
-
-#define INDEX_METHODS(table, ary, len) \
-    do { \
-	if (len > 0) { \
-	    if (table == NULL) { \
-	        table = st_init_numtable(); \
-		rb_objc_retain(table); \
-	    } \
-	    for (i = 0; i < len; i++) { \
-		bs_element_method_t *method = &ary[i]; \
-		st_insert(table, (st_data_t)method->name, (st_data_t)method); \
-	    } \
-	} \
-    } \
-    while (0)
-
-	    INDEX_METHODS(bs_class_new->cmethods, bs_class->class_methods,
-		bs_class->class_methods_count);
-
-	    INDEX_METHODS(bs_class_new->imethods, bs_class->instance_methods,
-		bs_class->instance_methods_count);
-
-#undef INDEX_METHODS
-
-	    free(bs_class);
-	    do_not_free = true;
-	    break;
-	}
-
-	case BS_ELEMENT_INFORMAL_PROTOCOL_METHOD:
-	{
-	    bs_element_informal_protocol_method_t *bs_inf_prot_method = 
-		(bs_element_informal_protocol_method_t *)value;
-	    struct st_table *t = bs_inf_prot_method->class_method
-		? bs_inf_prot_cmethods
-		: bs_inf_prot_imethods;
-
-	    st_insert(t, (st_data_t)bs_inf_prot_method->name,
-		(st_data_t)bs_inf_prot_method->type);
-
-	    free(bs_inf_prot_method->protocol_name);
-	    free(bs_inf_prot_method);
-	    do_not_free = true;
-	    break;
-	}
-
-	case BS_ELEMENT_CFTYPE:
-	{
-	    bs_element_cftype_t *bs_cftype = (bs_element_cftype_t *)value;
-	    st_insert(bs_cftypes, (st_data_t)bs_cftype->type, 
-		    (st_data_t)bs_cftype);
-	    do_not_free = true;
-	    break;
-	}
-    }
-
-    if (!do_not_free)
-	bs_element_free(type, value);
-}
-
-static bs_parser_t *bs_parser = NULL;
-
-static void
-rb_objc_load_bridge_support(const char *path, const char *framework_path,
-			    int options)
-{
-    char *error;
-    bool ok;
-    CFMutableDictionaryRef rb_cObject_dict;  
-
-    if (bs_parser == NULL) {
-	bs_parser = bs_parser_new();
-    }
-
-    rb_cObject_dict = rb_class_ivar_dict(rb_cObject);
-    assert(rb_cObject_dict != NULL);
-
-    ok = bs_parser_parse(bs_parser, path, framework_path, options,
-			 bs_parse_cb, rb_cObject_dict, &error);
-    if (!ok) {
-	rb_raise(rb_eRuntimeError, "%s", error);
-    }
-#if MAC_OS_X_VERSION_MAX_ALLOWED <= 1060
-    /* XXX we should introduce the possibility to write prelude scripts per
-     * frameworks where this kind of changes could be located.
-     */
-#if defined(__LP64__)
-    static bool R6399046_fixed = false;
-    /* XXX work around for <rdar://problem/6399046> NSNotFound 64-bit value is incorrect */
-    if (!R6399046_fixed) {
-	ID nsnotfound = rb_intern("NSNotFound");
-	VALUE val = 
-	    (VALUE)CFDictionaryGetValue(rb_cObject_dict, (void *)nsnotfound);
-	if ((VALUE)val == INT2FIX(-1)) {
-	    CFDictionarySetValue(rb_cObject_dict, 
-		    (const void *)nsnotfound,
-		    (const void *)ULL2NUM(NSNotFound));
-	    R6399046_fixed = true;
-	    DLOG("XXX", "applied work-around for rdar://problem/6399046");
-	}
-    }
 #endif
-    static bool R6401816_fixed = false;
-    /* XXX work around for <rdar://problem/6401816> -[NSObject performSelector:withObject:] has wrong sel_of_type attributes*/
-    if (!R6401816_fixed) {
-	bs_element_method_t *bs_method = 
-	    rb_bs_find_method((Class)rb_cNSObject, 
-			      @selector(performSelector:withObject:));
-	if (bs_method != NULL) {
-	    bs_element_arg_t *arg = bs_method->args;
-	    while (arg != NULL) {
-		if (arg->index == 0 
-		    && arg->sel_of_type != NULL
-		    && arg->sel_of_type[0] != '@') {
-		    arg->sel_of_type[0] = '@';
-		    R6401816_fixed = true;
-		    DLOG("XXX", "applied work-around for rdar://problem/6401816");
-		    break;
-		}
-		arg++;
-	    }
-	}	
-    }
-#endif
-}
 
 static VALUE
 rb_objc_load_bs(VALUE recv, SEL sel, VALUE path)
 {
-    rb_objc_load_bridge_support(StringValuePtr(path), NULL, 0);
+    rb_vm_load_bridge_support(StringValuePtr(path), NULL, 0);
     return recv;
 }
 
@@ -2844,7 +2583,7 @@
     char path[PATH_MAX];
 
     if (bs_find_path(framework_path, path, sizeof path)) {
-	rb_objc_load_bridge_support(path, framework_path,
+	rb_vm_load_bridge_support(path, framework_path,
                                     BS_PARSE_OPTIONS_LOAD_DYLIBS);
     }
 }
@@ -3670,7 +3409,7 @@
 
 - (void)loadBridgeSupportFileAtPath:(NSString *)path
 {
-    rb_objc_load_bridge_support([path fileSystemRepresentation], NULL, 0);
+    rb_vm_load_bridge_support([path fileSystemRepresentation], NULL, 0);
 }
 
 - (void)loadBridgeSupportFileAtURL:(NSURL *)URL

Modified: MacRuby/branches/experimental/roxor.cpp
===================================================================
--- MacRuby/branches/experimental/roxor.cpp	2009-04-20 23:30:02 UTC (rev 1432)
+++ MacRuby/branches/experimental/roxor.cpp	2009-04-21 02:11:23 UTC (rev 1433)
@@ -40,6 +40,7 @@
 #include "objc.h"
 #include "roxor.h"
 #include <execinfo.h>
+#include <dlfcn.h>
 
 #define FROM_GV(gv,t) ((t)(gv.IntVal.getZExtValue()))
 static GenericValue
@@ -249,6 +250,7 @@
 	Function *catArrayFunc;
 	Function *dupArrayFunc;
 	Function *newArrayFunc;
+	Function *newStructFunc;
 	Function *newRangeFunc;
 	Function *newRegexpFunc;
 	Function *strInternFunc;
@@ -330,10 +332,12 @@
 	void compile_landing_pad_footer(void);
 	void compile_rethrow_exception(void);
 	Value *compile_lvar_slot(ID name);
+	Value *compile_new_struct(VALUE klass, std::vector<Value *> &fields);
 
-	Value *compile_conversion_to_c(const char *type, Value *val, Value *slot);
-	Value *compile_conversion_to_ruby(const char *type, const Type *llvm_type, 
-		Value *val);
+	Value *compile_conversion_to_c(const char *type, Value *val,
+				       Value *slot);
+	Value *compile_conversion_to_ruby(const char *type,
+					  const Type *llvm_type, Value *val);
 
 	int *get_slot_cache(ID id) {
 	    if (current_block || !current_instance_method || current_module) {
@@ -422,6 +426,18 @@
     NODE *node;
 } rb_vm_method_source_t;
 
+typedef struct {
+    bs_element_type_t bs_type;
+    bool is_struct(void) { return bs_type == BS_ELEMENT_STRUCT; }
+    union {
+	bs_element_struct_t *s;
+	bs_element_opaque_t *o;
+	void *v;
+    } as;
+    Type *type;
+    VALUE klass;
+} rb_vm_bs_boxed_t;
+
 class RoxorVM
 {
     private:
@@ -465,6 +481,16 @@
 
 	std::map<std::string, void *> c_stubs, objc_stubs;
 
+	bs_parser_t *bs_parser;
+	std::map<std::string, rb_vm_bs_boxed_t *> bs_boxed;
+	std::map<ID, bs_element_function_t *> bs_funcs;
+	std::map<ID, bs_element_constant_t *> bs_consts;
+	std::map<std::string, std::map<SEL, bs_element_method_t *> *>
+	    bs_classes_class_methods, bs_classes_instance_methods;
+
+	bs_element_method_t *find_bs_method(Class klass, SEL sel);
+	rb_vm_bs_boxed_t *find_bs_struct(std::string type);
+
 #if ROXOR_ULTRA_LAZY_JIT
 	std::map<SEL, std::map<Class, rb_vm_method_source_t *> *>
 	    method_sources;
@@ -617,6 +643,7 @@
     catArrayFunc = NULL;
     dupArrayFunc = NULL;
     newArrayFunc = NULL;
+    newStructFunc = NULL;
     newRangeFunc = NULL;
     newRegexpFunc = NULL;
     strInternFunc = NULL;
@@ -2425,6 +2452,8 @@
     loaded_features = rb_ary_new();
     rb_objc_retain((void *)loaded_features);
 
+    bs_parser = NULL;
+
     emp = new ExistingModuleProvider(RoxorCompiler::module);
     jmm = new RoxorJITManager;
     ee = ExecutionEngine::createJIT(emp, 0, jmm, true);
@@ -4913,10 +4942,49 @@
     return ULL2NUM(l);
 }
 
+extern "C"
+VALUE
+rb_vm_new_struct(VALUE klass, int argc, ...)
+{
+    assert(argc > 0);
+
+    va_list ar;
+    va_start(ar, argc);
+    VALUE *data = (VALUE *)xmalloc(argc * sizeof(VALUE));
+    for (int i = 0; i < argc; ++i) {
+	VALUE field = va_arg(ar, VALUE);
+	GC_WB(&data[i], field);
+    }
+    va_end(ar);
+
+    return Data_Wrap_Struct(klass, NULL, NULL, data);
+}
+
 Value *
-RoxorCompiler::compile_conversion_to_ruby(const char *type, const Type *llvm_type,
-					  Value *val)
+RoxorCompiler::compile_new_struct(VALUE klass, std::vector<Value *> &fields)
 {
+    if (newStructFunc == NULL) {
+	std::vector<const Type *> types;
+	types.push_back(RubyObjTy);
+	types.push_back(Type::Int32Ty);
+	FunctionType *ft = FunctionType::get(RubyObjTy, types, true);
+
+	newStructFunc = cast<Function>(module->getOrInsertFunction(
+		    "rb_vm_new_struct", ft));
+    }
+
+    fields.insert(fields.begin(),
+	    ConstantInt::get(Type::Int32Ty, fields.size()));
+    fields.insert(fields.begin(), ConstantInt::get(RubyObjTy, klass));
+
+    return CallInst::Create(newStructFunc, fields.begin(), fields.end(),
+	    "", bb); 
+}
+
+Value *
+RoxorCompiler::compile_conversion_to_ruby(const char *type,
+					  const Type *llvm_type, Value *val)
+{
     const char *func_name = NULL;
 
     switch (*type) {
@@ -4977,10 +5045,31 @@
 	    func_name = "rb_float_new";
 	    break;
 
-	default:
-	    printf("unrecognized compile type `%s' to Ruby - aborting\n", type);
-	    abort();
+	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;
+
+		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));
+		}
+
+		return compile_new_struct(bs_boxed->klass, params);
+	    }
+	    break;
     }
+
+    if (func_name == NULL) {
+	printf("unrecognized compile type `%s' to Ruby - aborting\n", type);
+	abort();
+    }
  
     std::vector<Value *> params;
     params.push_back(val);
@@ -5036,6 +5125,24 @@
 	case _C_LNG_LNG:
 	case _C_ULNG_LNG:
 	    return Type::Int64Ty;
+
+	case _C_STRUCT_B:
+	    rb_vm_bs_boxed_t *bs_boxed = GET_VM()->find_bs_struct(type);
+	    if (bs_boxed != NULL) {
+		if (bs_boxed->type == NULL) {
+		    std::vector<const Type *> s_types;
+		    for (unsigned i = 0; i < bs_boxed->as.s->fields_count;
+			 i++) {
+
+			const char *ftype = bs_boxed->as.s->fields[i].type;
+			s_types.push_back(convert_type(ftype));
+		    }
+		    bs_boxed->type = StructType::get(s_types);
+		    assert(bs_boxed->type != NULL);
+		}
+		return bs_boxed->type;
+	    }
+	    break;
     }
 
     printf("unrecognized runtime type `%s' - aborting\n", type);
@@ -5102,7 +5209,8 @@
     Value *imp = new BitCastInst(imp_arg, PointerType::getUnqual(ft), "", bb);
 
     // Compile call.
-    CallInst *imp_call = CallInst::Create(imp, params.begin(), params.end(), "", bb); 
+    CallInst *imp_call = CallInst::Create(imp, params.begin(), params.end(),
+	    "", bb); 
 
     // Compile retval.
     GetFirstType(types, buf, sizeof buf);
@@ -6434,7 +6542,7 @@
 		cache->flag = MCACHE_OCALL;
 		ocache.klass = klass;
 		ocache.imp = imp;
-		ocache.bs_method = rb_bs_find_method(klass, sel);
+		ocache.bs_method = GET_VM()->find_bs_method(klass, sel);
 
 		char types[200];
 		if (!rb_objc_get_types(self, klass, sel, ocache.bs_method,
@@ -7749,6 +7857,439 @@
     return Qnil; // never reached
 }
 
+// BridgeSupport implementation
+
+static inline ID
+generate_const_name(char *name)
+{
+    ID id;
+    if (islower(name[0])) {
+	name[0] = toupper(name[0]);
+	id = rb_intern(name);
+	name[0] = tolower(name[0]);
+	return id;
+    }
+    else {
+	return rb_intern(name);
+    }
+}
+
+static VALUE bs_const_magic_cookie = Qnil;
+
+extern "C"
+VALUE
+rb_vm_resolve_const_value(VALUE v, VALUE klass, ID id)
+{
+    void *sym;
+    bs_element_constant_t *bs_const;
+
+    if (v == bs_const_magic_cookie) {
+	std::map<ID, bs_element_constant_t *>::iterator iter =
+	    GET_VM()->bs_consts.find(id);
+	if (iter == GET_VM()->bs_consts.end()) {
+	    rb_bug("unresolved BridgeSupport constant `%s'",
+		    rb_id2name(id));
+	}
+	bs_const = iter->second;
+
+	sym = dlsym(RTLD_DEFAULT, bs_const->name);
+	if (sym == NULL) {
+	    rb_bug("cannot locate symbol for BridgeSupport constant `%s'",
+		    bs_const->name);
+	}
+
+	// TODO
+	//rb_objc_ocval_to_rval(sym, bs_const->type, &v);
+	v = INT2FIX(42);
+
+	CFMutableDictionaryRef iv_dict = rb_class_ivar_dict(rb_cObject);
+	assert(iv_dict != NULL);
+	CFDictionarySetValue(iv_dict, (const void *)id, (const void *)v);
+    }
+
+    return v;
+}
+
+#define GEN_STRUCT_READER(idx) \
+    static VALUE rb_vm_struct_reader_##idx (VALUE self, SEL sel) { \
+	VALUE *data; \
+	Data_Get_Struct(self, VALUE, data); \
+	return data[idx]; \
+    } \
+
+GEN_STRUCT_READER(0);  GEN_STRUCT_READER(1);  GEN_STRUCT_READER(2);
+GEN_STRUCT_READER(3);  GEN_STRUCT_READER(4);  GEN_STRUCT_READER(5);
+GEN_STRUCT_READER(6);  GEN_STRUCT_READER(7);  GEN_STRUCT_READER(8);
+GEN_STRUCT_READER(9);  GEN_STRUCT_READER(10); GEN_STRUCT_READER(11);
+GEN_STRUCT_READER(12); GEN_STRUCT_READER(13); GEN_STRUCT_READER(14);
+GEN_STRUCT_READER(15); GEN_STRUCT_READER(16); GEN_STRUCT_READER(17);
+GEN_STRUCT_READER(18); GEN_STRUCT_READER(19);
+
+#define BS_STRUCT_MAX_FIELDS 20
+typedef VALUE rb_vm_struct_reader_t(VALUE, SEL);
+static rb_vm_struct_reader_t *struct_readers[] = {
+    rb_vm_struct_reader_0,  rb_vm_struct_reader_1,  rb_vm_struct_reader_2,
+    rb_vm_struct_reader_3,  rb_vm_struct_reader_4,  rb_vm_struct_reader_5,
+    rb_vm_struct_reader_6,  rb_vm_struct_reader_7,  rb_vm_struct_reader_8,
+    rb_vm_struct_reader_9,  rb_vm_struct_reader_10, rb_vm_struct_reader_11,
+    rb_vm_struct_reader_12, rb_vm_struct_reader_13, rb_vm_struct_reader_14,
+    rb_vm_struct_reader_15, rb_vm_struct_reader_16, rb_vm_struct_reader_17,
+    rb_vm_struct_reader_18, rb_vm_struct_reader_19
+};
+
+static bool
+register_bs_boxed(bs_element_type_t type, void *value)
+{
+    std::string octype(((bs_element_opaque_t *)value)->type);
+
+    std::map<std::string, rb_vm_bs_boxed_t *>::iterator iter =
+	GET_VM()->bs_boxed.find(octype);
+
+    if (iter != GET_VM()->bs_boxed.end()) {
+	return false;
+    }
+
+    rb_vm_bs_boxed_t *boxed = (rb_vm_bs_boxed_t *)malloc(
+	    sizeof(rb_vm_bs_boxed_t));
+
+    boxed->bs_type = type;
+    boxed->as.v = value;
+    boxed->type = NULL; // lazy
+    boxed->klass = rb_define_class(((bs_element_opaque_t *)value)->name,
+	    rb_cBoxed);
+
+    if (type == BS_ELEMENT_STRUCT) {
+	assert(boxed->as.s->fields_count < BS_STRUCT_MAX_FIELDS);
+	for (unsigned i = 0; i < boxed->as.s->fields_count; i++) {
+	    rb_objc_define_method(boxed->klass, boxed->as.s->fields[i].name,
+		    (void *)struct_readers[i], 0);
+	}
+    }
+
+    GET_VM()->bs_boxed[octype] = boxed;
+
+    return true;
+}
+
+static inline void
+index_bs_class_methods(const char *name,
+	std::map<std::string, std::map<SEL, bs_element_method_t *> *> &map,
+	bs_element_method_t *methods,
+	unsigned method_count)
+{
+    std::map<std::string, std::map<SEL, bs_element_method_t *> *>::iterator
+	iter = map.find(name);
+
+    std::map<SEL, bs_element_method_t *> *methods_map = NULL;	
+    if (iter == map.end()) {
+	methods_map = new std::map<SEL, bs_element_method_t *>();
+	map[name] = methods_map;
+    }
+    else {
+	methods_map = iter->second;
+    }
+
+    for (unsigned i = 0; i < method_count; i++) {
+	bs_element_method_t *m = &methods[i];
+	methods_map->insert(std::make_pair(m->name, m));
+    }
+} 
+
+inline bs_element_method_t *
+RoxorVM::find_bs_method(Class klass, SEL sel)
+{
+    std::map<std::string, std::map<SEL, bs_element_method_t *> *> &map =
+	class_isMetaClass(klass) ? bs_classes_class_methods
+	: bs_classes_instance_methods;
+
+    std::map<std::string, std::map<SEL, bs_element_method_t *> *>::iterator
+	iter = map.find(class_getName(klass));
+
+    if (iter == map.end()) {
+	return NULL;
+    }
+
+    std::map<SEL, bs_element_method_t *> *map2 = iter->second;
+    std::map<SEL, bs_element_method_t *>::iterator iter2 = map2->find(sel);
+
+    if (iter2 == map2->end()) {
+	return NULL;
+    }
+
+    return iter2->second;
+}
+
+inline rb_vm_bs_boxed_t *
+RoxorVM::find_bs_struct(std::string type)
+{
+    std::map<std::string, rb_vm_bs_boxed_t *>::iterator iter =
+	bs_boxed.find(type);
+
+    if (iter == bs_boxed.end()) {
+	return NULL;
+    }
+
+    rb_vm_bs_boxed_t *boxed = iter->second;
+    return boxed->is_struct() ? boxed : NULL; 
+}
+
+static inline void
+register_bs_class(bs_element_class_t *bs_class)
+{
+    if (bs_class->class_methods_count > 0) {
+	index_bs_class_methods(bs_class->name,
+		GET_VM()->bs_classes_class_methods,
+		bs_class->class_methods,
+		bs_class->class_methods_count);
+    }
+    if (bs_class->instance_methods_count > 0) {
+	index_bs_class_methods(bs_class->name,
+		GET_VM()->bs_classes_instance_methods,
+		bs_class->instance_methods,
+		bs_class->instance_methods_count);
+    }
+}
+
+static void
+bs_parse_cb(bs_parser_t *parser, const char *path, bs_element_type_t type, 
+            void *value, void *ctx)
+{
+    bool do_not_free = false;
+    CFMutableDictionaryRef rb_cObject_dict = (CFMutableDictionaryRef)ctx;
+
+    switch (type) {
+	case BS_ELEMENT_ENUM:
+	{
+	    bs_element_enum_t *bs_enum = (bs_element_enum_t *)value;
+	    ID name = generate_const_name(bs_enum->name);
+	    if (!CFDictionaryGetValueIfPresent(rb_cObject_dict,
+			(const void *)name, NULL)) {
+
+		VALUE val = strchr(bs_enum->value, '.') != NULL
+		    ? rb_float_new(rb_cstr_to_dbl(bs_enum->value, 1))
+		    : rb_cstr_to_inum(bs_enum->value, 10, 1);
+		CFDictionarySetValue(rb_cObject_dict, (const void *)name, 
+			(const void *)val);
+	    }
+	    else {
+		rb_warning("bs: enum `%s' already defined", rb_id2name(name));
+	    }
+	    break;
+	}
+
+	case BS_ELEMENT_CONSTANT:
+	{
+	    bs_element_constant_t *bs_const = (bs_element_constant_t *)value;
+	    ID name = generate_const_name(bs_const->name);
+	    if (!CFDictionaryGetValueIfPresent(rb_cObject_dict,
+			(const void *)name, NULL)) {
+
+		GET_VM()->bs_consts[name] = bs_const;
+		CFDictionarySetValue(rb_cObject_dict, (const void *)name, 
+			(const void *)bs_const_magic_cookie);
+		do_not_free = true;
+	    }
+	    else {
+		rb_warning("bs: constant `%s' already defined", 
+			   rb_id2name(name));
+	    }
+	    break;
+	}
+
+	case BS_ELEMENT_STRING_CONSTANT:
+	{
+	    bs_element_string_constant_t *bs_strconst = 
+		(bs_element_string_constant_t *)value;
+	    ID name = generate_const_name(bs_strconst->name);
+	    if (!CFDictionaryGetValueIfPresent(rb_cObject_dict,
+			(const void *)name, NULL)) {
+
+		VALUE val;
+#if 0 // this is likely not needed anymore
+	    	if (bs_strconst->nsstring) {
+		    CFStringRef string = CFStringCreateWithCString(NULL,
+			    bs_strconst->value, kCFStringEncodingUTF8);
+		    val = (VALUE)string;
+	    	}
+	    	else {
+#endif
+		    val = rb_str_new2(bs_strconst->value);
+//	    	}
+		CFDictionarySetValue(rb_cObject_dict, (const void *)name, 
+			(const void *)val);
+	    }
+	    else {
+		rb_warning("bs: string constant `%s' already defined", 
+			   rb_id2name(name));
+	    }
+	    break;
+	}
+
+	case BS_ELEMENT_FUNCTION:
+	{
+	    bs_element_function_t *bs_func = (bs_element_function_t *)value;
+	    ID name = rb_intern(bs_func->name);
+
+	    std::map<ID, bs_element_function_t *>::iterator iter =
+		GET_VM()->bs_funcs.find(name);
+	    if (iter == GET_VM()->bs_funcs.end()) {
+		GET_VM()->bs_funcs[name] = bs_func;
+		do_not_free = true;
+	    }
+	    else {
+		rb_warning("bs: function `%s' already defined", bs_func->name);
+	    }
+	    break;
+	}
+
+	case BS_ELEMENT_FUNCTION_ALIAS:
+	{
+#if 0 // TODO
+	    bs_element_function_alias_t *bs_func_alias = 
+		(bs_element_function_alias_t *)value;
+	    bs_element_function_t *bs_func_original;
+	    if (st_lookup(bs_functions, 
+			(st_data_t)rb_intern(bs_func_alias->original), 
+			(st_data_t *)&bs_func_original)) {
+		st_insert(bs_functions, 
+			(st_data_t)rb_intern(bs_func_alias->name), 
+			(st_data_t)bs_func_original);
+	    }
+	    else {
+		rb_raise(rb_eRuntimeError, 
+			"cannot alias '%s' to '%s' because it doesn't exist", 
+			bs_func_alias->name, bs_func_alias->original);
+	    }
+#endif
+	    break;
+	}
+
+	case BS_ELEMENT_OPAQUE:
+	case BS_ELEMENT_STRUCT:
+	{
+	    if (register_bs_boxed(type, value)) {
+		do_not_free = true;
+	    }
+	    else {
+		rb_warning("bs: boxed `%s' already defined",
+			((bs_element_opaque_t *)value)->name);
+	    }
+	    break;
+	}
+
+	case BS_ELEMENT_CLASS:
+	{
+	    bs_element_class_t *bs_class = (bs_element_class_t *)value;
+	    register_bs_class(bs_class);
+	    free(bs_class);
+	    do_not_free = true;
+	    break;
+	}
+
+	case BS_ELEMENT_INFORMAL_PROTOCOL_METHOD:
+	{
+#if 0
+	    bs_element_informal_protocol_method_t *bs_inf_prot_method = 
+		(bs_element_informal_protocol_method_t *)value;
+	    struct st_table *t = bs_inf_prot_method->class_method
+		? bs_inf_prot_cmethods
+		: bs_inf_prot_imethods;
+
+	    st_insert(t, (st_data_t)bs_inf_prot_method->name,
+		(st_data_t)bs_inf_prot_method->type);
+
+	    free(bs_inf_prot_method->protocol_name);
+	    free(bs_inf_prot_method);
+	    do_not_free = true;
+#endif
+	    break;
+	}
+
+	case BS_ELEMENT_CFTYPE:
+	{
+#if 0
+	    bs_element_cftype_t *bs_cftype = (bs_element_cftype_t *)value;
+	    st_insert(bs_cftypes, (st_data_t)bs_cftype->type, 
+		    (st_data_t)bs_cftype);
+	    do_not_free = true;
+#endif
+	    break;
+	}
+    }
+
+    if (!do_not_free) {
+	bs_element_free(type, value);
+    }
+}
+
+extern "C"
+void
+rb_vm_load_bridge_support(const char *path, const char *framework_path,
+			  int options)
+{
+    char *error;
+    bool ok;
+    CFMutableDictionaryRef rb_cObject_dict;  
+
+    if (GET_VM()->bs_parser == NULL) {
+	GET_VM()->bs_parser = bs_parser_new();
+    }
+
+    rb_cObject_dict = rb_class_ivar_dict(rb_cObject);
+    assert(rb_cObject_dict != NULL);
+
+    ok = bs_parser_parse(GET_VM()->bs_parser, path, framework_path,
+			 (bs_parse_options_t)options,
+			 bs_parse_cb, rb_cObject_dict, &error);
+    if (!ok) {
+	rb_raise(rb_eRuntimeError, "%s", error);
+    }
+#if 0 //TODO //MAC_OS_X_VERSION_MAX_ALLOWED <= 1060
+    /* XXX we should introduce the possibility to write prelude scripts per
+     * frameworks where this kind of changes could be located.
+     */
+#if defined(__LP64__)
+    static bool R6399046_fixed = false;
+    /* XXX work around for <rdar://problem/6399046> NSNotFound 64-bit value is incorrect */
+    if (!R6399046_fixed) {
+	ID nsnotfound = rb_intern("NSNotFound");
+	VALUE val = 
+	    (VALUE)CFDictionaryGetValue(rb_cObject_dict, (void *)nsnotfound);
+	if ((VALUE)val == INT2FIX(-1)) {
+	    CFDictionarySetValue(rb_cObject_dict, 
+		    (const void *)nsnotfound,
+		    (const void *)ULL2NUM(NSNotFound));
+	    R6399046_fixed = true;
+	    DLOG("XXX", "applied work-around for rdar://problem/6399046");
+	}
+    }
+#endif
+    static bool R6401816_fixed = false;
+    /* XXX work around for <rdar://problem/6401816> -[NSObject performSelector:withObject:] has wrong sel_of_type attributes*/
+    if (!R6401816_fixed) {
+	bs_element_method_t *bs_method = 
+	    rb_bs_find_method((Class)rb_cNSObject, 
+			      @selector(performSelector:withObject:));
+	if (bs_method != NULL) {
+	    bs_element_arg_t *arg = bs_method->args;
+	    while (arg != NULL) {
+		if (arg->index == 0 
+		    && arg->sel_of_type != NULL
+		    && arg->sel_of_type[0] != '@') {
+		    arg->sel_of_type[0] = '@';
+		    R6401816_fixed = true;
+		    DLOG("XXX", "applied work-around for rdar://problem/6401816");
+		    break;
+		}
+		arg++;
+	    }
+	}	
+    }
+#endif
+}
+
+// stubs
+
 static VALUE
 builtin_ostub1(IMP imp, id self, SEL sel, int argc, VALUE *argv)
 {
@@ -7833,6 +8374,9 @@
     VALUE top_self = rb_obj_alloc(rb_cTopLevel);
     rb_objc_retain((void *)top_self);
     GET_VM()->current_top_object = top_self;
+
+    bs_const_magic_cookie = rb_str_new2("bs_const_magic_cookie");
+    rb_objc_retain((void *)bs_const_magic_cookie);
 }
 
 extern "C"

Modified: MacRuby/branches/experimental/roxor.h
===================================================================
--- MacRuby/branches/experimental/roxor.h	2009-04-20 23:30:02 UTC (rev 1432)
+++ MacRuby/branches/experimental/roxor.h	2009-04-21 02:11:23 UTC (rev 1433)
@@ -63,6 +63,7 @@
 void rb_vm_set_safe_level(int level);
 VALUE rb_vm_top_self(void);
 void rb_vm_const_is_defined(ID path);
+VALUE rb_vm_resolve_const_value(VALUE val, VALUE klass, ID name);
 bool rb_vm_lookup_method(Class klass, SEL sel, IMP *pimp, NODE **pnode);
 bool rb_vm_lookup_method2(Class klass, ID mid, SEL *psel, IMP *pimp, NODE **pnode);
 NODE *rb_vm_get_method_node(IMP imp);
@@ -185,6 +186,9 @@
 
 void rb_vm_finalize(void);
 
+void rb_vm_load_bridge_support(const char *path, const char *framework_path,
+	int options);
+
 VALUE rb_iseq_compile(VALUE src, VALUE file, VALUE line);
 VALUE rb_iseq_eval(VALUE iseq);
 VALUE rb_iseq_new(NODE *node, VALUE filename);

Modified: MacRuby/branches/experimental/spec/frozen/macruby/fixtures/method.m
===================================================================
--- MacRuby/branches/experimental/spec/frozen/macruby/fixtures/method.m	2009-04-20 23:30:02 UTC (rev 1432)
+++ MacRuby/branches/experimental/spec/frozen/macruby/fixtures/method.m	2009-04-21 02:11:23 UTC (rev 1433)
@@ -141,6 +141,21 @@
     return 3.1415;
 }
 
+- (NSPoint)methodReturningNSPoint
+{
+    return NSMakePoint(1, 2);
+}
+
+- (NSSize)methodReturningNSSize
+{
+    return NSMakeSize(3, 4);
+}
+
+- (NSRect)methodReturningNSRect
+{
+    return NSMakeRect(1, 2, 3, 4);
+}
+
 @end
 
 void

Modified: MacRuby/branches/experimental/spec/frozen/macruby/method_spec.rb
===================================================================
--- MacRuby/branches/experimental/spec/frozen/macruby/method_spec.rb	2009-04-20 23:30:02 UTC (rev 1432)
+++ MacRuby/branches/experimental/spec/frozen/macruby/method_spec.rb	2009-04-21 02:11:23 UTC (rev 1433)
@@ -225,8 +225,10 @@
     o = TestMethod.new
     o.methodReturningLong3.should ==
       (RUBY_ARCH == 'x86_64' ? 4611686018427387904 : 1073741824)
+    o.methodReturningLong3.class.should == Bignum
     o.methodReturningLong4.should ==
       (RUBY_ARCH == 'x86_64' ? -4611686018427387905 : -1073741825)
+    o.methodReturningLong4.class.should == Bignum
   end
 
   it "returning 'unsigned long' returns a Fixnum if possible in Ruby" do
@@ -238,15 +240,18 @@
     o = TestMethod.new
     o.methodReturningUnsignedLong2.should ==
       (RUBY_ARCH == 'x86_64' ? 4611686018427387904 : 1073741824)
+    o.methodReturningUnsignedLong2.class.should == Bignum
   end
 
   it "returning 'float' returns a Float in Ruby" do
     o = TestMethod.new
     o.methodReturningFloat.should be_close(3.1415, 0.0001)
+    o.methodReturningFloat.class.should == Float
   end
 
   it "returning 'double' returns a Float in Ruby" do
     o = TestMethod.new
     o.methodReturningDouble.should be_close(3.1415, 0.0001)
+    o.methodReturningDouble.class.should == Float
   end
 end

Modified: MacRuby/branches/experimental/variable.c
===================================================================
--- MacRuby/branches/experimental/variable.c	2009-04-20 23:30:02 UTC (rev 1432)
+++ MacRuby/branches/experimental/variable.c	2009-04-21 02:11:23 UTC (rev 1433)
@@ -1547,7 +1547,7 @@
 		rb_warn("toplevel constant %s referenced by %s::%s",
 			rb_id2name(id), rb_class2name(klass), rb_id2name(id));
 	    }
-	    value = rb_objc_resolve_const_value(value, klass, id);
+	    value = rb_vm_resolve_const_value(value, klass, id);
 	    return value;
 	}
 	if (!recurse && klass != rb_cObject) break;
@@ -1557,7 +1557,7 @@
 	    for (i = 0; i < count; i++) {
 		iv_dict = rb_class_ivar_dict(RARRAY_AT(inc_mods, i));
 		if (CFDictionaryGetValueIfPresent(iv_dict, (const void *)id, (const void **)&value))
-		    return rb_objc_resolve_const_value(value, klass, id);
+		    return rb_vm_resolve_const_value(value, klass, id);
 	    }
 	}
 	tmp = RCLASS_SUPER(tmp);
@@ -1568,10 +1568,10 @@
 	goto retry;
     }
 
-    /* Classes are typically pre-loaded by Kernel#framework and imported by
-     * rb_objc_resolve_const_value(), but it is still useful to keep the
-     * dynamic import facility, because someone in the Objective-C world may
-     * dynamically define classes at runtime (like ScriptingBridge.framework).
+    /* Classes are typically pre-loaded by Kernel#framework but it is still
+     * useful to keep the dynamic import facility, because someone in the
+     * Objective-C world may dynamically define classes at runtime (like
+     * ScriptingBridge.framework).
      *
      * Note that objc_getClass does _not_ honor namespaces. Consider:
      *
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macruby-changes/attachments/20090420/e7d9bc12/attachment-0001.html>


More information about the macruby-changes mailing list