ruby-changes:6373
From: nobu <ko1@a...>
Date: Sat, 5 Jul 2008 21:25:43 +0900 (JST)
Subject: [ruby-changes:6373] Ruby:r17889 (mvm): * merged from trunk r17835:17888.
nobu 2008-07-05 21:25:07 +0900 (Sat, 05 Jul 2008) New Revision: 17889 Added directories: branches/mvm/ext/coverage/ Added files: branches/mvm/test/test_singleton.rb Modified files: branches/mvm/.merged-trunk-revision branches/mvm/ChangeLog branches/mvm/configure.in branches/mvm/encoding.c branches/mvm/eval.c branches/mvm/ext/win32ole/win32ole.c branches/mvm/gc.c branches/mvm/include/ruby/encoding.h branches/mvm/include/ruby/oniguruma.h branches/mvm/insns.def branches/mvm/iseq.c branches/mvm/lib/coverage.rb branches/mvm/lib/net/ftp.rb branches/mvm/lib/net/smtp.rb branches/mvm/lib/test/unit/autorunner.rb branches/mvm/lib/test/unit/collector/dir.rb branches/mvm/lib/test/unit/collector/objectspace.rb branches/mvm/lib/test/unit/testcase.rb branches/mvm/numeric.c branches/mvm/parse.y branches/mvm/re.c branches/mvm/test/ruby/test_m17n.rb branches/mvm/test/win32ole/test_win32ole.rb branches/mvm/test/win32ole/test_win32ole_variant.rb branches/mvm/test/win32ole/test_word.rb branches/mvm/thread.c branches/mvm/version.h branches/mvm/vm.c branches/mvm/vm_core.h Log: * merged from trunk r17835:17888. Added: branches/mvm/ext/coverage/ http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=17889 Index: mvm/encoding.c =================================================================== --- mvm/encoding.c (revision 17888) +++ mvm/encoding.c (revision 17889) @@ -19,10 +19,12 @@ static ID id_encoding, id_base_encoding; VALUE rb_cEncoding; +static VALUE rb_encoding_list; struct rb_encoding_entry { const char *name; rb_encoding *enc; + rb_encoding *base; }; static struct { @@ -49,36 +51,60 @@ static VALUE enc_new(rb_encoding *encoding) { - VALUE enc = Data_Wrap_Struct(rb_cEncoding, enc_mark, 0, encoding); - encoding->auxiliary_data = (void *)enc; - return enc; + return Data_Wrap_Struct(rb_cEncoding, enc_mark, 0, encoding); } VALUE rb_enc_from_encoding(rb_encoding *encoding) { + VALUE list, enc; + int idx; + if (!encoding) return Qnil; - if (enc_initialized_p(encoding)) - return ENC_FROM_ENCODING(encoding); - return enc_new(encoding); + idx = ENC_TO_ENCINDEX(encoding); + if (!(list = rb_encoding_list)) { + rb_bug("rb_enc_from_encoding(%d\"%s\"): no rb_encoding_list", + idx, rb_enc_name(encoding)); + } + enc = rb_ary_entry(list, idx); + if (NIL_P(enc)) { + rb_bug("rb_enc_from_encoding(%d\"%s\"): not created yet", + idx, rb_enc_name(encoding)); + } + return enc; } +static int enc_autoload(rb_encoding *); + static int -enc_check_encoding(VALUE obj) +check_encoding(rb_encoding *enc) { - int index; - rb_encoding *enc; + int index = rb_enc_to_index(enc); + if (rb_enc_from_index(index) != enc) + return -1; + if (enc_autoload_p(enc)) { + index = enc_autoload(enc); + } + return index; +} +static int +enc_check_encoding(VALUE obj) +{ if (SPECIAL_CONST_P(obj) || BUILTIN_TYPE(obj) != T_DATA || RDATA(obj)->dmark != enc_mark) { return -1; } - enc = (rb_encoding*)RDATA(obj)->data; - index = rb_enc_to_index(enc); - if (rb_enc_from_index(index) != enc) - return -1; - if (enc_autoload_p(enc)) { - index = rb_enc_find_index(enc->name); + return check_encoding(RDATA(obj)->data); +} + +static int +must_encoding(VALUE enc) +{ + int index = enc_check_encoding(enc); + if (index < 0) { + rb_raise(rb_eTypeError, "wrong argument type %s (expected Encoding)", + rb_obj_classname(enc)); } return index; } @@ -116,13 +142,6 @@ void rb_gc_mark_encodings(void) { - int i; - for (i = 0; i < enc_table.count; ++i) { - rb_encoding *enc = enc_table.list[i].enc; - if (enc && enc_initialized_p(enc)) { - rb_gc_mark(ENC_FROM_ENCODING(enc)); - } - } } static int @@ -145,7 +164,7 @@ enc_register_at(int index, const char *name, rb_encoding *encoding) { struct rb_encoding_entry *ent = &enc_table.list[index]; - void *obj = ENC_UNINITIALIZED; + VALUE list; if (!ent->name) { ent->name = name = strdup(name); @@ -156,9 +175,6 @@ if (!ent->enc) { ent->enc = xmalloc(sizeof(rb_encoding)); } - else { - obj = ent->enc->auxiliary_data; - } if (encoding) { *ent->enc = *encoding; } @@ -169,16 +185,11 @@ encoding->name = name; encoding->ruby_encoding_index = index; st_insert(enc_table.names, (st_data_t)name, (st_data_t)index); - if (obj != ENC_UNINITIALIZED) { - encoding->auxiliary_data = obj; - } - else if (rb_cEncoding) { + list = rb_encoding_list; + if (list && NIL_P(rb_ary_entry(list, index))) { /* initialize encoding data */ - enc_new(encoding); + rb_ary_store(list, index, enc_new(encoding)); } - else { - encoding->auxiliary_data = ENC_UNINITIALIZED; - } return index; } @@ -205,9 +216,7 @@ if (STRCASECMP(name, rb_enc_name(oldenc))) { index = enc_register(name, encoding); } - else if (!enc_autoload_p(oldenc) || - (enc_initialized_p(oldenc) && - !ENC_DUMMY_P(ENC_FROM_ENCODING(oldenc)))) { + else if (enc_autoload_p(oldenc) || !ENC_DUMMY_P(oldenc)) { enc_register_at(index, name, encoding); } else { @@ -239,12 +248,12 @@ } } -static VALUE +static rb_encoding* set_base_encoding(int index, rb_encoding *base) { - VALUE enc = rb_enc_from_encoding(enc_table.list[index].enc); + rb_encoding *enc = enc_table.list[index].enc; - rb_ivar_set(enc, id_base_encoding, rb_enc_from_encoding(base)); + enc_table.list[index].base = base; if (rb_enc_dummy_p(base)) ENC_SET_DUMMY(enc); return enc; } @@ -293,7 +302,7 @@ rb_define_dummy_encoding(const char *name) { int index = rb_enc_replicate(name, rb_ascii8bit_encoding()); - VALUE enc = rb_enc_from_encoding(enc_table.list[index].enc); + rb_encoding *enc = enc_table.list[index].enc; ENC_SET_DUMMY(enc); return index; @@ -304,7 +313,7 @@ { int index = enc_replicate(rb_enc_registered(name), name, rb_ascii8bit_encoding()); - VALUE enc = rb_enc_from_encoding(enc_table.list[index].enc); + rb_encoding *enc = enc_table.list[index].enc; ENC_SET_DUMMY(enc); return index; @@ -326,7 +335,7 @@ static VALUE enc_dummy_p(VALUE enc) { - return ENC_DUMMY_P(enc) ? Qtrue : Qfalse; + return ENC_DUMMY_P(enc_table.list[must_encoding(enc)].enc) ? Qtrue : Qfalse; } static int @@ -448,33 +457,44 @@ return idx; } +static int +enc_autoload(rb_encoding *enc) +{ + int i; + rb_encoding *base = enc_table.list[ENC_TO_ENCINDEX(enc)].base; + + if (base) { + i = 0; + do { + if (i >= enc_table.count) return -1; + } while (enc_table.list[i].enc != base && (++i, 1)); + if (enc_autoload_p(base)) { + if (enc_autoload(base) < 0) return -1; + } + i = ENC_TO_ENCINDEX(enc); + enc_register_at(i, rb_enc_name(enc), base); + } + else { + i = load_encoding(rb_enc_name(enc)); + } + return i; +} + int rb_enc_find_index(const char *name) { - int i = rb_enc_registered(name), b; + int i = rb_enc_registered(name); rb_encoding *enc; - VALUE base; if (i < 0) { i = load_encoding(name); } else if (enc_autoload_p(enc = rb_enc_from_index(i))) { - if (enc_initialized_p(enc) && - (base = enc_base_encoding(ENC_FROM_ENCODING(enc)), !NIL_P(base))) { - if ((b = enc_check_encoding(base)) < 0) { - goto failed; - } - enc_register_at(i, rb_enc_name(enc), rb_enc_from_index(b)); + if (enc_autoload(enc) < 0) { + rb_warn("failed to load encoding (%s); use ASCII-8BIT instead", + name); + return 0; } - else { - i = load_encoding(rb_enc_name(enc)); - if (i < 0) { - failed: - rb_warn("failed to load encoding (%s); use ASCII-8BIT instead", - name); - return 0; - } - } } return i; } @@ -503,33 +523,6 @@ } } -#if 0 -static void -enc_check_capable(VALUE x) -{ - if (!enc_capable(x)) { - const char *etype; - - if (NIL_P(x)) { - etype = "nil"; - } - else if (FIXNUM_P(x)) { - etype = "Fixnum"; - } - else if (SYMBOL_P(x)) { - etype = "Symbol"; - } - else if (rb_special_const_p(x)) { - etype = RSTRING_PTR(rb_obj_as_string(x)); - } - else { - etype = rb_obj_classname(x); - } - rb_raise(rb_eTypeError, "wrong argument type %s (not encode capable)", etype); - } -} -#endif - ID rb_id_encoding(void) { @@ -777,7 +770,7 @@ { VALUE str = rb_sprintf("#<%s:%s%s>", rb_obj_classname(self), rb_enc_name((rb_encoding*)DATA_PTR(self)), - (ENC_DUMMY_P(self) ? " (dummy)" : "")); + (enc_dummy_p(self) ? " (dummy)" : "")); ENCODING_CODERANGE_SET(str, rb_usascii_encindex(), ENC_CODERANGE_7BIT); return str; } @@ -799,7 +792,9 @@ static VALUE enc_base_encoding(VALUE self) { - return rb_attr_get(self, id_base_encoding); + rb_encoding *base = enc_table.list[must_encoding(self)].base; + if (!base) return Qnil; + return ENC_FROM_ENCODING(base); } /* @@ -823,14 +818,8 @@ static VALUE enc_list(VALUE klass) { - VALUE ary = rb_ary_new2(enc_table.count); - int i; - for (i = 0; i < enc_table.count; ++i) { - rb_encoding *enc = enc_table.list[i].enc; - if (enc) { - rb_ary_push(ary, rb_enc_from_encoding(enc)); - } - } + VALUE ary = rb_ary_new2(0); + rb_ary_replace(ary, rb_encoding_list); return ary; } @@ -1183,6 +1172,8 @@ Init_Encoding(void) { #undef rb_intern + VALUE list; + int i; id_base_encoding = rb_intern("#base_encoding"); @@ -1204,6 +1195,14 @@ rb_define_singleton_method(rb_cEncoding, "default_external", get_default_external, 0); rb_define_singleton_method(rb_cEncoding, "locale_charmap", rb_locale_charmap, 0); + + rb_gc_register_address(&rb_encoding_list); + list = rb_ary_new2(enc_table.count); + RBASIC(list)->klass = 0; + rb_encoding_list = list; + for (i = 0; i < enc_table.count; ++i) { + rb_ary_push(list, enc_new(enc_table.list[i].enc)); + } } /* locale insensitive functions */ Index: mvm/include/ruby/encoding.h =================================================================== --- mvm/include/ruby/encoding.h (revision 17888) +++ mvm/include/ruby/encoding.h (revision 17889) @@ -70,7 +70,7 @@ int rb_enc_replicate(const char *, rb_encoding *); int rb_define_dummy_encoding(const char *); -#define rb_enc_to_index(enc) ((enc) ? ((enc)->ruby_encoding_index) : 0) +#define rb_enc_to_index(enc) ((enc) ? ENC_TO_ENCINDEX(enc) : 0) int rb_enc_get_index(VALUE obj); void rb_enc_set_index(VALUE obj, int encindex); int rb_enc_find_index(const char *name); @@ -176,20 +176,21 @@ long rb_memsearch(const void*,long,const void*,long,rb_encoding*); RUBY_EXTERN VALUE rb_cEncoding; +#define enc_initialized_p(enc) ((enc)->ruby_encoding_index != ENC_UNINITIALIZED) +#define ENC_DUMMY_FLAG (1<<24) +#define ENC_INDEX_MASK (~(~0U<<24)) -#define ENC_UNINITIALIZED (&rb_cEncoding) -#define enc_initialized_p(enc) ((enc)->auxiliary_data != &rb_cEncoding) -#define ENC_FROM_ENCODING(enc) ((VALUE)(enc)->auxiliary_data) +#define ENC_TO_ENCINDEX(enc) ((enc)->ruby_encoding_index & ENC_INDEX_MASK) +#define ENC_FROM_ENCINDEX(idx) (RARRAY_PTR(rb_encoding_list)[idx]) +#define ENC_FROM_ENCODING(enc) ENC_FROM_ENCINDEX(ENC_TO_ENCINDEX(enc)) -#define ENC_DUMMY_FLAG FL_USER2 -#define ENC_DUMMY_P(enc) (RBASIC(enc)->flags & ENC_DUMMY_FLAG) -#define ENC_SET_DUMMY(enc) (RBASIC(enc)->flags |= ENC_DUMMY_FLAG) +#define ENC_DUMMY_P(enc) ((enc)->ruby_encoding_index & ENC_DUMMY_FLAG) +#define ENC_SET_DUMMY(enc) ((enc)->ruby_encoding_index |= ENC_DUMMY_FLAG) static inline int rb_enc_dummy_p(rb_encoding *enc) { - if (!enc_initialized_p(enc)) return Qfalse; - return ENC_DUMMY_P(ENC_FROM_ENCODING(enc)); + return ENC_DUMMY_P(enc) != 0; } VALUE rb_str_transcode(VALUE str, VALUE to); Index: mvm/include/ruby/oniguruma.h =================================================================== --- mvm/include/ruby/oniguruma.h (revision 17888) +++ mvm/include/ruby/oniguruma.h (revision 17889) @@ -166,7 +166,6 @@ int (*get_ctype_code_range)(OnigCtype ctype, OnigCodePoint* sb_out, const OnigCodePoint* ranges[], struct OnigEncodingTypeST* enc); OnigUChar* (*left_adjust_char_head)(const OnigUChar* start, const OnigUChar* p, struct OnigEncodingTypeST* enc); int (*is_allowed_reverse_match)(const OnigUChar* p, const OnigUChar* end, struct OnigEncodingTypeST* enc); - void *auxiliary_data; int ruby_encoding_index; } OnigEncodingType; Index: mvm/configure.in =================================================================== --- mvm/configure.in (revision 17888) +++ mvm/configure.in (revision 17889) @@ -700,6 +700,27 @@ ;; esac AC_FUNC_MEMCMP + +# http://sources.redhat.com/ml/libc-hacker/2005-08/msg00008.html +# Debian GNU/Linux Etch's libc6.1 2.3.6.ds1-13etch5 has this problem. +# Debian GNU/Linux Lenny's libc6.1 2.7-10 has no problem. +AC_CACHE_CHECK(for broken erfc of glibc-2.3.6 on IA64, rb_broken_glibc_ia64_erfc, + [AC_TRY_RUN([ +#include <math.h> +int +main() +{ + erfc(10000.0); + return 0; +} +], + rb_broken_glibc_ia64_erfc=no, + rb_broken_glibc_ia64_erfc=yes, + rb_broken_glibc_ia64_erfc=no)]) +case $rb_broken_glibc_ia64_erfc in + yes) ac_cv_func_erf=no;; +esac + AC_REPLACE_FUNCS(dup2 memmove strerror strftime\ strchr strstr crypt flock vsnprintf\ isnan finite isinf hypot acosh erf tgamma lgamma_r cbrt \ Index: mvm/re.c =================================================================== --- mvm/re.c (revision 17888) +++ mvm/re.c (revision 17889) @@ -2085,7 +2085,8 @@ static int unescape_nonascii(const char *p, const char *end, rb_encoding *enc, - VALUE buf, rb_encoding **encp, onig_errmsg_buffer err) + VALUE buf, rb_encoding **encp, int *has_property, + onig_errmsg_buffer err) { char c; char smallbuf[2]; @@ -2163,6 +2164,12 @@ break; } + case 'p': /* \p{Hiragana} */ + if (!*encp) { + *has_property = 1; + } + goto escape_asis; + default: /* \n, \\, \d, \9, etc. */ escape_asis: smallbuf[0] = '\\'; @@ -2186,6 +2193,7 @@ rb_encoding **fixed_enc, onig_errmsg_buffer err) { VALUE buf; + int has_property = 0; buf = rb_str_buf_new(0); @@ -2196,9 +2204,13 @@ rb_enc_associate(buf, enc); } - if (unescape_nonascii(p, end, enc, buf, fixed_enc, err) != 0) + if (unescape_nonascii(p, end, enc, buf, fixed_enc, &has_property, err) != 0) return Qnil; + if (has_property && !*fixed_enc) { + *fixed_enc = enc; + } + if (*fixed_enc) { rb_enc_associate(buf, *fixed_enc); } Index: mvm/insns.def =================================================================== --- mvm/insns.def (revision 17888) +++ mvm/insns.def (revision 17889) @@ -853,23 +853,7 @@ { rb_event_flag_t flag = nf; - if (flag == RUBY_EVENT_COVERAGE) { - VALUE coverage = GET_ISEQ()->coverage; - if (coverage) { - long line = vm_get_sourceline(GET_CFP()) - 1; - long count; - if (RARRAY_PTR(coverage)[line] == Qnil) { - rb_bug("bug"); - } - count = FIX2LONG(RARRAY_PTR(coverage)[line]) + 1; - if (POSFIXABLE(count)) { - RARRAY_PTR(coverage)[line] = LONG2FIX(count); - } - } - } - else { - EXEC_EVENT_HOOK(th, flag, GET_SELF(), 0, 0 /* TODO: id, klass */); - } + EXEC_EVENT_HOOK(th, flag, GET_SELF(), 0, 0 /* TODO: id, klass */); } /**********************************************************/ Index: mvm/ChangeLog =================================================================== --- mvm/ChangeLog (revision 17888) +++ mvm/ChangeLog (revision 17889) @@ -1,3 +1,157 @@ +Sat Jul 5 20:53:18 2008 Masaki Suketa <masaki.suketa@n...> + + * test/win32ole/test_word.rb: check word installed. + +Sat Jul 5 16:12:54 2008 Narihiro Nakamura <authorNari@g...> + + * gc.c: revert. before lazy sweep. + +Sat Jul 5 09:55:44 2008 Masaki Suketa <masaki.suketa@n...> + + * ext/win32ole/win32ole.c: add WIN32OLE#ole_respond_to? + + * test/win32ole/test_win32ole.rb: ditto. + +Sat Jul 5 08:48:05 2008 Tanaka Akira <akr@f...> + + * re.c (unescape_nonascii): add has_property argument not to + raise error by /\p{Hiragana}\u{3042}/ in EUC-JP script. + (rb_reg_preprocess): use has_property argument to make regexp + encoding fixed. + +Sat Jul 5 08:29:47 2008 Tanaka Akira <akr@f...> + + * re.c (unescape_nonascii): make regexp fixed_encoding if \p is used. + fixed [ruby-core:17279]. + +Fri Jul 4 23:12:53 2008 Masaki Suketa <masaki.suketa@n...> + + * ext/win32ole/win32ole.c (d2time): fix the bug of VT_DATE + to String conversion when negative value. + + * test/win32ole/test_win32ole_variant.rb: ditto. + +Fri Jul 4 22:15:29 2008 Tanaka Akira <akr@f...> + + * lib/test/unit/testcase.rb: collect decendants of + Test::Unit::TestCase using inherited. + + * lib/test/unit/autorunner.rb: don't use ObjectSpace.each_object. + + * lib/test/unit/collector/dir.rb: ditto. + + * lib/test/unit/collector/objectspace.rb: ditto. + + [ruby-core:17126] + +Fri Jul 4 20:43:53 2008 Nobuyoshi Nakada <nobu@r...> + + * include/ruby/oniguruma.h (OnigEncoding): removed auxiliary_data. + + * include/ruby/encoding.h (ENC_DUMMY_P): moved dummy encoding flag to + rb_encoding from Encoding instance. + + * encoding.c (rb_encoding_list): list of Encoding instances. + + * encoding.c (struct rb_encoding_entry): moved base encoding from + instance variable. + +Fri Jul 4 17:51:07 2008 NAKAMURA Usaku <usa@r...> + + * numeric.c (check_uint, rb_num2uint, rb_fix2uint): proper check. + +Fri Jul 4 14:17:22 2008 Nobuyoshi Nakada <nobu@r...> + + * lib/net/ftp.rb (Net::FTP#sendport): use divmod. [ruby-core:17557] + +Fri Jul 4 11:08:37 2008 Narihiro Nakamura <authorNari@g...> + + * gc.c (garbage_collect_force): sweep is completely ended. + + * gc.c (os_obj_of): invoke garbage_collect_force() when freelist none. + +Fri Jul 4 05:01:26 2008 NAKAMURA Usaku <usa@r...> + + * numeric.c (rb_num2uint, rb_fix2uint): typo. + +Fri Jul 4 02:21:06 2008 NAKAMURA Usaku <usa@r...> + + * numeric.c (check_uint, rb_num2uint, rb_fix2uint): also needs checking + negative value. see [ruby-dev:33683] + +Thu Jul 3 23:26:36 2008 Yusuke Endoh <mame@t...> + + * include/ruby/intern.h: remove prototypes about coverage. + + * iseq.c (prepare_iseq_build): add prototype. + + * parse.y (coverage): ditto. + + * thread.c (clear_coverage): ditto. + + * thread.c (update_coverage): use rb_sourceline. + + * thread.c (rb_get_coverages): rename and move to vm.c. + + * vm.c (rb_vm_get_coverages): ditto. + + * ext/coverage/coverage.c: add rdoc. + +Thu Jul 3 21:51:21 2008 Yusuke Endoh <mame@t...> + + * ext/coverage/coverage.c, ext/coverage/extconf.rb: eliminate + COVERAGE__ and introduce coverage.so instead. How to measure + coverage: (1) require "coverage.so", (2) require or load Ruby source + file, and (3) Coverage.result will return the same hash as COVERAGE__. + [ruby-dev:35324] + + * thread.c (rb_enable_coverages): start coverage measurement by using + rb_add_event_hook. + + * thread.c (rb_get_coverages): returns current results of coverage + measurement. + + * include/ruby/intern.h: add prototype for above two functions. + + * vm_core.h, vm.c: add field of coverages to rb_vm_t. + + * insns.def (trace): remove special handling for COVERAGE__. + + * iseq.c (prepare_iseq_build): switch COVERAGE__ to + rb_get_coverages(). + + * parse.y (coverage): ditto. + + * thread.c (clear_coverage): ditto. + + * lib/coverage.rb: use coverage.so instead of COVERAGE__. + +Thu Jul 3 21:20:45 2008 Yusuke Endoh <mame@t...> + + * thread.c (thread_initialize): NUM2INT returns long. + +Thu Jul 3 21:06:16 2008 Nobuyoshi Nakada <nobu@r...> + + * eval.c (Init_eval): typo fixed in r17833. + +Thu Jul 3 19:44:44 2008 Masaki Suketa <masaki.suketa@n...> + + * ext/win32ole/win32ole.c (Init_win32ole): remove duplicate line. + +Thu Jul 3 16:08:36 2008 Tanaka Akira <akr@f...> + + * configure.in (erfc): erfc of glibc comes with Debian GNU/Linux Etch + on IA64 is broken. erfc(10000.0) aborts. + use missing/erf.c instead. + http://sources.redhat.com/ml/libc-hacker/2005-08/msg00008.html + +Thu Jul 3 12:49:39 2008 Yukihiro Matsumoto <matz@r...> + + * lib/net/smtp.rb (Net::SMTP::start): use 'localhost' instead of + 'localhost.localdomain'. [ruby-dev:35333] + + * lib/net/smtp.rb (Net::SMTP::SMTP.start): ditto. + Thu Jul 3 07:06:02 2008 Nobuyoshi Nakada <nobu@r...> * Makefile.in (SET_LC_MESSAGES): LC_MESSAGES must be C. @@ -45,11 +199,15 @@ * include/ruby/intern.h: ditto. Wed Jul 2 09:49:10 2008 Narihiro Nakamura <authorNari@g...> - - * gc.c (gc_lazy_sweep) : use lazy sweep algorithm for response performance gain. - (garbage_collect_force) : mark and lazysweep invoke, after erasing all mark. - (GC_NOT_LAZY_SWEEP) : not lazy sweep flag. for debug. + * gc.c (gc_lazy_sweep) : use lazy sweep algorithm for response + performance gain. + + * gc.c (garbage_collect_force) : mark and lazysweep invoke, after + erasing all mark. + + * gc.c (GC_NOT_LAZY_SWEEP) : not lazy sweep flag. for debug. + Wed Jul 2 03:42:44 2008 Yusuke Endoh <mame@t...> * test/ruby/test_settracefunc.rb: fix expected traces for Index: mvm/vm_core.h =================================================================== --- mvm/vm_core.h (revision 17888) +++ mvm/vm_core.h (revision 17889) @@ -342,6 +342,7 @@ int src_encoding_index; VALUE verbose, debug, progname; + VALUE coverages; #ifdef RUBY_DEBUG_ENV int enable_coredump; Index: mvm/iseq.c =================================================================== --- mvm/iseq.c (revision 17888) +++ mvm/iseq.c (revision 17889) @@ -194,12 +194,11 @@ iseq->coverage = Qfalse; if (!GET_THREAD()->parse_in_eval) { - if (rb_const_defined_at(rb_cObject, rb_intern("COVERAGE__"))) { - VALUE hash = rb_const_get_at(rb_cObject, rb_intern("COVERAGE__")); - if (TYPE(hash) == T_HASH) { - iseq->coverage = rb_hash_aref(hash, filename); - if (NIL_P(iseq->coverage)) iseq->coverage = Qfalse; - } + extern VALUE rb_vm_get_coverages(void); + VALUE coverages = rb_vm_get_coverages(); + if (RTEST(coverages)) { + iseq->coverage = rb_hash_aref(coverages, filename); + if (NIL_P(iseq->coverage)) iseq->coverage = Qfalse; } } Index: mvm/lib/coverage.rb =================================================================== --- mvm/lib/coverage.rb (revision 17888) +++ mvm/lib/coverage.rb (revision 17889) @@ -1,4 +1,5 @@ -COVERAGE__ ||= {} +require "coverage.so" + ext = ENV["COVERUBY_EXT"] || ".cov" accum = ENV["COVERUBY_ACCUM"] accum = !accum || accum == "" || !(%w(f n 0).include?(accum[0])) @@ -6,7 +7,7 @@ at_exit do Dir.chdir(pwd) do - COVERAGE__.each do |sfile, covs| + Coverage.result.each do |sfile, covs| cfile = sfile + ext writable = proc do |f| Index: mvm/lib/test/unit/autorunner.rb =================================================================== --- mvm/lib/test/unit/autorunner.rb (revision 17888) +++ mvm/lib/test/unit/autorunner.rb (revision 17889) @@ -14,10 +14,7 @@ def self.standalone? return false unless("-e" == $0) - ObjectSpace.each_object(Class) do |klass| - return false if(klass < TestCase) - end - true + TestCase::DECENDANT_CLASSES.empty? end RUNNERS = { Index: mvm/lib/test/unit/collector/dir.rb =================================================================== --- mvm/lib/test/unit/collector/dir.rb (revision 17888) +++ mvm/lib/test/unit/collector/dir.rb (revision 17889) @@ -10,7 +10,7 @@ attr_reader :pattern, :exclude attr_accessor :base - def initialize(dir=::Dir, file=::File, object_space=::ObjectSpace, req=nil) + def initialize(dir=::Dir, file=::File, object_space=nil, req=nil) super() @dir = dir @file = file @@ -43,8 +43,14 @@ def find_test_cases(ignore=[]) cases = [] - @object_space.each_object(Class) do |c| - cases << c if(c < TestCase && !ignore.include?(c)) + if @object_space + @object_space.each_object(Class) do |c| + cases << c if(c < TestCase && !ignore.include?(c)) + end + else + TestCase::DECENDANT_CLASSES.each do |c| + cases << c if !ignore.include?(c) + end end ignore.concat(cases) cases Index: mvm/lib/test/unit/collector/objectspace.rb =================================================================== --- mvm/lib/test/unit/collector/objectspace.rb (revision 17888) +++ mvm/lib/test/unit/collector/objectspace.rb (revision 17889) @@ -10,9 +10,9 @@ class ObjectSpace include Test::Unit::Collector - NAME = 'collected from the ObjectSpace' + NAME = 'collected from the subclasses of TestSuite' - def initialize(source=::ObjectSpace) + def initialize(source=nil) super() @source = source end @@ -20,8 +20,14 @@ def collect(name=NAME) suite = TestSuite.new(name) sub_suites = [] - @source.each_object(Class) do |klass| - if(Test::Unit::TestCase > klass) + if @source + @source.each_object(Class) do |klass| + if(Test::Unit::TestCase > klass) + add_suite(sub_suites, klass.suite) + end + end + else + TestCase::DECENDANT_CLASSES.each do |klass| add_suite(sub_suites, klass.suite) end end Index: mvm/lib/test/unit/testcase.rb =================================================================== --- mvm/lib/test/unit/testcase.rb (revision 17888) +++ mvm/lib/test/unit/testcase.rb (revision 17889) @@ -34,6 +34,11 @@ PASSTHROUGH_EXCEPTIONS = [NoMemoryError, SignalException, Interrupt, SystemExit] + DECENDANT_CLASSES = [] + def self.inherited(decendant) + DECENDANT_CLASSES << decendant + end + # Creates a new instance of the fixture for running the # test represented by test_method_name. def initialize(test_method_name) Index: mvm/lib/net/smtp.rb =================================================================== --- mvm/lib/net/smtp.rb (revision 17888) +++ mvm/lib/net/smtp.rb (revision 17889) @@ -437,7 +437,7 @@ # +port+ is the port to connect to; it defaults to port 25. # # +helo+ is the _HELO_ _domain_ provided by the client to the - # server (see overview comments); it defaults to 'localhost.localdomain'. + # server (see overview comments); it defaults to 'localhost'. # # The remaining arguments are used for SMTP authentication, if required # or desired. +user+ is the account name; +secret+ is your password @@ -457,7 +457,7 @@ # * IOError # * TimeoutError # - def SMTP.start(address, port = nil, helo = 'localhost.localdomain', + def SMTP.start(address, port = nil, helo = 'localhost', user = nil, secret = nil, authtype = nil, &block) # :yield: smtp new(address, port).start(helo, user, secret, authtype, &block) @@ -518,7 +518,7 @@ # * IOError # * TimeoutError # - def start(helo = 'localhost.localdomain', + def start(helo = 'localhost', user = nil, secret = nil, authtype = nil) # :yield: smtp if block_given? begin Index: mvm/lib/net/ftp.rb =================================================================== --- mvm/lib/net/ftp.rb (revision 17888) +++ mvm/lib/net/ftp.rb (revision 17889) @@ -296,12 +296,9 @@ def sendport(host, port) af = (@sock.peeraddr)[0] if af == "AF_INET" - hbytes = host.split(".") - pbytes = [port / 256, port % 256] - bytes = hbytes + pbytes - cmd = "PORT " + bytes.join(",") + cmd = "PORT " + (host.split(".") + port.divmod(256)).join(",") elsif af == "AF_INET6" - cmd = "EPRT |2|" + host + "|" + sprintf("%d", port) + "|" + cmd = sprintf("EPRT |2|%s|%d|", host, port) else raise FTPProtoError, host end Index: mvm/thread.c =================================================================== --- mvm/thread.c (revision 17888) +++ mvm/thread.c (revision 17889) @@ -498,7 +498,7 @@ rb_raise(rb_eThreadError, "already initialized thread - %s", file); } - rb_raise(rb_eThreadError, "already initialized thread - %s:%d", + rb_raise(rb_eThreadError, "already initialized thread - %s:%ld", file, NUM2INT(line)); } return thread_create_core(thread, args, 0); @@ -2127,11 +2127,10 @@ static void clear_coverage(void) { - if (rb_const_defined_at(rb_cObject, rb_intern("COVERAGE__"))) { - VALUE hash = rb_const_get_at(rb_cObject, rb_intern("COVERAGE__")); - if (TYPE(hash) == T_HASH) { - st_foreach(RHASH_TBL(hash), clear_coverage_i, 0); - } + extern VALUE rb_vm_get_coverages(void); + VALUE coverages = rb_vm_get_coverages(); + if (RTEST(coverages)) { + st_foreach(RHASH_TBL(coverages), clear_coverage_i, 0); } } @@ -3596,3 +3595,34 @@ { return ruby_vm_specific_ptr(GET_VM(), key); } + +static void +update_coverage(rb_event_flag_t event, VALUE proc, VALUE self, ID id, VALUE klass) +{ + VALUE coverage = GET_THREAD()->cfp->iseq->coverage; + if (coverage) { + long line = rb_sourceline() - 1; + long count; + if (RARRAY_PTR(coverage)[line] == Qnil) { + rb_bug("bug"); + } + count = FIX2LONG(RARRAY_PTR(coverage)[line]) + 1; + if (POSFIXABLE(count)) { + RARRAY_PTR(coverage)[line] = LONG2FIX(count); + } + } +} + +void +rb_enable_coverages(void) +{ + VALUE rb_mCoverage; + + if (!RTEST(GET_VM()->coverages)) { + extern VALUE rb_vm_get_coverages(void); + GET_VM()->coverages = rb_hash_new(); + rb_add_event_hook(update_coverage, RUBY_EVENT_COVERAGE, Qnil); + rb_mCoverage = rb_define_module("Coverage"); + rb_define_module_function(rb_mCoverage, "result", rb_vm_get_coverages, 0); + } +} Index: mvm/eval.c =================================================================== --- mvm/eval.c (revision 17888) +++ mvm/eval.c (revision 17889) @@ -1223,7 +1223,7 @@ rb_define_virtual_variable("$SAFE", safe_getter, safe_setter); - exception_error = rb_exc_new2(rb_eFatal, + exception_error = rb_exc_new3(rb_eFatal, rb_obj_freeze(rb_str_new2("exception reentered"))); rb_ivar_set(exception_error, idThrowState, INT2FIX(TAG_FATAL)); OBJ_TAINT(exception_error); Index: mvm/gc.c =================================================================== --- mvm/gc.c (revision 17888) +++ mvm/gc.c (revision 17889) @@ -129,17 +129,10 @@ #pragma pack(pop) #endif -enum slot_color { - WHITE = 0x00, /* garbage */ - BLACK = 0x01, /* used */ - GRAY = 0x02, /* not sweep */ -}; - struct heaps_slot { void *membase; RVALUE *slot; int limit; - enum slot_color color; }; #define HEAP_MIN_SLOTS 10000 @@ -169,11 +162,6 @@ RVALUE *freelist; RVALUE *range[2]; RVALUE *freed; - size_t live; - size_t dead; - size_t do_heap_free; - size_t sweep_index; - size_t sweep_increment; } heap; struct { int dont_gc; @@ -212,11 +200,6 @@ #define himem objspace->heap.range[1] #define heaps_inc objspace->heap.increment #define heaps_freed objspace->heap.freed -#define live objspace->heap.live -#define dead objspace->heap.dead -#define do_heap_free objspace->heap.do_heap_free -#define heaps_sweep_index objspace->heap.sweep_index -#define heaps_sweep_inc objspace->heap.sweep_increment #define dont_gc objspace->flags.dont_gc #define during_gc objspace->flags.during_gc #define finalizer_table objspace->final.table @@ -266,7 +249,6 @@ static void run_final(rb_objspace_t *objspace, VALUE obj); static int garbage_collect(rb_objspace_t *objspace); -static int garbage_collect_force(rb_objspace_t *objspace); void rb_global_variable(VALUE *var) @@ -343,11 +325,11 @@ if ((ruby_gc_stress && !ruby_disable_gc_stress) || (malloc_increase+size) > malloc_limit) { - garbage_collect_force(objspace); + garbage_collect(objspace); } RUBY_CRITICAL(mem = malloc(size)); if (!mem) { - if (garbage_collect_force(objspace)) { + if (garbage_collect(objspace)) { RUBY_CRITICAL(mem = malloc(size)); } if (!mem) { @@ -383,9 +365,10 @@ objspace->malloc_params.allocated_size -= size; ptr = (size_t *)ptr - 1; #endif + RUBY_CRITICAL(mem = realloc(ptr, size)); if (!mem) { - if (garbage_collect_force(objspace)) { + if (garbage_collect(objspace)) { RUBY_CRITICAL(mem = realloc(ptr, size)); } if (!mem) { @@ -576,8 +559,6 @@ heaps_length = next_heaps_length; } -#define RANY(o) ((RVALUE*)(o)) - static void assign_heap_slot(rb_objspace_t *objspace) { @@ -621,7 +602,6 @@ heaps[hi].membase = membase; heaps[hi].slot = p; heaps[hi].limit = objs; - heaps[hi].color = BLACK; pend = p + objs; if (lomem == 0 || lomem > p) lomem = p; if (himem < pend) himem = pend; @@ -633,9 +613,6 @@ freelist = p; p++; } - if (hi < heaps_sweep_index) { - heaps_sweep_index++; - } } static void @@ -678,13 +655,15 @@ return Qfalse; } +#define RANY(o) ((RVALUE*)(o)) + static VALUE rb_newobj_from_heap(rb_objspace_t *objspace) { VALUE obj; if ((ruby_gc_stress && !ruby_disable_gc_stress) || !freelist) { - if (!garbage_collect(objspace)) { + if (!heaps_increment(objspace) && !garbage_collect(objspace)) { rb_memerror(); } } @@ -1065,7 +1044,6 @@ if (obj->as.basic.flags == 0) return; /* free cell */ if (obj->as.basic.flags & FL_MARK) return; /* already marked */ obj->as.basic.flags |= FL_MARK; - live++; if (lev > GC_LEVEL_MAX || (lev == 0 && ruby_stack_check())) { if (!mark_stack_overflow) { @@ -1101,7 +1079,6 @@ if (obj->as.basic.flags == 0) return; /* free cell */ if (obj->as.basic.flags & FL_MARK) return; /* already marked */ obj->as.basic.flags |= FL_MARK; - live++; marking: if (FL_TEST(obj, FL_EXIVAR)) { @@ -1361,133 +1338,139 @@ if (!FL_TEST(p, FL_SINGLETON)) { /* not freeing page */ VALGRIND_MAKE_MEM_UNDEFINED((void*)p, sizeof(RVALUE)); p->as.free.flags = 0; + p->as.free.next = freelist; + freelist = p; } p = tmp; } } -void rb_gc_abort_threads(void); - -static int -slot_sweep(rb_objspace_t *objspace, struct heaps_slot *target) +static void +free_unused_heaps(rb_objspace_t *objspace) { - RVALUE *p, *pend, *free; - RVALUE *final; - int freed = 0; + size_t i, j; + RVALUE *last = 0; - if (target->color == BLACK || target->color == WHITE) { - return Qfalse; - } - - final = deferred_final_list; - free = freelist; - p = target->slot; pend = p + target->limit; - while (p < pend) { - if (!(p->as.basic.flags & FL_MARK)) { - if (p->as.basic.flags) { - obj_free(objspace, (VALUE)p); + for (i = j = 1; j < heaps_used; i++) { + if (heaps[i].limit == 0) { + if (!last) { + last = heaps[i].membase; } - if (need_call_final && FL_TEST(p, FL_FINALIZE)) { - p->as.free.flags = FL_MARK; /* remain marked */ - p->as.free.next = deferred_final_list; - deferred_final_list = p; - } else { - VALGRIND_MAKE_MEM_UNDEFINED((void*)p, sizeof(RVALUE)); - p->as.free.flags = 0; - p->as.free.next = freelist; - freelist = p; + free(heaps[i].membase); } - freed++; + heaps_used--; } - else if (RBASIC(p)->flags == FL_MARK) { - /* objects to be finalized */ - /* do nothing remain marked */ - } else { - p->as.basic.flags &= ~FL_MARK; + if (i != j) { + heaps[j] = heaps[i]; + } + j++; } - p++; } - dead += freed; - if (freed == target->limit && dead > do_heap_free) { - RVALUE *pp; - - target->limit = 0; - target->color = WHITE; - for (pp = deferred_final_list; pp != final; pp = pp->as.free.next) { - pp->as.free.flags |= FL_SINGLETON; /* freeing page mark */ + if (last) { + if (last < heaps_freed) { + free(heaps_freed); + heaps_freed = last; } - freelist = free; /* cancel this page from freelist */ + else { + free(last); + } } - else { - target->color = BLACK; - } - return Qtrue; } static void -heap_sweep_increment(rb_objspace_t *objspace) +gc_sweep(rb_objspace_t *objspace) { - int i = 0; + RVALUE *p, *pend, *final_list; + size_t freed = 0; + size_t i; + size_t live = 0, free_min = 0, do_heap_free = 0; - while (i < heaps_sweep_inc && heaps_sweep_index < heaps_used) { - if (slot_sweep(objspace, &heaps[heaps_sweep_index])) { - i++; - } - heaps_sweep_index++; + do_heap_free = (heaps_used * HEAP_OBJ_LIMIT) * 0.65; + free_min = (heaps_used * HEAP_OBJ_LIMIT) * 0.2; + if (free_min < FREE_MIN) { + do_heap_free = heaps_used * HEAP_OBJ_LIMIT; + free_min = FREE_MIN; } -} -static void -heap_sweep(rb_objspace_t *objspace) -{ - while (!freelist && heaps_sweep_index < heaps_used) { - slot_sweep(objspace, &heaps[heaps_sweep_index]); - heaps_sweep_index++; - } -} + freelist = 0; + final_list = deferred_final_list; + deferred_final_list = 0; + for (i = 0; i < heaps_used; i++) { + int n = 0; + RVALUE *free = freelist; + RVALUE *final = final_list; -#define GC_NOT_LAZY_SWEEP 0 + p = heaps[i].slot; pend = p + heaps[i].limit; + while (p < pend) { + if (!(p->as.basic.flags & FL_MARK)) { + if (p->as.basic.flags) { + obj_free(objspace, (VALUE)p); + } + if (need_call_final && FL_TEST(p, FL_FINALIZE)) { + p->as.free.flags = FL_MARK; /* remain marked */ + p->as.free.next = final_list; + final_list = p; + } + else { + VALGRIND_MAKE_MEM_UNDEFINED((void*)p, sizeof(RVALUE)); + p->as.free.flags = 0; + p->as.free.next = freelist; + freelist = p; + } + n++; + } + else if (RBASIC(p)->flags == FL_MARK) { + /* objects to be finalized */ + /* do nothing remain marked */ + } + else { + RBASIC(p)->flags &= ~FL_MARK; + live++; + } + p++; + } + if (n == heaps[i].limit && freed > do_heap_free) { + RVALUE *pp; -#ifdef GC_NOT_LAZY_SWEEP -static void -heap_all_sweep(rb_objspace_t *objspace) -{ - while (heaps_sweep_index < heaps_used) { - slot_sweep(objspace, &heaps[heaps_sweep_index]); - heaps_sweep_index++; + heaps[i].limit = 0; + for (pp = final_list; pp != final; pp = pp->as.free.next) { + p->as.free.flags |= FL_SINGLETON; /* freeing page mark */ + } + freelist = free; /* cancel this page from freelist */ + } + else { + freed += n; + } } -} -#endif - -static int -gc_lazy_sweep(rb_objspace_t *objspace, rb_thread_t *th) -{ - - if (heaps_increment(objspace)) { - heap_sweep_increment(objspace); + if (malloc_increase > malloc_limit) { + malloc_limit += (malloc_increase - malloc_limit) * (double)live / (live + freed); + if (malloc_limit < GC_MALLOC_LIMIT) malloc_limit = GC_MALLOC_LIMIT; } - else { - heap_sweep(objspace); + malloc_increase = 0; + if (freed < free_min) { + set_heaps_increment(objspace); + heaps_increment(objspace); } + during_gc = 0; -#ifdef GC_NOT_LAZY_SWEEP - if (GC_NOT_LAZY_SWEEP) heap_all_sweep(objspace); -#endif - - if (!freelist) { - return Qfalse; + /* clear finalization list */ + if (final_list) { + deferred_final_list = final_list; + return; } - - return Qtrue; + free_unused_heaps(objspace); } void rb_gc_force_recycle(VALUE p) { + rb_objspace_t *objspace = &rb_objspace; VALGRIND_MAKE_MEM_UNDEFINED((void*)p, sizeof(RVALUE)); RANY(p)->as.free.flags = 0; + RANY(p)->as.free.next = freelist; + freelist = RANY(p); } static void @@ -1688,87 +1671,30 @@ void rb_gc_mark_encodings(void); -static void -gc_mark_all_clear(rb_objspace_t *objspace) +static int +garbage_collect(rb_objspace_t *objspace) { - RVALUE *last = 0; - size_t i, j; - - for (i = j = 0; j < heaps_used; i++) { - if (heaps[i].color == WHITE && !deferred_final_list) { - if (!last) { - last = heaps[i].membase; - } - else { - free(heaps[i].membase); - } - heaps_used--; - } - else { - if (heaps[i].color == GRAY) { - RVALUE *p, *pend; - p = heaps[i].slot; pend = p + heaps[i].limit; - while (p < pend) { - if (!(RBASIC(p)->flags & FL_MARK)) { - if (p->as.basic.flags && !FL_TEST(p, FL_FINALIZE)) { - obj_free(objspace, (VALUE)p); - VALGRIND_MAKE_MEM_UNDEFINED((void*)p, sizeof(RVALUE)); - p->as.free.flags = 0; - } - } - else if (RBASIC(p)->flags != FL_MARK) { - p->as.basic.flags &= ~FL_MARK; - } - p++; - } - } - else { - heaps[i].color = GRAY; - } - if (i != j) { - heaps[j] = heaps[i]; - } - j++; - } - } - if (last) { - if (last < heaps_freed) { - free(heaps_freed); - heaps_freed = last; - } - else { - free(last); - } - } -} + struct gc_list *list; + rb_thread_t *th = GET_THREAD(); -static void -set_lazy_sweep_params(rb_objspace_t *objspace) -{ - size_t free_min = 0; + if (GC_NOTIFY) printf("start garbage_collect()\n"); - dead = 0; - heaps_sweep_index = 0; - heaps_sweep_inc = (heaps_used / 10) + 1; - do_heap_free = (heaps_used * HEAP_OBJ_LIMIT) * 0.65; - free_min = (heaps_used * HEAP_OBJ_LIMIT) * 0.2; - if (free_min < FREE_MIN) free_min = FREE_MIN; - if (free_min > (heaps_used * HEAP_OBJ_LIMIT - live)) { - set_heaps_increment(objspace); - heaps_sweep_inc = (heaps_used + heaps_sweep_inc) / heaps_sweep_inc + 1; + if (!heaps) { + return Qfalse; } -} -static void -gc_marks(rb_objspace_t *objspace, rb_thread_t *th) -{ - struct gc_list *list; + if (dont_gc || during_gc) { + if (!freelist) { + if (!heaps_increment(objspace)) { + set_heaps_increment(objspace); + heaps_increment(objspace); + } + } + return Qtrue; + } + during_gc++; + objspace->count++; - live = 0; - freelist = 0; - - gc_mark_all_clear(objspace); - SET_STACK_END; init_mark_stack(objspace); @@ -1785,7 +1711,6 @@ rb_gc_mark_symbols(); rb_gc_mark_encodings(); - /* mark protected global variables */ for (list = global_List; list; list = list->next) { rb_gc_mark_maybe(*list->varptr); @@ -1811,51 +1736,9 @@ } } - set_lazy_sweep_params(objspace); -} + gc_sweep(objspace); -static int -garbage_collect_force(rb_objspace_t *objspace) -{ - if (malloc_increase > malloc_limit) { - malloc_limit += (malloc_increase - malloc_limit) * (double)live / (heaps_used * HEAP_OBJ_LIMIT); - if (malloc_limit < GC_MALLOC_LIMIT) malloc_limit = GC_MALLOC_LIMIT; - } - malloc_increase = 0; - gc_marks(objspace, GET_THREAD()); - return garbage_collect(objspace); -} - -static int -garbage_collect(rb_objspace_t *objspace) -{ - rb_thread_t *th = GET_THREAD(); - - if (GC_NOTIFY) printf("start garbage_collect()\n"); - - if (!heaps) { - return Qfalse; - } - - if (dont_gc || during_gc) { - if (!freelist) { - if (!heaps_increment(objspace)) { - set_heaps_increment(objspace); - heaps_increment(objspace); - } - } - return Qtrue; - } - during_gc++; - objspace->count++; - - while (!gc_lazy_sweep(objspace, th)) { - gc_marks(objspace, th); - } - if (GC_NOTIFY) printf("end garbage_collect()\n"); - during_gc = 0; - return Qtrue; } @@ -2155,6 +2038,7 @@ if (p) { finalize_list(objspace, p); } + free_unused_heaps(objspace); } void @@ -2226,8 +2110,8 @@ rb_gc(void) { rb_objspace_t *objspace = &rb_objspace; - gc_finalize_deferred(objspace); garbage_collect(objspace); + gc_finalize_deferred(objspace); } /* Index: mvm/parse.y =================================================================== --- mvm/parse.y (revision 17888) +++ mvm/parse.y (revision 17889) @@ -4672,17 +4672,16 @@ static VALUE coverage(const char *f, int n) { - if (rb_const_defined_at(rb_cObject, rb_intern("COVERAGE__"))) { - VALUE hash = rb_const_get_at(rb_cObject, rb_intern("COVERAGE__")); - if (TYPE(hash) == T_HASH) { - VALUE fname = rb_str_new2(f); - VALUE lines = rb_ary_new2(n); - int i; - for (i = 0; i < n; i++) RARRAY_PTR(lines)[i] = Qnil; - RARRAY(lines)->len = n; - rb_hash_aset(hash, fname, lines); - return lines; - } + extern VALUE rb_vm_get_coverages(void); + VALUE coverages = rb_vm_get_coverages(); + if (RTEST(coverages)) { + VALUE fname = rb_str_new2(f); + VALUE lines = rb_ary_new2(n); + int i; + for (i = 0; i < n; i++) RARRAY_PTR(lines)[i] = Qnil; + RARRAY(lines)->len = n; + rb_hash_aset(coverages, fname, lines); + return lines; } return 0; } Index: mvm/ext/coverage/extconf.rb =================================================================== --- mvm/ext/coverage/extconf.rb (revision 0) +++ mvm/ext/coverage/extconf.rb (revision 17889) @@ -0,0 +1,2 @@ +require 'mkmf' +create_makefile('coverage') Property changes on: mvm/ext/coverage/extconf.rb ___________________________________________________________________ Name: svn:eol-style + LF Index: mvm/ext/coverage/coverage.c =================================================================== --- mvm/ext/coverage/coverage.c (revision 0) +++ mvm/ext/coverage/coverage.c (revision 17889) @@ -0,0 +1,47 @@ +/************************************************ + + coverage.c - + + $Author: $ + + Copyright (c) 2008 Yusuke Endoh + +************************************************/ + +#include "ruby.h" + +extern void rb_enable_coverages(void); + +/* Coverage provides coverage measurement feature for Ruby. + * + * = Usage + * + * (1) require "coverage.so" + * (2) require or load Ruby source file + * (3) Coverage.result will return a hash that contains filename as key and + * coverage array as value. + * + * = Example + * + * [foo.rb] + * s = 0 + * 10.times do |x| + * s += x + * end + * + * if s == 45 + * p :ok + * else + * p :ng + * end + * [EOF] + * + * require "coverage.so" + * require "foo.rb" + * p COVERAGE__ #=> {"foo.rb"=>[1, 1, 10, nil, nil, 1, 1, nil, 0, nil]} + */ +void +Init_coverage(void) +{ + rb_enable_coverages(); +} Property changes on: mvm/ext/coverage/coverage.c ___________________________________________________________________ Name: svn:eol-style + LF Property changes on: mvm/ext/coverage ___________________________________________________________________ Name: svn:ignore + extconf.h Makefile Index: mvm/ext/win32ole/win32ole.c =================================================================== --- mvm/ext/win32ole/win32ole.c (revision 17888) +++ mvm/ext/win32ole/win32ole.c (revision 17889) @@ -24,6 +24,7 @@ #include <olectl.h> #include <ole2.h> #include <stdlib.h> +#include <math.h> #ifdef HAVE_STDARG_PROTOTYPES #include <stdarg.h> #define va_init_list(a,b) va_start(a,b) @@ -117,7 +118,7 @@ #define WC2VSTR(x) ole_wc2vstr((x), TRUE) -#define WIN32OLE_VERSION "1.1.8" +#define WIN32OLE_VERSION "1.2.0" typedef HRESULT (STDAPICALLTYPE FNCOCREATEINSTANCEEX) (REFCLSID, IUnknown*, DWORD, COSERVERINFO*, DWORD, MULTI_QI*); @@ -367,6 +368,7 @@ static VALUE ole_typelib_from_itypeinfo(ITypeInfo *pTypeInfo); static VALUE fole_typelib(VALUE self); static VALUE fole_query_interface(VALUE self, VALUE str_iid); +static VALUE fole_respond_to(VALUE self, VALUE method); static HRESULT ole_docinfo_from_type(ITypeInfo *pTypeInfo, BSTR *name, BSTR *helpstr, DWORD *helpcontext, BSTR *helpfile); static VALUE ole_usertype2val(ITypeInfo *pTypeInfo, TYPEDESC *pTypeDesc, VALUE typedetails); static VALUE ole_ptrtype2val(ITypeInfo *pTypeInfo, TYPEDESC *pTypeDesc, VALUE typedetails); @@ -763,7 +765,7 @@ double d_hh, d_mm, d_ss; int i_hh, i_mm, i_ss; - double d = v * 86400.0; + double d = fabs(v * 86400.0); d_hh = d / 3600.0; i_hh = (int)d_hh; @@ -4373,6 +4375,32 @@ return create_win32ole_object(cWIN32OLE, pDispatch, 0, 0); } +/* + * call-seq: + * WIN32OLE#ole_respond_to?(method) -> true or false + * + * Returns true when OLE object has OLE method, otherwise returns false. + * + * ie = WIN32OLE.new('InternetExplorer.Application') + * ie.ole_respond_to?("gohome") => true + */ +static VALUE +fole_respond_to(VALUE self, VALUE method) +{ + struct oledata *pole; + BSTR wcmdname; + DISPID DispID; + HRESULT hr; + rb_secure(4); + Check_SafeStr(method); + OLEData_Get_Struct(self, pole); + wcmdname = ole_vstr2wc(method); + hr = pole->pDispatch->lpVtbl->GetIDsOfNames( pole->pDispatch, &IID_NULL, + &wcmdname, 1, cWIN32OLE_lcid, &DispID); + SysFreeString(wcmdname); + return SUCCEEDED(hr) ? Qtrue : Qfalse; +} + static HRESULT ole_docinfo_from_type(ITypeInfo *pTypeInfo, BSTR *name, BSTR *helpstr, DWORD *helpcontext, BSTR *helpfile) { @@ -8281,7 +8309,6 @@ message_filter.MessagePending = mf_MessagePending; com_hash = Data_Wrap_Struct(rb_cData, rb_mark_hash, st_free_table, st_init_numtable()); - com_hash = Data_Wrap_Struct(rb_cData, rb_mark_hash, st_free_table, st_init_numtable()); rb_register_mark_object(com_hash); cWIN32OLE = rb_define_class("WIN32OLE", rb_cObject); @@ -8331,6 +8358,7 @@ rb_define_alias(cWIN32OLE, "ole_obj_help", "ole_type"); rb_define_method(cWIN32OLE, "ole_typelib", fole_typelib, 0); rb_define_method(cWIN32OLE, "ole_query_interface", fole_query_interface, 1); + rb_define_method(cWIN32OLE, "ole_respond_to?", fole_respond_to, 1); rb_define_const(cWIN32OLE, "VERSION", rb_str_new2(WIN32OLE_VERSION)); rb_define_const(cWIN32OLE, "ARGV", rb_ary_new()); Index: mvm/.merged-trunk-revision =================================================================== --- mvm/.merged-trunk-revision (revision 17888) +++ mvm/.merged-trunk-revision (revision 17889) @@ -1 +1 @@ -17835 +17888 Index: mvm/numeric.c =================================================================== --- mvm/numeric.c (revision 17888) +++ mvm/numeric.c (revision 17889) @@ -1615,9 +1615,10 @@ { unsigned long num = rb_num2ulong(val); - if (RTEST(rb_funcall(INT2FIX(0), '<', 1, val))) { + if (RTEST(rb_funcall(val, '<', 1, INT2FIX(0)))) + check_int(num); + else check_uint(num); - } return num; } @@ -1630,9 +1631,10 @@ return rb_num2uint(val); } num = FIX2ULONG(val); - if (FIX2LONG(val) > 0) { + if (RTEST(rb_funcall(val, '<', 1, INT2FIX(0)))) + check_int(num); + else check_uint(num); - } return num; } #else Index: mvm/vm.c =================================================================== --- mvm/vm.c (revision 17888) +++ mvm/vm.c (revision 17889) @@ -1395,6 +1395,7 @@ RUBY_MARK_UNLESS_NULL(vm->load_path); RUBY_MARK_UNLESS_NULL(vm->loaded_features); RUBY_MARK_UNLESS_NULL(vm->top_self); + RUBY_MARK_UNLESS_NULL(vm->coverages); rb_gc_mark_locations(vm->special_exceptions, vm->special_exceptions + ruby_special_error_count - 1); if (vm->loading_table) { @@ -1915,3 +1916,9 @@ { return ruby_vm_debug_ptr(GET_VM()); } + +VALUE +rb_vm_get_coverages(void) +{ + return GET_VM()->coverages; +} Index: mvm/version.h =================================================================== --- mvm/version.h (revision 17888) +++ mvm/version.h (revision 17889) @@ -1,7 +1,7 @@ #define RUBY_VERSION "1.9.0" -#define RUBY_RELEASE_DATE "2008-07-03" +#define RUBY_RELEASE_DATE "2008-07-05" #define RUBY_VERSION_CODE 190 -#define RUBY_RELEASE_CODE 20080703 +#define RUBY_RELEASE_CODE 20080705 #define RUBY_PATCHLEVEL 0 #define RUBY_VERSION_MAJOR 1 @@ -9,7 +9,7 @@ #define RUBY_VERSION_TEENY 0 #define RUBY_RELEASE_YEAR 2008 #define RUBY_RELEASE_MONTH 7 -#define RUBY_RELEASE_DAY 3 +#define RUBY_RELEASE_DAY 5 #ifdef RUBY_EXTERN RUBY_EXTERN const char ruby_version[]; Index: mvm/test/ruby/test_m17n.rb =================================================================== --- mvm/test/ruby/test_m17n.rb (revision 17888) +++ mvm/test/ruby/test_m17n.rb (revision 17889) @@ -493,6 +493,33 @@ assert_match(/[[:space:]]/, "\u{00a0}") end + def test_regexp_property + s = '\p{Hiragana}'.force_encoding("euc-jp") + assert_equal(Encoding::EUC_JP, s.encoding) + r = nil + assert_nothing_raised { + r = Regexp.new(s) + } + assert(r.fixed_encoding?) + assert_match(r, "\xa4\xa2".force_encoding("euc-jp")) + + r = eval('/\p{Hiragana}/'.force_encoding("euc-jp")) + assert(r.fixed_encoding?) + assert_match(r, "\xa4\xa2".force_encoding("euc-jp")) + + r = /\p{Hiragana}/e + assert(r.fixed_encoding?) + assert_match(r, "\xa4\xa2".force_encoding("euc-jp")) + + r = eval('/\u{3042}\p{Hiragana}/'.force_encoding("euc-jp")) + assert(r.fixed_encoding?) + assert_equal(Encoding::UTF_8, r.encoding) + + r = eval('/\p{Hiragana}\u{3042}/'.force_encoding("euc-jp")) + assert(r.fixed_encoding?) + assert_equal(Encoding::UTF_8, r.encoding) + end + def test_regexp_embed_preprocess r1 = /\xa4\xa2/e r2 = /#{r1}/ Index: mvm/test/win32ole/test_win32ole.rb =================================================================== --- mvm/test/win32ole/test_win32ole.rb (revision 17888) +++ mvm/test/win32ole/test_win32ole.rb (revision 17889) @@ -246,6 +246,16 @@ assert_instance_of(WIN32OLE, shell2) end + def test_ole_respond_to + fso = WIN32OLE.new('Scripting.FileSystemObject') + assert(fso.ole_respond_to?('getFolder')) + assert(fso.ole_respond_to?('GETFOLDER')) + assert(!fso.ole_respond_to?('XXXXX')) + assert_raise(TypeError) { + assert_raise(fso.ole_respond_to?(1)) + } + end + def test_s_const_load assert(!defined?(CONST1::SsfWINDOWS)) shell=WIN32OLE.new('Shell.Application') Index: mvm/test/win32ole/test_win32ole_variant.rb =================================================================== --- mvm/test/win32ole/test_win32ole_variant.rb (revision 17888) +++ mvm/test/win32ole/test_win32ole_variant.rb (revision 17889) @@ -540,6 +540,44 @@ } end + def test_conversion_vt_date + obj = WIN32OLE_VARIANT.new(-657434, WIN32OLE::VARIANT::VT_DATE) + assert_equal("0100/01/01 00:00:00", obj.value) + + obj = WIN32OLE_VARIANT.new("1500/12/29 23:59:59", WIN32OLE::VARIANT::VT_DATE) + assert_equal("1500/12/29 23:59:59", obj.value) + + obj = WIN32OLE_VARIANT.new("1500/12/30 00:00:00", WIN32OLE::VARIANT::VT_DATE) + assert_equal("1500/12/30 00:00:00", obj.value) + + obj = WIN32OLE_VARIANT.new("1500/12/30 00:00:01", WIN32OLE::VARIANT::VT_DATE) + assert_equal("1500/12/30 00:00:01", obj.value) + + obj = WIN32OLE_VARIANT.new("1899/12/29 23:59:59", WIN32OLE::VARIANT::VT_DATE) + assert_equal("1899/12/29 23:59:59", obj.value) + + obj = WIN32OLE_VARIANT.new("1899/12/30 00:00:00", WIN32OLE::VARIANT::VT_DATE) + assert_equal("1899/12/30 00:00:00", obj.value) + + obj = WIN32OLE_VARIANT.new("1899/12/30 00:00:01", WIN32OLE::VARIANT::VT_DATE) + assert_equal("1899/12/30 00:00:01", obj.value) + + obj = WIN32OLE_VARIANT.new(0, WIN32OLE::VARIANT::VT_DATE) + assert_equal("1899/12/30 00:00:00", obj.value) + + obj = WIN32OLE_VARIANT.new("2008/12/29 23:59:59", WIN32OLE::VARIANT::VT_DATE) + assert_equal("2008/12/29 23:59:59", obj.value) + + obj = WIN32OLE_VARIANT.new("2008/12/30 00:00:00", WIN32OLE::VARIANT::VT_DATE) + assert_equal("2008/12/30 00:00:00", obj.value) + + obj = WIN32OLE_VARIANT.new("2008/12/30 00:00:01", WIN32OLE::VARIANT::VT_DATE) + assert_equal("2008/12/30 00:00:01", obj.value) + + obj = WIN32OLE_VARIANT.new("9999/12/31 23:59:59", WIN32OLE::VARIANT::VT_DATE) + assert_equal("9999/12/31 23:59:59", obj.value) + end + def test_create_nil_dispatch var = WIN32OLE_VARIANT.new(nil, WIN32OLE::VARIANT::VT_DISPATCH) assert_nil(var.value) Index: mvm/test/win32ole/test_word.rb =================================================================== --- mvm/test/win32ole/test_word.rb (revision 17888) +++ mvm/test/win32ole/test_word.rb (revision 17889) @@ -7,39 +7,66 @@ end require "test/unit" -if defined?(WIN32OLE) - class TestWIN32OLE_WITH_WORD < Test::Unit::TestCase - - def setup - begin - @obj = WIN32OLE.new('Word.Application') - rescue WIN32OLERuntimeError - @obj = nil +def word_installed? + installed = false + w = nil + if defined?(WIN32OLE) + begin + w = WIN32OLE.new('Word.Application') + installed = true + rescue + ensure + if w + w.quit + w = nil end end + end + return installed +end - def test_ole_methods - if @obj - @obj.visible = true - @obj.wordbasic.disableAutoMacros(true) - assert(true) +if defined?(WIN32OLE) + w = nil + dotest = word_installed? + if !dotest + STDERR.puts("\n#{__FILE__} skipped(Microsoft Word not found.)") + end + if dotest + class TestWIN32OLE_WITH_WORD < Test::Unit::TestCase + def setup + begin + @obj = WIN32OLE.new('Word.Application') + rescue WIN32OLERuntimeError + @obj = nil + if !$skipped + $skipped = true + end + end end - end - def test_s_connect - if @obj - obj2 = WIN32OLE.connect("Word.Application") - assert_instance_of(WIN32OLE, obj2) - obj2.visible = true + def test_ole_methods + if @obj + @obj.visible = true + @obj.wordbasic.disableAutoMacros(true) + assert(true) + else + end end - end - def teardown - if @obj - @obj.quit - @obj = nil + def test_s_connect + if @obj + obj2 = WIN32OLE.connect("Word.Application") + assert_instance_of(WIN32OLE, obj2) + obj2.visible = true + end end + + def teardown + if @obj + @obj.quit + @obj = nil + end + end end - end end Index: mvm/test/test_singleton.rb =================================================================== --- mvm/test/test_singleton.rb (revision 0) +++ mvm/test/test_singleton.rb (revision 17889) @@ -0,0 +1,15 @@ +require 'test/unit' +require 'singleton' + +class TestSingleton < Test::Unit::TestCase + class C + include Singleton + end + + def test_marshal + o1 = C.instance + m = Marshal.dump(o1) + o2 = Marshal.load(m) + assert_same(o1, o2) + end +end Property changes on: mvm/test/test_singleton.rb ___________________________________________________________________ Name: svn:eol-style + LF -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/