[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