From 40bc4f5ae4ffe325c36a49e0d3280dbee2a39cee Mon Sep 17 00:00:00 2001 From: matz Date: Thu, 29 Aug 2002 09:08:18 +0000 Subject: * array.c (rb_ary_become): should not free ptr if it's shared. * eval.c (rb_alias): prohibit making an alias named "allocate" if klass is a metaclass. * string.c (rb_string_value_ptr): StringValuePtr() should never return NULL pointer. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@2764 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 14 +++- ToDo | 5 +- array.c | 3 +- configure.in | 2 +- eval.c | 12 ++- file.c | 8 +- gc.c | 2 +- hash.c | 6 ++ lib/finalize.rb | 253 ++++++++++++++++++++++++++------------------------------ marshal.c | 25 ++++-- re.c | 2 +- ruby.h | 3 +- string.c | 28 +++++-- struct.c | 4 +- 14 files changed, 203 insertions(+), 164 deletions(-) diff --git a/ChangeLog b/ChangeLog index a90f1699fa..d7acebe845 100644 --- a/ChangeLog +++ b/ChangeLog @@ -7,6 +7,13 @@ Thu Aug 29 00:55:55 2002 Nobuyoshi Nakada * marshal.c (r_object): yield loaded objects, not intermediates. (ruby-bugs-ja:PR#296) +Thu Aug 29 00:06:54 2002 Yukihiro Matsumoto + + * array.c (rb_ary_become): should not free ptr if it's shared. + + * eval.c (rb_alias): prohibit making an alias named "allocate" if + klass is a metaclass. + Wed Aug 28 23:59:15 2002 Michal Rokos * signal.c: remove #ifdef SIGINT for struct signals. @@ -17,6 +24,11 @@ Wed Aug 28 23:34:32 2002 Nobuyoshi Nakada * io.c (appendline): data was lost when raw mode. +Wed Aug 28 22:57:34 2002 Yukihiro Matsumoto + + * string.c (rb_string_value_ptr): StringValuePtr() should never + return NULL pointer. + Wed Aug 28 19:12:46 2002 Nobuyoshi Nakada * ext/stringio/stringio.c (strio_initialize): RSTRING(mode)->ptr @@ -34,7 +46,7 @@ Wed Aug 28 17:45:03 2002 Nobuyoshi Nakada Wed Aug 28 16:36:40 2002 WATANABE Hirofumi - * configure.in (ar): don't check twice for ar. + * configure.in (ar): don't check ar twice. Wed Aug 28 15:00:29 2002 Yukihiro Matsumoto diff --git a/ToDo b/ToDo index 3b03b417fb..fa7f32daed 100644 --- a/ToDo +++ b/ToDo @@ -32,10 +32,11 @@ Language Spec. * .. or something like defadvice in Emacs. * property - for methods, or for objects in general. * "in" modifier, to annotate, or to encourage assertion. -* selector namespace - something like generic-flet in CLOS, to help RubyBehevior +* selector namespace - something like generic-flet in CLOS, to help RubyBehavior * private instance variable (as in Python?) @_foo in class Foo => @_Foo_foo * warn/error "bare word" method, like "foo", you should type "foo()" * clarify evaluation order of operator argument (=~, .., ...) +* :symbol => value hash in the form of {symbol: value, ...} ?? Hacking Interpreter @@ -115,7 +116,7 @@ Extension Libraries Ruby Libraries -* add uri.rb +- add uri.rb * urllib.rb, nttplib.rb, etc. * format like perl's diff --git a/array.c b/array.c index f88e1b1cc2..f247db9794 100644 --- a/array.c +++ b/array.c @@ -801,7 +801,8 @@ rb_ary_become(copy, orig) { orig = to_ary(orig); ary_make_shared(orig); - if (RARRAY(copy)->ptr) free(RARRAY(copy)->ptr); + if (RARRAY(copy)->ptr && !FL_TEST(copy, ELTS_SHARED)) + free(RARRAY(copy)->ptr); RARRAY(copy)->ptr = RARRAY(orig)->ptr; RARRAY(copy)->len = RARRAY(orig)->len; RARRAY(copy)->aux.shared = RARRAY(orig)->aux.shared; diff --git a/configure.in b/configure.in index 4553aaa9ef..357eb74314 100644 --- a/configure.in +++ b/configure.in @@ -1018,7 +1018,7 @@ case "$target_os" in CFLAGS="$CFLAGS -pipe -no-precomp" ;; darwin*) - CFLAGS="$CFLAGS -pipe -no-precomp" + CFLAGS="$CFLAGS -pipe" ;; os2_emx) CFLAGS="$CFLAGS -DOS2" diff --git a/eval.c b/eval.c index 425ee5a361..25ce389052 100644 --- a/eval.c +++ b/eval.c @@ -1700,6 +1700,7 @@ rb_alias(klass, name, def) { VALUE origin; NODE *orig, *body; + VALUE singleton = 0; rb_frozen_class_p(klass); if (name == def) return; @@ -1715,6 +1716,12 @@ rb_alias(klass, name, def) if (!orig || !orig->nd_body) { print_undef(klass, def); } + if (FL_TEST(klass, FL_SINGLETON)) { + singleton = rb_iv_get(klass, "__attached__"); + if (name == alloc && TYPE(singleton) == T_CLASS) { + rb_raise(rb_eNameError, "cannot make alias named `allocate'"); + } + } body = orig->nd_body; orig->nd_cnt++; if (nd_type(body) == NODE_FBODY) { /* was alias */ @@ -1726,9 +1733,8 @@ rb_alias(klass, name, def) rb_clear_cache_by_id(name); st_insert(RCLASS(klass)->m_tbl, name, NEW_METHOD(NEW_FBODY(body, def, origin), orig->nd_noex)); - if (FL_TEST(klass, FL_SINGLETON)) { - rb_funcall(rb_iv_get(klass, "__attached__"), - singleton_added, 1, ID2SYM(name)); + if (singleton) { + rb_funcall(singleton, singleton_added, 1, ID2SYM(name)); } else { rb_funcall(klass, added, 1, ID2SYM(name)); diff --git a/file.c b/file.c index 719bb27557..fe13a9ee59 100644 --- a/file.c +++ b/file.c @@ -2027,8 +2027,12 @@ rb_stat_become(obj, orig) struct stat *nst; /* need better argument type check */ - if (!rb_obj_is_kind_of(orig, rb_obj_class(obj))) { - rb_raise(rb_eTypeError, "wrong argument type"); + if (!rb_obj_is_instance_of(orig, rb_obj_class(obj))) { + rb_raise(rb_eTypeError, "wrong argument class"); + } + if (DATA_PTR(obj)) { + free(DATA_PTR(obj)); + DATA_PTR(obj) = 0; } if (DATA_PTR(orig)) { nst = ALLOC(struct stat); diff --git a/gc.c b/gc.c index 678240a333..1503d42a74 100644 --- a/gc.c +++ b/gc.c @@ -1356,7 +1356,7 @@ static VALUE call_final(os, obj) VALUE os, obj; { - rb_warn("ObjectSpace::call_final is deprecated; use define_finalizer"); + rb_warn("ObjectSpace::call_finalizer is deprecated; use define_finalizer"); need_call_final = 1; FL_SET(obj, FL_FINALIZE); return obj; diff --git a/hash.c b/hash.c index e7fa574e12..60dc89ff0b 100644 --- a/hash.c +++ b/hash.c @@ -265,9 +265,15 @@ rb_hash_become(copy, orig) if (FL_TEST(orig, HASH_PROC_DEFAULT)) { FL_SET(copy, HASH_PROC_DEFAULT); } + else { + FL_UNSET(copy, HASH_PROC_DEFAULT); + } if (FL_TEST(orig, HASH_DELETED)) { FL_SET(copy, HASH_DELETED); } + else { + FL_UNSET(copy, HASH_DELETED); + } return copy; } diff --git a/lib/finalize.rb b/lib/finalize.rb index 598569f52e..7d86d94212 100644 --- a/lib/finalize.rb +++ b/lib/finalize.rb @@ -43,159 +43,144 @@ module Finalizer RCS_ID='-$Id: finalize.rb,v 1.4 1998/02/27 05:34:33 keiju Exp keiju $-' - - # @dependency: {id => [[dependant, method, *opt], ...], ...} - - # add dependency R_method(obj, dependant) - def add_dependency(obj, dependant, method = :finalize, *opt) - ObjectSpace.call_finalizer(obj) - method = method.intern unless method.kind_of?(Integer) - assoc = [dependant, method].concat(opt) - if dep = @dependency[obj.id] - dep.push assoc - else - @dependency[obj.id] = [assoc] + + class < [[dependant, method, *opt], ...], ...} + + # add dependency R_method(obj, dependant) + def add_dependency(obj, dependant, method = :finalize, *opt) + ObjectSpace.call_finalizer(obj) + method = method.intern unless method.kind_of?(Integer) + assoc = [dependant, method].concat(opt) + if dep = @dependency[obj.id] + dep.push assoc + else + @dependency[obj.id] = [assoc] + end end - end - alias add add_dependency - - # delete dependency R_method(obj, dependant) - def delete_dependency(id, dependant, method = :finalize) - id = id.id unless id.kind_of?(Integer) - method = method.intern unless method.kind_of?(Integer) - for assoc in @dependency[id] - assoc.delete_if do - |d, m, *o| - d == dependant && m == method + alias add add_dependency + + # delete dependency R_method(obj, dependant) + def delete_dependency(id, dependant, method = :finalize) + id = id.id unless id.kind_of?(Integer) + method = method.intern unless method.kind_of?(Integer) + for assoc in @dependency[id] + assoc.delete_if do + |d, m, *o| + d == dependant && m == method + end + @dependency.delete(id) if assoc.empty? end - @dependency.delete(id) if assoc.empty? end - end - alias delete delete_dependency - - # delete dependency R_*(obj, dependant) - def delete_all_dependency(id, dependant) - id = id.id unless id.kind_of?(Integer) - method = method.intern unless method.kind_of?(Integer) - for assoc in @dependency[id] - assoc.delete_if do - |d, m, *o| - d == dependant + alias delete delete_dependency + + # delete dependency R_*(obj, dependant) + def delete_all_dependency(id, dependant) + id = id.id unless id.kind_of?(Integer) + method = method.intern unless method.kind_of?(Integer) + for assoc in @dependency[id] + assoc.delete_if do + |d, m, *o| + d == dependant + end + @dependency.delete(id) if assoc.empty? end - @dependency.delete(id) if assoc.empty? end - end - - # delete dependency R_method(*, dependant) - def delete_by_dependant(dependant, method = :finalize) - method = method.intern unless method.kind_of?(Integer) - for id in @dependency.keys - delete(id, dependant, method) + + # delete dependency R_method(*, dependant) + def delete_by_dependant(dependant, method = :finalize) + method = method.intern unless method.kind_of?(Integer) + for id in @dependency.keys + delete(id, dependant, method) + end end - end - - # delete dependency R_*(*, dependant) - def delete_all_by_dependant(dependant) - for id in @dependency.keys - delete_all_dependency(id, dependant) + + # delete dependency R_*(*, dependant) + def delete_all_by_dependant(dependant) + for id in @dependency.keys + delete_all_dependency(id, dependant) + end end - end - - # finalize the depandant connected by dependency R_method(obj, dependtant) - def finalize_dependency(id, dependant, method = :finalize) - id = id.id unless id.kind_of?(Integer) - method = method.intern unless method.kind_of?(Integer) - for assocs in @dependency[id] - assocs.delete_if do - |d, m, *o| - d.send(m, id, *o) if ret = d == dependant && m == method - ret + + # finalize the depandant connected by dependency R_method(obj, dependtant) + def finalize_dependency(id, dependant, method = :finalize) + id = id.id unless id.kind_of?(Integer) + method = method.intern unless method.kind_of?(Integer) + for assocs in @dependency[id] + assocs.delete_if do + |d, m, *o| + d.send(m, id, *o) if ret = d == dependant && m == method + ret + end + @dependency.delete(id) if assoc.empty? end - @dependency.delete(id) if assoc.empty? end - end - alias finalize finalize_dependency - - # finalize all dependants connected by dependency R_*(obj, dependtant) - def finalize_all_dependency(id, dependant) - id = id.id unless id.kind_of?(Integer) - method = method.intern unless method.kind_of?(Integer) - for assoc in @dependency[id] - assoc.delete_if do - |d, m, *o| - d.send(m, id, *o) if ret = d == dependant + alias finalize finalize_dependency + + # finalize all dependants connected by dependency R_*(obj, dependtant) + def finalize_all_dependency(id, dependant) + id = id.id unless id.kind_of?(Integer) + method = method.intern unless method.kind_of?(Integer) + for assoc in @dependency[id] + assoc.delete_if do + |d, m, *o| + d.send(m, id, *o) if ret = d == dependant + end + @dependency.delete(id) if assoc.empty? end - @dependency.delete(id) if assoc.empty? end - end - - # finalize the dependant connected by dependency R_method(*, dependtant) - def finalize_by_dependant(dependant, method = :finalize) - method = method.intern unless method.kind_of?(Integer) - for id in @dependency.keys - finalize(id, dependant, method) + + # finalize the dependant connected by dependency R_method(*, dependtant) + def finalize_by_dependant(dependant, method = :finalize) + method = method.intern unless method.kind_of?(Integer) + for id in @dependency.keys + finalize(id, dependant, method) + end end - end - - # finalize all dependants connected by dependency R_*(*, dependtant) - def finalize_all_by_dependant(dependant) - for id in @dependency.keys - finalize_all_dependency(id, dependant) + + # finalize all dependants connected by dependency R_*(*, dependtant) + def finalize_all_by_dependant(dependant) + for id in @dependency.keys + finalize_all_dependency(id, dependant) + end end - end - - # finalize all dependants registered to the Finalizer. - def finalize_all - for id, assocs in @dependency - for dependant, method, *opt in assocs - dependant.send(method, id, *opt) + + # finalize all dependants registered to the Finalizer. + def finalize_all + for id, assocs in @dependency + for dependant, method, *opt in assocs + dependant.send(method, id, *opt) + end + assocs.clear end - assocs.clear end - end - - # method to call finalize_* safely. - def safe - old_status = Thread.critical - Thread.critical = true - ObjectSpace.remove_finalizer(@proc) - yield - ObjectSpace.add_finalizer(@proc) - Thread.critical = old_status - end - - # registering function to ObjectSpace#add_finalizer - def final_of(id) - if assocs = @dependency.delete(id) - for dependant, method, *opt in assocs - dependant.send(method, id, *opt) + + # method to call finalize_* safely. + def safe + old_status = Thread.critical + Thread.critical = true + ObjectSpace.remove_finalizer(@proc) + begin + yield + ensure + ObjectSpace.add_finalizer(@proc) + Thread.critical = old_status + end + end + + private + + # registering function to ObjectSpace#add_finalizer + def final_of(id) + if assocs = @dependency.delete(id) + for dependant, method, *opt in assocs + dependant.send(method, id, *opt) + end end end + end - @dependency = Hash.new @proc = proc{|id| final_of(id)} ObjectSpace.add_finalizer(@proc) - - module_function :add - module_function :add_dependency - - module_function :delete - module_function :delete_dependency - module_function :delete_all_dependency - module_function :delete_by_dependant - module_function :delete_all_by_dependant - - module_function :finalize - module_function :finalize_dependency - module_function :finalize_all_dependency - module_function :finalize_by_dependant - module_function :finalize_all_by_dependant - module_function :finalize_all - - module_function :safe - - module_function :final_of - private_class_method :final_of - end diff --git a/marshal.c b/marshal.c index 3b4761ea7c..78d801bbb2 100644 --- a/marshal.c +++ b/marshal.c @@ -466,11 +466,15 @@ w_object(obj, arg, limit) case T_HASH: w_uclass(obj, rb_cHash, arg); - if (!NIL_P(RHASH(obj)->ifnone)) { - w_byte(TYPE_HASH_DEF, arg); + if (NIL_P(RHASH(obj)->ifnone)) { + w_byte(TYPE_HASH, arg); + } + else if (FL_TEST(obj, FL_USER2)) { + /* FL_USER2 means HASH_PROC_DEFAULT (see hash.c) */ + rb_raise(rb_eArgError, "cannot dump hash with default proc"); } else { - w_byte(TYPE_HASH, arg); + w_byte(TYPE_HASH_DEF, arg); } w_long(RHASH(obj)->tbl->num_entries, arg); st_foreach(RHASH(obj)->tbl, hash_each, &c_arg); @@ -1047,12 +1051,17 @@ r_object0(arg, proc) VALUE klass; klass = rb_path2class(r_unique(arg)); - if (!rb_respond_to(klass, s_alloc)) { - rb_raise(rb_eTypeError, - "class %s needs to have class method `_alloc'", - rb_class2name(klass)); + if (rb_respond_to(klass, s_alloc)) { + static int warn = Qtrue; + if (warn) { + rb_warn("define `allocate' instead of `_alloc'"); + warn = Qfalse; + } + v = rb_funcall(klass, s_alloc, 0); } - v = rb_funcall(klass, s_alloc, 0); + else { + v = rb_obj_alloc(klass); + } if (TYPE(v) != T_DATA) { rb_raise(rb_eArgError, "dump format error"); } diff --git a/re.c b/re.c index 60f8140616..0b0c899f20 100644 --- a/re.c +++ b/re.c @@ -1333,7 +1333,7 @@ rb_reg_become(clone, re) VALUE re; { /* need better argument type check */ - if (!rb_obj_is_kind_of(re, rb_obj_class(clone))) { + if (!rb_obj_is_instance_of(re, rb_obj_class(clone))) { rb_raise(rb_eTypeError, "wrong argument type"); } RREGEXP(clone)->ptr = 0; diff --git a/ruby.h b/ruby.h index 3b74185f53..7829b85476 100644 --- a/ruby.h +++ b/ruby.h @@ -211,6 +211,7 @@ void rb_check_type _((VALUE,int)); VALUE rb_str_to_str _((VALUE)); VALUE rb_string_value _((volatile VALUE*)); +char *rb_string_value_ptr _((volatile VALUE*)); #define StringValue(v) if (TYPE(v) != T_STRING) rb_string_value(&(v)) void rb_check_safe_str _((VALUE)); @@ -218,7 +219,7 @@ void rb_check_safe_str _((VALUE)); StringValue(v);\ rb_check_safe_str(v);\ } while (0) -#define StringValuePtr(v) RSTRING((TYPE(v) == T_STRING) ? (v) : rb_string_value(&(v)))->ptr +#define StringValuePtr(v) rb_string_value_ptr(&(v)) /* obsolete macro - use SafeStringValue(v) */ #define Check_SafeStr(v) rb_check_safe_str((VALUE)(v)) diff --git a/string.c b/string.c index 2ef8de5319..b036cb5db7 100644 --- a/string.c +++ b/string.c @@ -440,6 +440,21 @@ rb_string_value(ptr) return *ptr = rb_str_to_str(*ptr); } +char * +rb_string_value_ptr(ptr) + volatile VALUE *ptr; +{ + VALUE s = *ptr; + if (TYPE(s) != T_STRING) { + s = rb_str_to_str(s); + *ptr = s; + } + if (!RSTRING(s)->ptr) { + str_make_independent(s); + } + return RSTRING(s)->ptr; +} + VALUE rb_str_substr(str, beg, len) VALUE str; @@ -1609,18 +1624,17 @@ rb_str_replace(str, str2) } RSTRING(str)->len = RSTRING(str2)->len; RSTRING(str)->ptr = RSTRING(str2)->ptr; - if (FL_TEST(str2, ELTS_SHARED|STR_ASSOC)) { - FL_SET(str, RBASIC(str2)->flags & (ELTS_SHARED|STR_ASSOC)); - RSTRING(str)->aux.shared = RSTRING(str2)->aux.shared; - } - else { - RSTRING(str)->aux.capa = RSTRING(str2)->aux.capa; - } + FL_SET(str, RBASIC(str2)->flags & (ELTS_SHARED|STR_ASSOC)); + RSTRING(str)->aux.shared = RSTRING(str2)->aux.shared; } else { rb_str_modify(str); rb_str_resize(str, RSTRING(str2)->len); memcpy(RSTRING(str)->ptr, RSTRING(str2)->ptr, RSTRING(str2)->len); + if (FL_TEST(str2, STR_ASSOC)) { + FL_SET(str, RBASIC(str2)->flags & (ELTS_SHARED|STR_ASSOC)); + RSTRING(str)->aux.shared = RSTRING(str2)->aux.shared; + } } OBJ_INFECT(str, str2); diff --git a/struct.c b/struct.c index 1a378c865f..4378196982 100644 --- a/struct.c +++ b/struct.c @@ -424,8 +424,8 @@ static VALUE rb_struct_become(clone, s) VALUE clone, s; { - if (!rb_obj_is_kind_of(s, rb_obj_class(clone))) { - rb_raise(rb_eTypeError, "wrong argument type"); + if (!rb_obj_is_instance_of(s, rb_obj_class(clone))) { + rb_raise(rb_eTypeError, "wrong argument class"); } RSTRUCT(clone)->ptr = ALLOC_N(VALUE, RSTRUCT(s)->len); RSTRUCT(clone)->len = RSTRUCT(s)->len; -- cgit v1.2.3