diff --git a/array.c b/array.c index 2eaeced84..40cd4299d 100644 --- a/array.c +++ b/array.c @@ -41,8 +41,10 @@ memfill(register VALUE *mem, register long size, register VALUE val) } #if WITH_OBJC +/* TODO optimize this */ struct rb_objc_ary_struct { bool frozen; + bool tainted; bool named_args; void *cptr; }; @@ -63,13 +65,29 @@ rb_objc_ary_get_struct2(VALUE ary) s = rb_objc_ary_get_struct(ary); if (s == NULL) { - s = xmalloc(sizeof(struct rb_objc_ary_struct)); - rb_objc_set_associative_ref((void *)ary, &rb_objc_ary_assoc_key, s); - s->frozen = false; - s->named_args = false; + s = xmalloc(sizeof(struct rb_objc_ary_struct)); + rb_objc_set_associative_ref((void *)ary, &rb_objc_ary_assoc_key, s); + s->frozen = false; + s->tainted = false; + s->named_args = false; + s->cptr = NULL; } return s; } + +static void +rb_objc_ary_copy_struct(VALUE old, VALUE new) +{ + struct rb_objc_ary_struct *s; + + s = rb_objc_ary_get_struct(old); + if (s != NULL) { + struct rb_objc_ary_struct *n; + + n = rb_objc_ary_get_struct2(new); + memcpy(n, s, sizeof(struct rb_objc_ary_struct)); + } +} #else #define ARY_SHARED_P(a) FL_TEST(a, ELTS_SHARED) @@ -129,6 +147,22 @@ rb_ary_freeze(VALUE ary) #endif } +#if WITH_OBJC +VALUE +rb_ary_taint(VALUE ary) +{ + rb_objc_ary_get_struct2(ary)->tainted = true; + return ary; +} + +VALUE +rb_ary_tainted(VALUE ary) +{ + struct rb_objc_ary_struct *s = rb_objc_ary_get_struct(ary); + return s != NULL && s->tainted ? Qtrue : Qfalse; +} +#endif + /* * call-seq: * array.frozen? -> true or false @@ -273,9 +307,7 @@ rb_ary_new4(long n, const VALUE *elts) ary = rb_ary_new2(n); if (n > 0 && elts) { #if WITH_OBJC - long i; - for (i = 0; i < n; i++) - rb_ary_insert(ary, i, elts[i]); + CFArrayReplaceValues((CFMutableArrayRef)ary, CFRangeMake(0, 0), (const void **)elts, n); #else MEMCPY(RARRAY_PTR(ary), elts, VALUE, n); RARRAY(ary)->len = n; @@ -1523,10 +1555,10 @@ rb_ary_empty_p(VALUE ary) return Qfalse; } -VALUE -rb_ary_dup(VALUE ary) -{ #if WITH_OBJC +static inline VALUE +rb_ary_dup2(VALUE ary) +{ VALUE klass, dup; long n; @@ -1536,6 +1568,24 @@ rb_ary_dup(VALUE ary) if (n > 0) CFArrayAppendArray((CFMutableArrayRef)dup, (CFArrayRef)ary, CFRangeMake(0, n)); + return dup; +} + +VALUE +rb_ary_clone(VALUE ary) +{ + VALUE dup = rb_ary_dup2(ary); + rb_objc_ary_copy_struct(ary, dup); + return dup; +} +#endif + +VALUE +rb_ary_dup(VALUE ary) +{ +#if WITH_OBJC + VALUE dup = rb_ary_dup2(ary); + /* copy the named_args flag, but not other flags */ if (rb_ary_is_named_args(ary)) rb_ary_set_named_args(dup, true); #else @@ -3692,7 +3742,9 @@ rb_ary_combination(VALUE ary, VALUE num) volatile VALUE cc = rb_ary_new2(n); long lev = 0; +#if !WITH_OBJC RBASIC(cc)->klass = 0; +#endif MEMZERO(stack, long, n); stack[0] = -1; for (i = 0; i < nlen; i++) { @@ -3700,7 +3752,11 @@ rb_ary_combination(VALUE ary, VALUE num) for (lev++; lev < n; lev++) { rb_ary_store(cc, lev, RARRAY_AT(ary, stack[lev+1] = stack[lev]+1)); } +#if WITH_OBJC + rb_yield(rb_ary_dup(cc)); +#else rb_yield(cc); +#endif do { stack[lev--]++; } while (lev && (stack[lev+1]+n == len+lev+1)); @@ -3925,6 +3981,8 @@ Init_Array(void) FL_UNSET(rb_cArrayRuby, RCLASS_OBJC_IMPORTED); rb_const_set(rb_cObject, rb_intern("Array"), rb_cArrayRuby); rb_define_method(rb_cArray, "freeze", rb_ary_freeze, 0); + rb_define_method(rb_cArray, "taint", rb_ary_taint, 0); + rb_define_method(rb_cArray, "tainted?", rb_ary_tainted, 0); #else rb_cArray = rb_define_class("Array", rb_cObject); #endif diff --git a/enumerator.c b/enumerator.c index 1dda293f5..744ee3fbf 100644 --- a/enumerator.c +++ b/enumerator.c @@ -241,7 +241,7 @@ enumerator_init(VALUE enum_obj, VALUE obj, VALUE meth, int argc, VALUE *argv) else { ptr->iter = enumerator_each_i; } - if (argc) ptr->args = rb_ary_new4(argc, argv); + if (argc) GC_WB(&ptr->args, rb_ary_new4(argc, argv)); ptr->fib = 0; ptr->dst = Qnil; ptr->no_next = Qfalse; diff --git a/hash.c b/hash.c index 69c1cd6f0..ccb0ffad8 100644 --- a/hash.c +++ b/hash.c @@ -260,10 +260,12 @@ rb_cfdictionary_release_cb(CFAllocatorRef allocator, const void *v) rb_objc_release(v); } +/* TODO optimize me */ struct rb_objc_hash_struct { VALUE ifnone; bool has_proc_default; bool frozen; + bool tainted; }; /* This variable will always stay NULL, we only use its address. */ @@ -287,6 +289,7 @@ rb_objc_hash_get_struct2(VALUE hash) s->ifnone = Qnil; s->has_proc_default = false; s->frozen = false; + s->tainted = false; } return s; } @@ -312,6 +315,27 @@ rb_hash_frozen(VALUE hash) return s != NULL && s->frozen ? Qtrue : Qfalse; } +VALUE +rb_hash_taint(VALUE hash) +{ + struct rb_objc_hash_struct *s; + + s = rb_objc_hash_get_struct2(hash); + s->tainted = true; + + return hash; +} + +VALUE +rb_hash_tainted(VALUE hash) +{ + struct rb_objc_hash_struct *s; + + s = rb_objc_hash_get_struct(hash); + + return s != NULL && s->tainted ? Qtrue : Qfalse; +} + static void rb_objc_hash_set_struct(VALUE hash, VALUE ifnone, bool has_proc_default) { @@ -322,6 +346,19 @@ rb_objc_hash_set_struct(VALUE hash, VALUE ifnone, bool has_proc_default) GC_WB(&s->ifnone, ifnone); s->has_proc_default = has_proc_default; } + +VALUE +rb_hash_clone(VALUE hash) +{ +#if 0 // TODO + VALUE klass, dup; + long n; + + klass = rb_obj_class(ary); + dup = hash_alloc(klass); +#endif + return Qnil; +} #endif static VALUE @@ -3046,6 +3083,8 @@ Init_Hash(void) rb_const_set(rb_cObject, rb_intern("Hash"), rb_cHashRuby); rb_define_method(rb_cHash, "freeze", rb_hash_freeze, 0); rb_define_method(rb_cHash, "frozen?", rb_hash_frozen, 0); + rb_define_method(rb_cHash, "taint", rb_hash_taint, 0); + rb_define_method(rb_cHash, "tainted?", rb_hash_tainted, 0); #else rb_cHash = rb_define_class("Hash", rb_cObject); #endif diff --git a/include/ruby/intern.h b/include/ruby/intern.h index 0b5a3b665..5a60d5594 100644 --- a/include/ruby/intern.h +++ b/include/ruby/intern.h @@ -81,6 +81,7 @@ VALUE rb_get_values_at(VALUE, long, int, VALUE*, VALUE(*)(VALUE,long)); VALUE rb_ary_elt(VALUE, long); void rb_ary_set_named_args(VALUE, bool); bool rb_ary_is_named_args(VALUE); +VALUE rb_ary_clone(VALUE); #endif /* bignum.c */ VALUE rb_big_clone(VALUE); @@ -361,6 +362,9 @@ VALUE rb_hash_delete(VALUE,VALUE); struct st_table *rb_hash_tbl(VALUE); int rb_path_check(const char*); int rb_env_path_tainted(void); +#if WITH_OBJC +VALUE rb_hash_clone(VALUE); +#endif /* io.c */ #define rb_defout rb_stdout RUBY_EXTERN VALUE rb_fs; diff --git a/object.c b/object.c index 6a46d9573..c48559763 100644 --- a/object.c +++ b/object.c @@ -157,6 +157,16 @@ rb_obj_class(VALUE obj) static void init_copy(VALUE dest, VALUE obj) { +#if WITH_OBJC + if (rb_objc_is_non_native(obj)) { + int type = TYPE(obj); + if (type == T_ARRAY) + if (rb_ary_tainted(obj)) rb_ary_taint(dest); + else if (type == T_HASH) + if (rb_hash_tainted(obj)) rb_hash_taint(dest); + goto call_init_copy; + } +#endif if (OBJ_FROZEN(dest)) { rb_raise(rb_eTypeError, "[bug] frozen object (%s) allocated", rb_obj_classname(dest)); } @@ -197,6 +207,7 @@ init_copy(VALUE dest, VALUE obj) } break; } +call_init_copy: rb_funcall(dest, id_init_copy, 1, obj); } @@ -234,6 +245,11 @@ rb_obj_clone(VALUE obj) } #if WITH_OBJC if (rb_objc_is_non_native(obj)) { + int type = TYPE(obj); + if (type == T_ARRAY) + return rb_ary_clone(obj); + if (type == T_HASH) + return rb_hash_clone(obj); clone = rb_obj_alloc(rb_obj_class(obj)); init_copy(clone, obj); return clone; diff --git a/test/ruby/test_array.rb b/test/ruby/test_array.rb index c0206baed..4cd7d0bc5 100644 --- a/test/ruby/test_array.rb +++ b/test/ruby/test_array.rb @@ -182,14 +182,14 @@ def setup def test_00_new a = @cls.new() - assert_instance_of(@cls, a) + assert_kind_of(@cls, a) assert_equal(0, a.length) assert_nil(a[0]) end def test_01_square_brackets a = @cls[ 5, 4, 3, 2, 1 ] - assert_instance_of(@cls, a) + assert_kind_of(@cls, a) assert_equal(5, a.length) 5.times { |i| assert_equal(5-i, a[i]) } assert_nil(a[6])