[前][次][番号順一覧][スレッド一覧]

ruby-changes:9026

From: nobu <ko1@a...>
Date: Sat, 6 Dec 2008 10:58:55 +0900 (JST)
Subject: [ruby-changes:9026] Ruby:r20562 (mvm): * merged from trunk r20375:20561.

nobu	2008-12-06 10:57:53 +0900 (Sat, 06 Dec 2008)

  New Revision: 20562

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=20562

  Log:
    * merged from trunk r20375:20561.

  Added files:
    branches/mvm/man/rake.1
    branches/mvm/test/test_open3.rb
  Modified files:
    branches/mvm/.merged-trunk-revision
    branches/mvm/ChangeLog
    branches/mvm/bootstraptest/test_autoload.rb
    branches/mvm/compile.c
    branches/mvm/complex.c
    branches/mvm/cont.c
    branches/mvm/enumerator.c
    branches/mvm/ext/bigdecimal/bigdecimal.c
    branches/mvm/ext/curses/curses.c
    branches/mvm/ext/openssl/ossl_ssl.c
    branches/mvm/ext/pty/pty.c
    branches/mvm/ext/socket/socket.c
    branches/mvm/ext/stringio/stringio.c
    branches/mvm/ext/tk/lib/tk/menu.rb
    branches/mvm/ext/tk/lib/tk.rb
    branches/mvm/ext/tk/tcltklib.c
    branches/mvm/gc.c
    branches/mvm/include/ruby/intern.h
    branches/mvm/io.c
    branches/mvm/iseq.c
    branches/mvm/iseq.h
    branches/mvm/lib/forwardable.rb
    branches/mvm/lib/gserver.rb
    branches/mvm/lib/net/protocol.rb
    branches/mvm/lib/open3.rb
    branches/mvm/lib/rexml/xpath.rb
    branches/mvm/lib/rubygems/local_remote_options.rb
    branches/mvm/lib/rubygems/validator.rb
    branches/mvm/load.c
    branches/mvm/man/goruby.1
    branches/mvm/man/irb.1
    branches/mvm/numeric.c
    branches/mvm/pack.c
    branches/mvm/parse.y
    branches/mvm/proc.c
    branches/mvm/process.c
    branches/mvm/rational.c
    branches/mvm/regparse.c
    branches/mvm/signal.c
    branches/mvm/spec/default.mspec
    branches/mvm/strftime.c
    branches/mvm/string.c
    branches/mvm/test/bigdecimal/test_bigdecimal.rb
    branches/mvm/test/cgi/test_cgi_session.rb
    branches/mvm/test/openssl/test_ssl.rb
    branches/mvm/test/ruby/test_complex.rb
    branches/mvm/test/ruby/test_fiber.rb
    branches/mvm/test/ruby/test_float.rb
    branches/mvm/test/ruby/test_method.rb
    branches/mvm/test/ruby/test_proc.rb
    branches/mvm/test/ruby/test_process.rb
    branches/mvm/test/ruby/test_range.rb
    branches/mvm/test/ruby/test_rational.rb
    branches/mvm/test/ruby/test_regexp.rb
    branches/mvm/test/ruby/test_string.rb
    branches/mvm/test/socket/test_tcp.rb
    branches/mvm/thread.c
    branches/mvm/variable.c
    branches/mvm/version.h
    branches/mvm/vm.c
    branches/mvm/vm_method.c
    branches/mvm/win32/win32.c

Index: mvm/complex.c
===================================================================
--- mvm/complex.c	(revision 20561)
+++ mvm/complex.c	(revision 20562)
@@ -885,15 +885,17 @@
     switch (TYPE(x)) {
       case T_FLOAT:
 #ifdef HAVE_SIGNBIT
-	return f_boolcast(signbit(RFLOAT_VALUE(x)));
+      {
+	  double f = RFLOAT_VALUE(x);
+	  return f_boolcast(!isnan(f) && signbit(f));
+      }
 #else
-	{
-	    char s[2];
+      {
+	  char s[2];
 
-	    (void)snprintf(s, sizeof s, "%.0f", RFLOAT_VALUE(x));
-
-	    return f_boolcast(s[0] == '-');
-	}
+	  (void)snprintf(s, sizeof s, "%.0f", RFLOAT_VALUE(x));
+	  return f_boolcast(s[0] == '-');
+      }
 #endif
     }
     return f_negative_p(x);
@@ -906,7 +908,7 @@
 }
 
 static VALUE
-nucomp_to_s(VALUE self)
+nucomp_format(VALUE self, VALUE (*func)(VALUE))
 {
     VALUE s, impos;
 
@@ -914,31 +916,32 @@
 
     impos = f_tpositive_p(dat->imag);
 
-    s = f_to_s(dat->real);
+    s = (*func)(dat->real);
     rb_str_cat2(s, !impos ? "-" : "+");
 
-    rb_str_concat(s, f_to_s(f_abs(dat->imag)));
+    rb_str_concat(s, (*func)(f_abs(dat->imag)));
+    if (!rb_isdigit(RSTRING_PTR(s)[RSTRING_LEN(s) - 1]))
+	rb_str_cat2(s, "*");
     rb_str_cat2(s, "i");
 
     return s;
 }
 
 static VALUE
+nucomp_to_s(VALUE self)
+{
+    return nucomp_format(self, f_to_s);
+}
+
+static VALUE
 nucomp_inspect(VALUE self)
 {
-    VALUE s, impos;
+    VALUE s;
 
-    get_dat1(self);
-
-    impos = f_tpositive_p(dat->imag);
-
     s = rb_str_new2("(");
-    rb_str_concat(s, f_inspect(dat->real));
-    rb_str_cat2(s, !impos ? "-" : "+");
+    rb_str_concat(s, nucomp_format(self, f_inspect));
+    rb_str_cat2(s, ")");
 
-    rb_str_concat(s, f_inspect(f_abs(dat->imag)));
-    rb_str_cat2(s, "i)");
-
     return s;
 }
 
Index: mvm/regparse.c
===================================================================
--- mvm/regparse.c	(revision 20561)
+++ mvm/regparse.c	(revision 20562)
@@ -2112,6 +2112,7 @@
   return c;
 }
 
+#if 0				/* no invalid quantifier */
 static int
 is_invalid_quantifier_target(Node* node)
 {
@@ -2143,6 +2144,9 @@
   }
   return 0;
 }
+#else
+#define is_invalid_quantifier_target(node) 0
+#endif
 
 /* ?:0, *:1, +:2, ??:3, *?:4, +?:5 */
 static int
Index: mvm/include/ruby/intern.h
===================================================================
--- mvm/include/ruby/intern.h	(revision 20561)
+++ mvm/include/ruby/intern.h	(revision 20562)
@@ -267,6 +267,7 @@
 void rb_load_protect(VALUE, int, int*);
 NORETURN(void rb_jump_tag(int));
 int rb_provided(const char*);
+int rb_feature_provided(const char *, const char **);
 void rb_provide(const char*);
 VALUE rb_f_require(VALUE, VALUE);
 VALUE rb_require_safe(VALUE, int);
Index: mvm/ChangeLog
===================================================================
--- mvm/ChangeLog	(revision 20561)
+++ mvm/ChangeLog	(revision 20562)
@@ -1,3 +1,294 @@
+Fri Dec  5 21:45:45 2008  Tadayoshi Funaba  <tadf@d...>
+
+	* rational.c (nurat_{to_s,inspect}): performance improvement.
+
+Fri Dec  5 21:42:44 2008  Tadayoshi Funaba  <tadf@d...>
+
+	* complex.c: inpsect should not depend on to_s.
+
+Fri Dec  5 19:06:04 2008  Tanaka Akira  <akr@f...>
+
+	* lib/open3.rb (Open3.pipeline_start): new method.
+	  (Open3.pipeline): ditto.
+
+Fri Dec  5 18:55:25 2008  Tanaka Akira  <akr@f...>
+
+	* process.c (run_exec_dup2): !save is false if Qnil.
+
+Fri Dec  5 18:07:32 2008  NAKAMURA Usaku  <usa@r...>
+
+	* win32/win32.c (rb_w32_read, rb_w32_write, rb_w32_isatty): check
+	  whether fd is valid.
+
+Fri Dec  5 13:05:45 2008  Nobuyoshi Nakada  <nobu@r...>
+
+	* iseq.c (rb_iseq_parameters): proc arguments are always optional.
+
+	* proc.c (get_proc_iseq, rb_proc_parameters): ditto.
+
+Fri Dec  5 12:38:48 2008  Nobuyoshi Nakada  <nobu@r...>
+
+	* compile.c (iseq_set_sequence): uses rb_compile_warning() for
+	  warning at compilation time.
+
+Fri Dec  5 12:35:46 2008  Nobuyoshi Nakada  <nobu@r...>
+
+	* compile.c (ruby_iseq_compile, ruby_iseq_translate_threaded_code),
+	  (ruby_insns_name_array, ruby_iseq_build_from_ary): prefixed with
+	  ruby_.
+
+	* iseq.c (ruby_iseq_load, ruby_insn_make_insn_table): ditto.
+
+Fri Dec  5 10:01:43 2008  Nobuyoshi Nakada  <nobu@r...>
+
+	* string.c (rb_str_cmp_m): fixed rdoc.  pointed out by <Thomas
+	  C. Mitchell AT gmail.com> at [ruby-talk:321967]
+
+Fri Dec  5 07:58:30 2008  Tanaka Akira  <akr@f...>
+
+	* io.c (io_binwrite): arg.offset should be updated after retry.
+
+Fri Dec  5 03:29:17 2008  Nobuyoshi Nakada  <nobu@r...>
+
+	* load.c (rb_get_load_path): returns the load path without
+	  touching.
+
+	* load.c (rb_feature_provided): new function to return the loading
+	  path in addition to rb_provided().
+
+	* load.c (search_required): sets path if loading.
+
+	* variable.c (autoload_provided): load paths are expanded to check
+	  if loading.
+
+	* variable.c (autoload_node): keeps autoload mark while loading.
+	  [ruby-core:20235]
+
+	* variable.c (rb_const_get_0): loops while autoload mark is set.
+
+Fri Dec  5 01:37:02 2008  NAKAMURA Usaku  <usa@r...>
+
+	* win32/win32.c (rb_w32_read): ERROR_BROKEN_PIPE is not a real error
+	  at this point.
+
+	* io.c (pipe_open): use rb_w32_spawn() instead of rb_w32_pipe_exec()
+	  to use our own redirection scheme.
+
+Fri Dec  5 01:35:08 2008  Nobuyoshi Nakada  <nobu@r...>
+
+	* string.c (sym_to_proc): use hidden object.
+
+Fri Dec  5 01:19:21 2008  Yukihiro Matsumoto  <matz@r...>
+
+	* pack.c (pack_pack): propagate taint status from format string to
+	  result string.
+
+Fri Dec  5 00:34:10 2008  NAKAMURA Usaku  <usa@r...>
+
+	* process.c (run_exec_dup2): need to sort by reverted order when
+	  restoring fds.
+
+Fri Dec  5 00:17:18 2008  Nobuyoshi Nakada  <nobu@r...>
+
+	* string.c (sym_to_proc): caches Symbol procs, based on a patch from
+	  Shumpei Akai <admin AT flexfrank.net>.  [ruby-dev:37265]
+
+Thu Dec  4 23:29:34 2008  NAKAMURA Usaku  <usa@r...>
+
+	* win32/win32.c (waitpid): fix bug of checking child slot.
+
+	* win32/win32.c (FindChildSlotByHandle): new.
+
+Thu Dec  4 23:24:05 2008  Tanaka Akira  <akr@f...>
+
+	* lib/open3.rb (Open3.poutput3): new method.
+	  (Open3.poutput2): ditto.
+	  (Open3.poutput2e): ditto.
+
+Thu Dec  4 23:02:13 2008  Yuki Sonoda (Yugui)  <yugui@y...>
+
+	* spec/default.mspec: follows changes in rubyspec project.
+	  inherits configurations from ruby.1.9.mspec.
+
+Thu Dec  4 22:13:55 2008  Tadayoshi Funaba  <tadf@d...>
+
+	* test/ruby/test_complex.rb: added some tests.
+
+	* test/ruby/test_rational.rb: ditto.
+
+Thu Dec  4 19:56:20 2008  Tanaka Akira  <akr@f...>
+
+	* lib/open3.rb (Open3.popen3): simplified.
+	  (Open3.popen_run): extracted from Open3.popen3.
+	  (Open3.popen2): new method.
+	  (Open3.popen2e): new method.
+	  (Open3.pipeline_rw): new method.
+	  (Open3.pipeline_r): new method.
+	  (Open3.pipeline_w): new method.
+	  (Open3.pipeline_run): new private method.
+
+Thu Dec  4 19:16:28 2008  Tanaka Akira  <akr@f...>
+
+	* process.c (check_exec_fds): resolve cascaded child fd reference.
+
+Thu Dec  4 16:58:12 2008  Yukihiro Matsumoto  <matz@r...>
+
+	* lib/rubygems/validator.rb (Gem#remove_leading_dot_dir): make
+	  this method private.  a patch from okkez in [ruby-dev:37245]
+
+Thu Dec  4 16:19:18 2008  Yukihiro Matsumoto  <matz@r...>
+
+	* ext/openssl/ossl_ssl.c (ossl_ssl_read_nonblock):
+	  OpenSSL::SSL::SSLSocket should implement read_nonblock.  a patch
+	  from Aaron Patterson in [ruby-core:20277].  fix: #814 [ruby-core:20241]
+
+Thu Dec  4 16:16:09 2008  Yukihiro Matsumoto  <matz@r...>
+
+	* lib/gserver.rb: fixed type in sample code.  a report from Oleg
+	  Puchinin.
+
+Thu Dec  4 14:54:32 2008  Yukihiro Matsumoto  <matz@r...>
+
+	* lib/rubygems/local_remote_options.rb (Gem#add_update_sources_option):
+	  little documentation fix.  a patch from okkez.  [ruby-dev:37271]
+
+Thu Dec  4 13:56:31 2008  Yukihiro Matsumoto  <matz@r...>
+
+	* ext/curses/curses.c (window_getch): avoid ISPRINT() macro which
+	  has an issue with OpenSolaris.  [ruby-core:20189]
+
+	* ext/curses/curses.c (curses_getch): no ISPRINT(). [ruby-core:20294]
+
+	* signal.c (ruby_signal): EINVAL from sigaction(2) is not a bug.
+
+Thu Dec  4 11:40:56 2008  Akinori MUSHA  <knu@i...>
+
+	* enumerator.c (inspect_enumerator): Implement #inspect.
+	  [ruby-dev:37248]-[ruby-dev:37263]
+
+Thu Dec  4 11:38:40 2008  Akinori MUSHA  <knu@i...>
+
+	* vm_method.c (rb_obj_respond_to): Remove a duplicated rdoc
+	  comment and fix a markup error.
+
+Thu Dec  4 06:04:16 2008  Hidetoshi NAGAI  <nagai@a...>
+
+	* ext/tk/lib/tk/menu.rb: TkOptionMenubutton.new fails to treat
+	  'parent' and 'variable' options on a Hash argument.
+
+Thu Dec  4 05:06:47 2008  Hidetoshi NAGAI  <nagai@a...>
+
+	* ext/tk/lib/tk.rb: bug fix. use ::RubyVM instead of ::VM
+	  [ruby-list:45676]
+
+	* ext/tk/tcltklib.c: update RELEASE_DATE
+
+Thu Dec  4 01:37:47 2008  Tadayoshi Funaba  <tadf@d...>
+
+	* complex.c (nurat_{to_s,inspect}): provides better representation
+	  for in-finite imag part.
+
+Thu Dec  4 01:22:41 2008  Tadayoshi Funaba  <tadf@d...>
+
+	* complex.c (f_signbit): NaN may be signed value.
+
+Wed Dec  3 23:59:32 2008  Tanaka Akira  <akr@f...>
+
+	* process.c (EXEC_OPTION_DUP2_CHILD): defined.
+	  (check_exec_redirect_fd): check :in, :out and :err.
+	  (check_exec_redirect): check [:child, fd].
+	  (check_exec_fds): validate EXEC_OPTION_DUP2_CHILD array.
+	  (run_exec_dup2_child): new function.
+	  (rb_run_exec_options): call run_exec_dup2_child.
+
+Wed Dec  3 22:54:39 2008  Nobuyoshi Nakada  <nobu@r...>
+
+	* parse.y (expr): keyword_not can continue across newline.
+	  [ruby-core:20252]
+
+Wed Dec  3 22:40:59 2008  Nobuyoshi Nakada  <nobu@r...>
+
+	* iseq.c (simple_default_value): returns simplest assignment only.
+	  [ruby-core:20237]
+
+Wed Dec  3 21:30:06 2008  Tanaka Akira  <akr@f...>
+
+	* process.c (check_exec_redirect): accept :in, :out, :err as redirect
+	  target.
+
+Wed Dec  3 21:18:27 2008  Tadayoshi Funaba  <tadf@d...>
+
+	* test/ruby/test_rational.rb: revert.
+
+Wed Dec  3 14:48:52 2008  Nobuyoshi Nakada  <nobu@r...>
+
+	* ext/tk/tcltklib.c (ip_ruby_cmd, ip_invoke_with_position): must
+	  not access internal union directly.  [ruby-list:45670]
+
+Wed Dec  3 12:24:08 2008  Nobuyoshi Nakada  <nobu@r...>
+
+	* io.c (rb_io_getc, rb_io_readchar): documentation correction from
+	  Emiel van de Laar.  [ruby-core:20212]
+
+	* ext/stringio/stringio.c (strio_readchar): ditto.
+
+Wed Dec  3 09:26:29 2008  Yukihiro Matsumoto  <matz@r...>
+
+	* lib/rexml/xpath.rb (REXML::XPath.first): apply documentation
+	  patch from Ken Bloom in [ruby-core:20213].
+
+	* lib/rexml/xpath.rb (REXML::XPath.each): ditto.
+
+Wed Dec  3 02:56:34 2008  Yusuke Endoh  <mame@t...>
+
+	* test/ruby/test_rational.rb: add a test.
+
+Wed Dec  3 02:53:24 2008  Yusuke Endoh  <mame@t...>
+
+	* test/ruby/test_range.rb: add a test.
+
+Wed Dec  3 02:26:07 2008  Yusuke Endoh  <mame@t...>
+
+	* test/ruby/test_string.rb: add some tests.
+
+Wed Dec  3 02:04:21 2008  Yusuke Endoh  <mame@t...>
+
+	* ext/pty/pty.c (Init_pty): fix typo.
+
+Tue Dec  2 19:22:13 2008  Tanaka Akira  <akr@f...>
+
+	* lib/open3.rb (Open3.popen3): merge hash options if given.
+
+Tue Dec  2 15:31:42 2008  Yukihiro Matsumoto  <matz@r...>
+
+	* lib/net/protocol.rb (Net::BufferedIO#rbuf_fill): use
+	  read_nonblock instead of sysread wrapped by timeout to boost
+	  performance.  a patch from Aaron Patterson in [ruby-core:20191].
+	  fix #806
+
+Mon Dec  1 23:23:52 2008  Yuki Sonoda (Yugui)  <yugui@y...>
+
+	* set 1.9.1-p5000 into version number. [ruby-dev:36998]
+
+Mon Dec  1 15:48:47 2008  NAKAMURA Usaku  <usa@r...>
+
+	* signal.c (register_sigaltstack): no need to define on non-sigaltstack
+	  platform.
+
+Mon Dec  1 12:00:45 2008  Nobuyoshi Nakada  <nobu@r...>
+
+	* cont.c (rb_fiber_start): calls with exact argument number.
+	  [ruby-core:20088]
+
+Sun Nov 30 21:41:10 2008  Yuki Sonoda (Yugui)  <yugui@y...>
+
+	* man/rake.1: new manual page
+
+Sun Nov 30 18:01:50 2008  Yuki Sonoda (Yugui)  <yugui@y...>
+
+	* test/ruby/test_regexp.rb (TestRegexp#test_parse_curly_brace):
+	  now accepts quantifier on anchrs agian by r20391.
+
 Sun Nov 30 15:26:44 2008  Nobuyoshi Nakada  <nobu@r...>
 
 	* inits.c (rb_vm_call_inits): let all InitVM functions use
@@ -3,4 +294,67 @@
 	  ruby_vm_t instead of rb_vm_t.
 
+Sat Nov 29 23:56:44 2008  Yuki Sonoda (Yugui)  <yugui@y...>
+
+	* man/irb.1 (EXAMPLES): new section
+
+Sat Nov 29 19:19:32 2008  Yukihiro Matsumoto  <matz@r...>
+
+	* regparse.c (is_invalid_quantifier_target): Perl and old Ruby
+	  accepts quantifier on anchors.  [ruby-core:20161]
+
+Sat Nov 29 18:28:57 2008  Yukihiro Matsumoto  <matz@r...>
+
+	* ext/socket/socket.c (sock_getaddrinfo): should have updated for
+	  Mac OS X.  a patch from Shumpei Akai in [ruby-dev:37234]
+
+Sat Nov 29 00:18:30 2008  Yukihiro Matsumoto  <matz@r...>
+
+	* cont.c (fiber_alloc): separate allocation and initialization.
+	  allow subclass to override #initialize.   [ruby-core:20086]
+
+Fri Nov 28 18:31:21 2008  Yukihiro Matsumoto  <matz@r...>
+
+	* ext/socket/socket.c (sock_s_getaddrinfo): refactored to remove
+	  code duplication regarding getaddrinfo.
+
+Fri Nov 28 17:52:26 2008  Keiju Ishitsuka  <keiju@r...>
+
+	* lib/forwardable.rb: should be usable def_single_delegator for
+	  Class and Module.
+
+Fri Nov 28 13:19:34 2008  Nobuyoshi Nakada  <nobu@r...>
+
+	* iseq.c (simple_default_value): extracts simplest default
+	  argument value.
+
+	* iseq.c (rb_iseq_parameters): returns parameter list.
+
+	* proc.c (get_proc_iseq, get_method_iseq): handles ifunc and
+	  bmethod.
+
+	* proc.c (rb_proc_parameters, rb_method_parameters): added
+	  Proc#parameters and Method#parameters.  [ruby-core:19759]
+
+Fri Nov 28 02:18:47 2008  Yukihiro Matsumoto  <matz@r...>
+
+	* ext/bigdecimal/bigdecimal.c (BigDecimal_DoDivmod): bigdecimal
+	  division (including modulo) should raise ZeroDivisionError as
+	  integer division. [incompatible]
+
+Fri Nov 28 00:12:00 2008  Yukihiro Matsumoto  <matz@r...>
+
+	* numeric.c (flodivmod): floating point division should raise
+	  ZeroDivisionError as integer division. [incompatible]
+
+Thu Nov 27 23:54:37 2008  Yukihiro Matsumoto  <matz@r...>
+
+	* gc.c (gc_mark): still needs to check stack depth during GC.
+
+	* gc.c (stack_check): ditto.
+
+Thu Nov 27 21:41:29 2008  Tadayoshi Funaba  <tadf@d...>
+
+	* strftime.c (rb_strftime): should add padding for %%.
+
 Thu Nov 27 17:06:46 2008  Nobuyoshi Nakada  <nobu@r...>
 
Index: mvm/enumerator.c
===================================================================
--- mvm/enumerator.c	(revision 20561)
+++ mvm/enumerator.c	(revision 20562)
@@ -542,7 +542,69 @@
     return obj;
 }
 
+static VALUE
+inspect_enumerator(VALUE obj, VALUE dummy, int recur)
+{
+    struct enumerator *e = enumerator_ptr(obj);
+    const char *cname = rb_obj_classname(obj);
+    VALUE eobj, str;
+    int tainted, untrusted;
+
+    if (recur) {
+	str = rb_sprintf("#<%s: ...>", cname);
+	OBJ_TAINT(str);
+	return str;
+    }
+
+    eobj = e->obj;
+
+    tainted   = OBJ_TAINTED(eobj);
+    untrusted = OBJ_UNTRUSTED(eobj);
+
+    /* (1..100).each_cons(2) => "#<Enumerator: 1..100:each_cons(2)>" */
+    str = rb_sprintf("#<%s: ", cname);
+    rb_str_concat(str, rb_inspect(eobj));
+    rb_str_buf_cat2(str, ":");
+    rb_str_buf_cat2(str, rb_id2name(e->meth));
+
+    if (e->args) {
+	int    argc = RARRAY_LEN(e->args);
+	VALUE *argv = RARRAY_PTR(e->args);
+
+	rb_str_buf_cat2(str, "(");
+
+	while (argc--) {
+	    VALUE arg = *argv++;
+
+	    rb_str_concat(str, rb_inspect(arg));
+	    rb_str_buf_cat2(str, argc > 0 ? ", " : ")");
+
+	    if (OBJ_TAINTED(arg)) tainted = Qtrue;
+	    if (OBJ_UNTRUSTED(arg)) untrusted = Qtrue;
+	}
+    }
+
+    rb_str_buf_cat2(str, ">");
+
+    if (tainted) OBJ_TAINT(str);
+    if (untrusted) OBJ_UNTRUST(str);
+    return str;
+}
+
 /*
+ * call-seq:
+ *   e.inspect  => string
+ *
+ *  Create a printable version of <i>e</i>.
+ */
+
+static VALUE
+enumerator_inspect(VALUE obj)
+{
+    return rb_exec_recursive(inspect_enumerator, obj, 0);
+}
+
+/*
  * Yielder
  */
 static void
@@ -782,6 +844,7 @@
     rb_define_method(rb_cEnumerator, "with_object", enumerator_with_object, 1);
     rb_define_method(rb_cEnumerator, "next", enumerator_next, 0);
     rb_define_method(rb_cEnumerator, "rewind", enumerator_rewind, 0);
+    rb_define_method(rb_cEnumerator, "inspect", enumerator_inspect, 0);
 
     rb_eStopIteration = rb_define_class("StopIteration", rb_eIndexError);
 
Index: mvm/variable.c
===================================================================
--- mvm/variable.c	(revision 20561)
+++ mvm/variable.c	(revision 20562)
@@ -1488,57 +1488,76 @@
     return (NODE *)load;
 }
 
-VALUE
-rb_autoload_load(VALUE klass, ID id)
+static VALUE
+autoload_provided(VALUE arg)
 {
-    VALUE file;
-    NODE *load = autoload_delete(klass, id);
-
-    if (!load || !(file = load->nd_lit)) {
-	return Qfalse;
-    }
-    return rb_require_safe(file, load->nd_nth);
+    const char **p = (const char **)arg;
+    return rb_feature_provided(*p, p);
 }
 
 static VALUE
-autoload_file(VALUE mod, ID id)
+reset_safe(VALUE safe)
 {
+    rb_set_safe_level_force((int)safe);
+    return safe;
+}
+
+static NODE *
+autoload_node(VALUE mod, ID id, int noload)
+{
     VALUE file;
     struct st_table *tbl;
-    st_data_t val, load, n = id;
+    st_data_t val;
+    NODE *load;
+    const char *loading;
+    int safe;
 
     if (!st_lookup(RCLASS_IV_TBL(mod), autoload, &val) ||
-	!(tbl = check_autoload_table((VALUE)val)) || !st_lookup(tbl, n, &load)) {
-	return Qnil;
+	!(tbl = check_autoload_table((VALUE)val)) || !st_lookup(tbl, (st_data_t)id, &val)) {
+	return 0;
     }
-    file = ((NODE *)load)->nd_lit;
+    load = (NODE *)val;
+    file = load->nd_lit;
     Check_Type(file, T_STRING);
     if (!RSTRING_PTR(file) || !*RSTRING_PTR(file)) {
 	rb_raise(rb_eArgError, "empty file name");
     }
-    if (!rb_provided(RSTRING_PTR(file))) {
-	return file;
+    loading = RSTRING_PTR(file);
+    safe = rb_safe_level();
+    rb_set_safe_level_force(0);
+    if (!rb_ensure(autoload_provided, (VALUE)&loading, reset_safe, (VALUE)safe)) {
+	return load;
     }
-
-    /* already loaded but not defined */
-    st_delete(tbl, &n, 0);
-    if (!tbl->num_entries) {
-	n = autoload;
-	st_delete(RCLASS_IV_TBL(mod), &n, &val);
+    if (!noload && loading) {
+	return load;
     }
-    return Qnil;
+    return 0;
 }
 
 VALUE
+rb_autoload_load(VALUE klass, ID id)
+{
+    VALUE file;
+    NODE *load = autoload_node(klass, id, 0);
+
+    if (!load) return Qfalse;
+    file = load->nd_lit;
+    return rb_require_safe(file, load->nd_nth);
+}
+
+VALUE
 rb_autoload_p(VALUE mod, ID id)
 {
     struct st_table *tbl = RCLASS_IV_TBL(mod);
-    VALUE val;
+    st_data_t val;
+    NODE *load;
+    VALUE file;
 
     if (!tbl || !st_lookup(tbl, id, &val) || val != Qundef) {
 	return Qnil;
     }
-    return autoload_file(mod, id);
+    load = autoload_node(mod, id, 0);
+    return load && (file = load->nd_lit) ? file : Qnil;
 }
 
 static VALUE
@@ -1552,7 +1571,7 @@
     while (RTEST(tmp)) {
 	while (RCLASS_IV_TBL(tmp) && st_lookup(RCLASS_IV_TBL(tmp),id,&value)) {
 	    if (value == Qundef) {
-		if (!RTEST(rb_autoload_load(tmp, id))) break;
+		rb_autoload_load(tmp, id);
 		continue;
 	    }
 	    if (exclude && tmp == rb_cObject && klass != rb_cObject) {
@@ -1737,7 +1756,7 @@
   retry:
     while (tmp) {
 	if (RCLASS_IV_TBL(tmp) && st_lookup(RCLASS_IV_TBL(tmp), id, &value)) {
-	    if (value == Qundef && NIL_P(autoload_file(klass, id)))
+	    if (value == Qundef && !autoload_node(klass, id, 1))
 		return Qfalse;
 	    return Qtrue;
 	}
@@ -1776,7 +1795,7 @@
     const char *dest = isconst ? "constant" : "class variable";
 
     if (!OBJ_UNTRUSTED(klass) && rb_safe_level() >= 4)
-      rb_raise(rb_eSecurityError, "Insecure: can't set %s", dest);
+	rb_raise(rb_eSecurityError, "Insecure: can't set %s", dest);
     if (OBJ_FROZEN(klass)) {
 	if (BUILTIN_TYPE(klass) == T_MODULE) {
 	    rb_error_frozen("module");
@@ -1799,7 +1818,7 @@
 	}
     }
 
-    if(isconst){
+    if (isconst){
 	rb_vm_change_state();
     }
     st_insert(RCLASS_IV_TBL(klass), id, val);
Index: mvm/bootstraptest/test_autoload.rb
===================================================================
--- mvm/bootstraptest/test_autoload.rb	(revision 20561)
+++ mvm/bootstraptest/test_autoload.rb	(revision 20562)
@@ -50,3 +50,12 @@
   module M; end
   Thread.new{eval('$SAFE=4; ZZZ.new.hoge')}.value
 }
+
+assert_equal 'okok', %q{
+  open("zzz.rb", "w") {|f| f.puts "class ZZZ; def self.ok;:ok;end;end"}
+  autoload :ZZZ, "./zzz.rb"
+  t1 = Thread.new {ZZZ.ok}
+  t2 = Thread.new {ZZZ.ok}
+  [t1.value, t2.value].join
+}
+
Index: mvm/iseq.c
===================================================================
--- mvm/iseq.c	(revision 20561)
+++ mvm/iseq.c	(revision 20562)
@@ -19,10 +19,6 @@
 #include "insns.inc"
 #include "insns_info.inc"
 
-/* compile.c */
-void iseq_compile(VALUE self, NODE *node);
-int iseq_translate_threaded_code(rb_iseq_t *iseq);
-
 static void
 compile_data_free(struct iseq_compile_data *compile_data)
 {
@@ -324,7 +320,7 @@
     iseq->self = self;
 
     prepare_iseq_build(iseq, name, filename, parent, type, bopt, option);
-    iseq_compile(self, node);
+    ruby_iseq_compile(self, node);
     cleanup_iseq_build(iseq);
     return self;
 }
@@ -346,17 +342,14 @@
 					   bopt, &COMPILE_OPTION_DEFAULT);
 }
 
-VALUE iseq_build_from_ary(rb_iseq_t *iseq, VALUE locals, VALUE args,
-			  VALUE exception, VALUE body);
-
 #define CHECK_ARRAY(v)   rb_convert_type(v, T_ARRAY, "Array", "to_ary")
 #define CHECK_STRING(v)  rb_convert_type(v, T_STRING, "String", "to_str")
 #define CHECK_SYMBOL(v)  rb_convert_type(v, T_SYMBOL, "Symbol", "to_sym")
 static inline VALUE CHECK_INTEGER(VALUE v) {NUM2LONG(v); return v;}
-VALUE
+static VALUE
 iseq_load(VALUE self, VALUE data, VALUE parent, VALUE opt)
 {
-    VALUE iseqval = iseq_alloc(rb_cISeq);
+    VALUE iseqval = iseq_alloc(self);
 
     VALUE magic, version1, version2, format_type, misc;
     VALUE name, filename;
@@ -426,7 +419,7 @@
     prepare_iseq_build(iseq, name, filename,
 		       parent, iseq_type, 0, &option);
 
-    iseq_build_from_ary(iseq, locals, args, exception, body);
+    ruby_iseq_build_from_ary(iseq, locals, args, exception, body);
 
     cleanup_iseq_build(iseq);
     return iseqval;
@@ -441,6 +434,12 @@
     return iseq_load(self, data, 0, opt);
 }
 
+VALUE
+ruby_iseq_load(VALUE data, VALUE parent, VALUE opt)
+{
+    return iseq_load(rb_cISeq, data, parent, opt);
+}
+
 static NODE *
 compile_string(VALUE str, VALUE file, VALUE line)
 {
@@ -1235,7 +1234,7 @@
 }
 
 struct st_table *
-insn_make_insn_table(void)
+ruby_insn_make_insn_table(void)
 {
     struct st_table *table;
     int i;
@@ -1272,6 +1271,103 @@
     return newiseq;
 }
 
+static VALUE
+simple_default_value(const VALUE *seq, const VALUE *eseq)
+{
+    VALUE val;
+
+  again:
+    switch (*seq++) {
+      case BIN(trace):
+	if (++seq >= eseq) return Qundef;
+	goto again;
+      case BIN(putnil):
+	val = Qnil;
+	goto got;
+      case BIN(putobject):
+	val = *seq++;
+      got:
+	switch (*seq++) {
+	  case BIN(setlocal):
+	    if ((seq+=1) == eseq) return val;
+	    break;
+	  case BIN(setdynamic):
+	    if ((seq+=2) == eseq) return val;
+	    break;
+	}
+      default:
+	return Qundef;
+    }
+}
+
+VALUE
+rb_iseq_parameters(const rb_iseq_t *iseq, int is_proc)
+{
+    int i, r, s;
+    VALUE a, args = rb_ary_new2(iseq->arg_size);
+    ID req, opt, rest, block;
+#define PARAM_TYPE(type) rb_ary_push(a = rb_ary_new2(2), ID2SYM(type))
+#define PARAM_ID(i) iseq->local_table[i]
+#define PARAM(i, type) (		      \
+	PARAM_TYPE(type),		      \
+	rb_id2name(PARAM_ID(i)) ?	      \
+	rb_ary_push(a, ID2SYM(PARAM_ID(i))) : \
+	a)
+
+    CONST_ID(req, "req");
+    CONST_ID(opt, "opt");
+    if (is_proc) {
+	for (i = 0; i < iseq->argc; i++) {
+	    PARAM_TYPE(opt);
+	    rb_ary_push(a, rb_id2name(PARAM_ID(i)) ? ID2SYM(PARAM_ID(i)) : Qnil);
+	    rb_ary_push(a, Qnil);
+	    rb_ary_push(args, a);
+	}
+    }
+    else {
+	for (i = 0; i < iseq->argc; i++) {
+	    rb_ary_push(args, PARAM(i, req));
+	}
+    }
+    r = iseq->arg_rest != -1 ? iseq->arg_rest :
+	iseq->arg_post_len > 0 ? iseq->arg_post_start :
+	iseq->arg_block != -1 ? iseq->arg_block :
+	iseq->arg_size;
+    for (s = i; i < r; i++) {
+	PARAM_TYPE(opt);
+	if (rb_id2name(PARAM_ID(i))) {
+	    VALUE defval = simple_default_value(iseq->iseq + iseq->arg_opt_table[i-s],
+						iseq->iseq + iseq->arg_opt_table[i-s+1]);
+	    rb_ary_push(a, ID2SYM(PARAM_ID(i)));
+	    if (defval != Qundef) rb_ary_push(a, defval);
+	}
+	rb_ary_push(args, a);
+    }
+    if (iseq->arg_rest != -1) {
+	CONST_ID(rest, "rest");
+	rb_ary_push(args, PARAM(iseq->arg_rest, rest));
+    }
+    r = iseq->arg_post_start + iseq->arg_post_len;
+    if (is_proc) {
+	for (i = iseq->arg_post_start; i < r; i++) {
+	    PARAM_TYPE(opt);
+	    rb_ary_push(a, rb_id2name(PARAM_ID(i)) ? ID2SYM(PARAM_ID(i)) : Qnil);
+	    rb_ary_push(a, Qnil);
+	    rb_ary_push(args, a);
+	}
+    }
+    else {
+	for (i = iseq->arg_post_start; i < r; i++) {
+	    rb_ary_push(args, PARAM(i, req));
+	}
+    }
+    if (iseq->arg_block != -1) {
+	CONST_ID(block, "block");
+	rb_ary_push(args, PARAM(iseq->arg_block, block));
+    }
+    return args;
+}
+
 /* ruby2cext */
 
 VALUE
@@ -1304,7 +1400,7 @@
 	iseq->iseq[i+1] = (VALUE)func;
     }
 
-    iseq_translate_threaded_code(iseq);
+    ruby_iseq_translate_threaded_code(iseq);
 
 #define ALLOC_AND_COPY(dst, src, type, size) do { \
   if (size) { \
Index: mvm/string.c
===================================================================
--- mvm/string.c	(revision 20561)
+++ mvm/string.c	(revision 20562)
@@ -2173,8 +2173,8 @@
  *  call-seq:
  *     str <=> other_str   => -1, 0, +1
  *  
- *  Comparison---Returns -1 if <i>other_str</i> is less than, 0 if
- *  <i>other_str</i> is equal to, and +1 if <i>other_str</i> is greater than
+ *  Comparison---Returns -1 if <i>other_str</i> is greater than, 0 if
+ *  <i>other_str</i> is equal to, and +1 if <i>other_str</i> is less than
  *  <i>str</i>. If the strings are of different lengths, and the strings are
  *  equal when compared up to the shortest length, then the longer string is
  *  considered greater than the shorter one. In older versions of Ruby, setting
@@ -6939,10 +6939,36 @@
 static VALUE
 sym_to_proc(VALUE sym)
 {
-    return rb_proc_new(sym_call, (VALUE)SYM2ID(sym));
+    static int sym_proc_cache_index = -1;
+    enum {SYM_PROC_CACHE_SIZE = 67};
+    VALUE *cache_ptr, sym_proc_cache, proc;
+    long id, index;
+    VALUE *aryp;
+
+    if (sym_proc_cache_index < 0) {
+	sym_proc_cache_index = rb_vm_key_create(); /* needs mutex/once */
+    }
+    sym_proc_cache = *(cache_ptr = rb_vm_specific_ptr(sym_proc_cache_index));
+    if (NIL_P(sym_proc_cache)) {
+	sym_proc_cache = *cache_ptr = rb_ary_tmp_new(SYM_PROC_CACHE_SIZE * 2);
+	rb_ary_store(sym_proc_cache, SYM_PROC_CACHE_SIZE*2 - 1, Qnil);
+    }
+
+    id = SYM2ID(sym);
+    index = (id % SYM_PROC_CACHE_SIZE) << 1;
+
+    aryp = RARRAY_PTR(sym_proc_cache);
+    if (aryp[index] == sym) {
+	return aryp[index + 1];
+    }
+    else {
+	proc = rb_proc_new(sym_call, (VALUE)id);
+	aryp[index] = sym;
+	aryp[index + 1] = proc;
+	return proc;
+    }
 }
 
-
 static VALUE
 sym_succ(VALUE sym)
 {
Index: mvm/iseq.h
===================================================================
--- mvm/iseq.h	(revision 20561)
+++ mvm/iseq.h	(revision 20562)
@@ -12,8 +12,17 @@
 #ifndef RUBY_COMPILE_H
 #define RUBY_COMPILE_H
 
-VALUE iseq_load(VALUE self, VALUE data, VALUE parent, VALUE opt);
+/* compile.c */
+VALUE ruby_iseq_compile(VALUE self, NODE *node);
+int ruby_iseq_translate_threaded_code(rb_iseq_t *iseq);
+VALUE ruby_insns_name_array(void);
+VALUE ruby_iseq_build_from_ary(rb_iseq_t *iseq, VALUE locals, VALUE args,
+			       VALUE exception, VALUE body);
 
+/* iseq.c */
+VALUE ruby_iseq_load(VALUE data, VALUE parent, VALUE opt);
+struct st_table *ruby_insn_make_insn_table(void);
+
 #define ISEQ_TYPE_TOP    INT2FIX(1)
 #define ISEQ_TYPE_METHOD INT2FIX(2)
 #define ISEQ_TYPE_BLOCK  INT2FIX(3)
Index: mvm/io.c
===================================================================
--- mvm/io.c	(revision 20561)
+++ mvm/io.c	(revision 20562)
@@ -797,8 +797,8 @@
 	}
 	arg.fptr = fptr;
 	arg.str = str;
+      retry:
 	arg.offset = offset;
-      retry:
 	arg.length = n;
 	if (fptr->write_lock) {
 	    r = rb_mutex_synchronize(fptr->write_lock, io_binwrite_string, (VALUE)&arg);
@@ -1316,7 +1316,7 @@
  *     ios.pid    => fixnum
  *
  *  Returns the process ID of a child process associated with
- *  <em>ios</em>. This will be set by <code>IO::popen</code>.
+ *  <em>ios</em>. This will be set by <code>IO.popen</code>.
  *
  *     pipe = IO.popen("-")
  *     if pipe
@@ -2693,14 +2693,14 @@
 
 /*
  *  call-seq:
- *     ios.getc   => fixnum or nil
+ *     ios.getc   => string or nil
  *
  *  Reads a one-character string from <em>ios</em>. Returns
  *  <code>nil</code> if called at end of file.
  *
  *     f = File.new("testfile")
- *     f.getc   #=> "8"
- *     f.getc   #=> "1"
+ *     f.getc   #=> "h"
+ *     f.getc   #=> "e"
  */
 
 static VALUE
@@ -2725,8 +2725,8 @@
  *  <code>EOFError</code> on end of file.
  *
  *     f = File.new("testfile")
- *     f.readchar   #=> "8"
- *     f.readchar   #=> "1"
+ *     f.readchar   #=> "h"
+ *     f.readchar   #=> "e"
  */
 
 static VALUE
@@ -4535,6 +4535,7 @@
     const char *exename = NULL;
     volatile VALUE cmdbuf;
     struct rb_exec_arg sarg;
+    int pair[2], write_pair[2];
 #endif
     FILE *fp = 0;
     int fd = -1;
@@ -4659,11 +4660,42 @@
 	cmd = rb_w32_join_argv(RSTRING_PTR(cmdbuf), args);
 	rb_str_resize(argbuf, 0);
     }
+    switch (fmode & (FMODE_READABLE|FMODE_WRITABLE)) {
+      case FMODE_READABLE|FMODE_WRITABLE:
+        if (rb_pipe(write_pair) < 0)
+            rb_sys_fail(cmd);
+        if (rb_pipe(pair) < 0) {
+            int e = errno;
+            close(write_pair[0]);
+            close(write_pair[1]);
+            errno = e;
+            rb_sys_fail(cmd);
+        }
+        if (eargp) {
+            rb_exec_arg_addopt(eargp, INT2FIX(0), INT2FIX(write_pair[0]));
+            rb_exec_arg_addopt(eargp, INT2FIX(1), INT2FIX(pair[1]));
+        }
+	break;
+      case FMODE_READABLE:
+        if (rb_pipe(pair) < 0)
+            rb_sys_fail(cmd);
+        if (eargp)
+            rb_exec_arg_addopt(eargp, INT2FIX(1), INT2FIX(pair[1]));
+	break;
+      case FMODE_WRITABLE:
+        if (rb_pipe(pair) < 0)
+            rb_sys_fail(cmd);
+        if (eargp)
+            rb_exec_arg_addopt(eargp, INT2FIX(0), INT2FIX(pair[0]));
+	break;
+      default:
+        rb_sys_fail(cmd);
+    }
     if (eargp) {
 	rb_exec_arg_fixup(eargp);
 	rb_run_exec_options(eargp, &sarg);
     }
-    while ((pid = rb_w32_pipe_exec(cmd, exename, openmode, &fd, &write_fd)) == -1) {
+    while ((pid = rb_w32_spawn(P_NOWAIT, cmd, exename)) == -1) {
 	/* exec failed */
 	switch (errno) {
 	  case EAGAIN:
@@ -4681,6 +4713,20 @@
     }
     if (eargp)
 	rb_run_exec_options(&sarg, NULL);
+    if ((fmode & FMODE_READABLE) && (fmode & FMODE_WRITABLE)) {
+        close(pair[1]);
+        fd = pair[0];
+        close(write_pair[0]);
+        write_fd = write_pair[1];
+    }
+    else if (fmode & FMODE_READABLE) {
+        close(pair[1]);
+        fd = pair[0];
+    }
+    else {
+        close(pair[0]);
+        fd = pair[1];
+    }
 #else
     if (argc) {
 	prog = rb_ary_join(rb_ary_new4(argc, argv), rb_str_new2(" "));
@@ -4774,23 +4820,46 @@
  *
  *  Runs the specified command as a subprocess; the subprocess's
  *  standard input and output will be connected to the returned
- *  <code>IO</code> object.  If _cmd_ is a +String+
- *  ``<code>-</code>'', then a new instance of Ruby is started as the
- *  subprocess.  If <i>cmd</i> is an +Array+ of +String+, then it will
- *  be used as the subprocess's +argv+ bypassing a shell.
+ *  <code>IO</code> object.
+ *
+ *  _cmd_ is a string or an array as follows.
+ *
+ *    cmd:
+ *      "-"                                      : fork
+ *      commandline                              : command line string which is passed to a shell
+ *      [env, cmdname, arg1, ..., opts]          : command name and arguments (no shell)
+ *      [env, [cmdname, argv0], arg1, ..., opts] : command name and arguments including argv[0] (no shell)
+ *    (env and opts are optional.)
+ *
+ *  If _cmd_ is a +String+ ``<code>-</code>'',
+ *  then a new instance of Ruby is started as the subprocess.
+ *
+ *  If <i>cmd</i> is an +Array+ of +String+,
+ *  then it will be used as the subprocess's +argv+ bypassing a shell.
  *  The array can contains a hash at first for environments and
- *  a hash at last for options similar to <code>spawn</code>.  The default
- *  mode for the new file object is ``r'', but <i>mode</i> may be set
- *  to any of the modes listed in the description for class IO.
+ *  a hash at last for options similar to <code>spawn</code>.
  *
- *  Raises exceptions which <code>IO::pipe</code> and
- *  <code>Kernel::system</code> raise.
+ *  The default mode for the new file object is ``r'',
+ *  but <i>mode</i> may be set to any of the modes listed in the description for class IO.
+ *  The last argument <i>opt</i> qualifies <i>mode</i>.
  *
+ *    # set IO encoding
+ *    nkf_io = IO.popen("nkf -e filename", :external_encoding=>"EUC-JP")
+ *    euc_jp_string = nkf_io.read
+ *
+ *    # merge standard output and standard error using
+ *    # spawn option.  See the document of Kernel.spawn.
+ *    ls_io = IO.popen(["ls", "/", STDERR=>[:child, STDOUT]])
+ *    ls_result_with_error = ls_io.read
+ *
+ *  Raises exceptions which <code>IO.pipe</code> and
+ *  <code>Kernel.spawn</code> raise.
+ *
  *  If a block is given, Ruby will run the command as a child connected
  *  to Ruby with a pipe. Ruby's end of the pipe will be passed as a
  *  parameter to the block.
  *  At the end of block, Ruby close the pipe and sets <code>$?</code>.
- *  In this case <code>IO::popen</code> returns
+ *  In this case <code>IO.popen</code> returns
  *  the value of the block.
  *
  *  If a block is given with a _cmd_ of ``<code>-</code>'',
@@ -4938,10 +5007,10 @@
  *     IO.open(fd, mode_string="r" [, opt] ) {|io| block } => obj
  *
  *  With no associated block, <code>open</code> is a synonym for
- *  <code>IO::new</code>. If the optional code block is given, it will
+ *  <code>IO.new</code>. If the optional code block is given, it will
  *  be passed <i>io</i> as an argument, and the IO object will
  *  automatically be closed when the block terminates. In this instance,
- *  <code>IO::open</code> returns the value of the block.
+ *  <code>IO.open</code> returns the value of the block.
  *
  */
 
@@ -5825,7 +5894,7 @@
  *  Returns a new <code>IO</code> object (a stream) for the given
  *  <code>IO</code> object or integer file descriptor and mode
  *  string. See also <code>IO#fileno</code> and
- *  <code>IO::for_fd</code>.
+ *  <code>IO.for_fd</code>.
  *
  *     puts IO.new($stdout).fileno # => 1
  *
@@ -5920,7 +5989,7 @@
  *
  *  Returns a new <code>IO</code> object (a stream) for the given
  *  integer file descriptor and mode string. See also
- *  <code>IO#fileno</code> and <code>IO::for_fd</code>.
+ *  <code>IO#fileno</code> and <code>IO.for_fd</code>.
  *
  *     a = IO.new(2,"w")      # '2' is standard error
  *     $stderr.puts "Hello"
@@ -5949,7 +6018,7 @@
  *  call-seq:
  *     IO.for_fd(fd, mode [, opt])    => io
  *
- *  Synonym for <code>IO::new</code>.
+ *  Synonym for <code>IO.new</code>.
  *
  */
 
Index: mvm/pack.c
===================================================================
--- mvm/pack.c	(revision 20561)
+++ mvm/pack.c	(revision 20562)
@@ -1018,6 +1018,7 @@
     if (associates) {
 	rb_str_associate(res, associates);
     }
+    OBJ_INFECT(res, fmt);
     return res;
 }
 
Index: mvm/load.c
===================================================================
--- mvm/load.c	(revision 20561)
+++ mvm/load.c	(revision 20562)
@@ -30,13 +30,7 @@
 rb_get_load_path(void)
 {
     VALUE load_path = GET_VM()->load_path;
-    VALUE ary = rb_ary_new2(RARRAY_LEN(load_path));
-    long i;
-
-    for (i = 0; i < RARRAY_LEN(load_path); ++i) {
-	rb_ary_push(ary, rb_file_expand_path(RARRAY_PTR(load_path)[i], Qnil));
-    }
-    return ary;
+    return load_path;
 }
 
 static VALUE
@@ -198,6 +192,12 @@
 int
 rb_provided(const char *feature)
 {
+    return rb_feature_provided(feature, 0);
+}
+
+int
+rb_feature_provided(const char *feature, const char **loading)
+{
     const char *ext = strrchr(feature, '.');
     volatile VALUE fullpath = 0;
 
@@ -208,15 +208,15 @@
     }
     if (ext && !strchr(ext, '/')) {
 	if (IS_RBEXT(ext)) {
-	    if (rb_feature_p(feature, ext, Qtrue, Qfalse, 0)) return Qtrue;
+	    if (rb_feature_p(feature, ext, Qtrue, Qfalse, loading)) return Qtrue;
 	    return Qfalse;
 	}
 	else if (IS_SOEXT(ext) || IS_DLEXT(ext)) {
-	    if (rb_feature_p(feature, ext, Qfalse, Qfalse, 0)) return Qtrue;
+	    if (rb_feature_p(feature, ext, Qfalse, Qfalse, loading)) return Qtrue;
 	    return Qfalse;
 	}
     }
-    if (rb_feature_p(feature, feature + strlen(feature), Qtrue, Qfalse, 0))
+    if (rb_feature_p(feature, feature + strlen(feature), Qtrue, Qfalse, loading))
 	return Qtrue;
     return Qfalse;
 }
@@ -430,9 +430,8 @@
 		return 'r';
 	    }
 	    if ((tmp = rb_find_file(fname)) != 0) {
-		tmp = rb_file_expand_path(tmp, Qnil);
 		ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
-		if (!rb_feature_p(ftptr, ext, Qtrue, Qtrue, 0))
+		if (!rb_feature_p(ftptr, ext, Qtrue, Qtrue, &loading) || loading)
 		    *path = tmp;
 		return 'r';
 	    }
@@ -447,9 +446,8 @@
 #ifdef DLEXT2
 	    OBJ_FREEZE(tmp);
 	    if (rb_find_file_ext(&tmp, loadable_ext + 1)) {
-		tmp = rb_file_expand_path(tmp, Qnil);
 		ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
-		if (!rb_feature_p(ftptr, ext, Qfalse, Qtrue, 0))
+		if (!rb_feature_p(ftptr, ext, Qfalse, Qtrue, &loading) || loading)
 		    *path = tmp;
 		return 's';
 	    }
@@ -457,9 +455,8 @@
 	    rb_str_cat2(tmp, DLEXT);
 	    OBJ_FREEZE(tmp);
 	    if ((tmp = rb_find_file(tmp)) != 0) {
-		tmp = rb_file_expand_path(tmp, Qnil);
 		ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
-		if (!rb_feature_p(ftptr, ext, Qfalse, Qtrue, 0))
+		if (!rb_feature_p(ftptr, ext, Qfalse, Qtrue, &loading) || loading)
 		    *path = tmp;
 		return 's';
 	    }
@@ -471,9 +468,8 @@
 		return 's';
 	    }
 	    if ((tmp = rb_find_file(fname)) != 0) {
-		tmp = rb_file_expand_path(tmp, Qnil);
 		ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
-		if (!rb_feature_p(ftptr, ext, Qfalse, Qtrue, 0))
+		if (!rb_feature_p(ftptr, ext, Qfalse, Qtrue, &loading) || loading)
 		    *path = tmp;
 		return 's';
 	    }
Index: mvm/lib/gserver.rb
===================================================================
--- mvm/lib/gserver.rb	(revision 20561)
+++ mvm/lib/gserver.rb	(revision 20562)
@@ -40,7 +40,7 @@
 #       super(port, *args)
 #     end
 #     def serve(io)
-#       io.puts(Time.now.to_i)
+#       io.puts(Time.now.to_s)
 #     end
 #   end
 #
Index: mvm/lib/open3.rb
===================================================================
--- mvm/lib/open3.rb	(revision 20561)
+++ mvm/lib/open3.rb	(revision 20562)
@@ -12,76 +12,536 @@
 # Open3 grants you access to stdin, stdout, stderr and a thread to wait the
 # child process when running another program.
 #
-# Example:
+# - Open3.popen3 : pipes for stdin, stdout, stderr
+# - Open3.popen2 : pipes for stdin, stdout
+# - Open3.popen2e : pipes for stdin, merged stdout and stderr
+# - Open3.poutput3 : give a string for stdin.  get strings for stdout, stderr
+# - Open3.poutput2 : give a string for stdin.  get a string for stdout
+# - Open3.poutput2e : give a string for stdin.  get a string for merged stdout and stderr
+# - Open3.pipeline_rw : pipes for first stdin and last stdout of a pipeline
+# - Open3.pipeline_r : pipe for last stdout of a pipeline
+# - Open3.pipeline_w : pipe for first stdin of a pipeline
+# - Open3.pipeline_start : a pipeline
+# - Open3.pipeline : run a pipline and wait
 #
-#   require "open3"
-#   include Open3
-#   
-#   stdin, stdout, stderr, wait_thr = popen3('nroff -man')
-#
-# Open3.popen3 can also take a block which will receive stdin, stdout,
-# stderr and wait_thr as parameters.
-# This ensures stdin, stdout and stderr are closed and
-# the process is terminated once the block exits.
-#
-# Example:
-#
-#   require "open3"
-#
-#   Open3.popen3('nroff -man') { |stdin, stdout, stderr, wait_thr| ... }
-#
 
 module Open3
-  # 
+
   # Open stdin, stdout, and stderr streams and start external executable.
   # In addition, a thread for waiting the started process is noticed.
-  # The thread has a thread variable :pid which is the pid of the started
-  # process.
+  # The thread has a pid method and thread variable :pid which is the pid of
+  # the started process.
   #
+  # Block form:
+  #
+  #   Open3.popen3(cmd... [, opts]) {|stdin, stdout, stderr, wait_thr|
+  #     pid = wait_thr.pid # pid of the started process.
+  #     ...
+  #     exit_status = wait_thr.value # Process::Status object returned.
+  #   }
+  #
   # Non-block form:
   #   
-  #   stdin, stdout, stderr, wait_thr = Open3.popen3(cmd)
+  #   stdin, stdout, stderr, wait_thr = Open3.popen3(cmd... [, opts])
   #   pid = wait_thr[:pid]  # pid of the started process.
   #   ...
-  #   stdin.close  # stdin, stdout and stderr should be closed in this form.
+  #   stdin.close  # stdin, stdout and stderr should be closed explicitly in this form.
   #   stdout.close
   #   stderr.close
   #   exit_status = wait_thr.value  # Process::Status object returned.
   #
-  # Block form:
+  # The parameters +cmd...+ is passed to Kernel#spawn.
+  # So a commandline string and list of argument strings can be accepted as follows.
   #
-  #   Open3.popen3(cmd) { |stdin, stdout, stderr, wait_thr| ... }
+  #   Open3.popen3("echo a") {|i, o, e, t| ... }
+  #   Open3.popen3("echo", "a") {|i, o, e, t| ... }
+  #   Open3.popen3(["echo", "argv0"], "a") {|i, o, e, t| ... }
   #
-  # The parameter +cmd+ is passed directly to Kernel#spawn.
+  # If the last parameter, opts, is a Hash, it is recognized as an option for Kernel#spawn.
   #
+  #   Open3.popen3("pwd", :chdir=>"/") {|i,o,e,t|
+  #     p o.read.chomp #=> "/"
+  #   }
+  #
   # wait_thr.value waits the termination of the process.
   # The block form also waits the process when it returns.
   #
   # Closing stdin, stdout and stderr does not wait the process.
   #
-  def popen3(*cmd)
-    pw = IO::pipe   # pipe[0] for read, pipe[1] for write
-    pr = IO::pipe
-    pe = IO::pipe
+  def popen3(*cmd, &block)
+    if Hash === cmd.last
+      opts = cmd.pop.dup
+    else
+      opts = {}
+    end
 
-    pid = spawn(*cmd, STDIN=>pw[0], STDOUT=>pr[1], STDERR=>pe[1])
+    in_r, in_w = IO.pipe
+    opts[:in] = in_r
+    in_w.sync = true
+
+    out_r, out_w = IO.pipe
+    opts[:out] = out_w
+
+    err_r, err_w = IO.pipe
+    opts[:err] = err_w
+
+    popen_run(cmd, opts, [in_r, out_w, err_w], [in_w, out_r, err_r], &block)
+  end
+  module_function :popen3
+
+  # Open3.popen2 is similer to Open3.popen3 except it doesn't make a pipe for
+  # the standard error stream.
+  #
+  # Block form:
+  #
+  #   Open3.popen2(cmd... [, opts]) {|stdin, stdout, wait_thr|
+  #     pid = wait_thr.pid # pid of the started process.
+  #     ...
+  #     exit_status = wait_thr.value # Process::Status object returned.
+  #   }
+  #
+  # Non-block form:
+  #   
+  #   stdin, stdout, wait_thr = Open3.popen2(cmd... [, opts])
+  #   ...
+  #   stdin.close  # stdin and stdout should be closed explicitly in this form.
+  #   stdout.close
+  #
+  # Example:
+  #
+  #   Open3.popen2("wc -c") {|i,o,t|
+  #     i.print "answer to life the universe and everything"
+  #     i.close
+  #     p o.gets #=> "42\n"
+  #   }
+  #
+  #   Open3.popen2("bc -q") {|i,o,t| 
+  #     i.puts "obase=13"
+  #     i.puts "6 * 9"
+  #     p o.gets #=> "42\n"
+  #   }
+  #
+  #   Open3.popen2("dc") {|i,o,t|
+  #     i.print "42P"                                       
+  #     i.close
+  #     p o.read #=> "*"
+  #   }
+  #
+  def popen2(*cmd, &block)
+    if Hash === cmd.last
+      opts = cmd.pop.dup
+    else
+      opts = {}
+    end
+
+    in_r, in_w = IO.pipe
+    opts[:in] = in_r
+    in_w.sync = true
+
+    out_r, out_w = IO.pipe
+    opts[:out] = out_w
+
+    popen_run(cmd, opts, [in_r, out_w], [in_w, out_r], &block)
+  end
+  module_function :popen2
+
+  # Open3.popen2e is similer to Open3.popen3 except it merges
+  # the standard output stream and the standard error stream.
+  #
+  # Block form:
+  #
+  #   Open3.popen2e(cmd... [, opts]) {|stdin, stdout_and_stderr, wait_thr|
+  #     pid = wait_thr.pid # pid of the started process.
+  #     ...
+  #     exit_status = wait_thr.value # Process::Status object returned.
+  #   }
+  #
+  # Non-block form:
+  #   
+  #   stdin, stdout_and_stderr, wait_thr = Open3.popen2e(cmd... [, opts])
+  #   ...
+  #   stdin.close  # stdin and stdout_and_stderr should be closed explicitly in this form.
+  #   stdout_and_stderr.close
+  #
+  def popen2e(*cmd, &block)
+    if Hash === cmd.last
+      opts = cmd.pop.dup
+    else
+      opts = {}
+    end
+
+    in_r, in_w = IO.pipe
+    opts[:in] = in_r
+    in_w.sync = true
+
+    out_r, out_w = IO.pipe
+    opts[[:out, :err]] = out_w
+
+    popen_run(cmd, opts, [in_r, out_w], [in_w, out_r], &block)
+  end
+  module_function :popen2e
+
+  def popen_run(cmd, opts, child_io, parent_io) # :nodoc:
+    pid = spawn(*cmd, opts)
     wait_thr = Process.detach(pid)
-    pw[0].close
-    pr[1].close
-    pe[1].close
-    pi = [pw[1], pr[0], pe[0], wait_thr]
-    pw[1].sync = true
+    child_io.each {|io| io.close }
+    result = [*parent_io, wait_thr]
     if defined? yield
       begin
-	return yield(*pi)
+	return yield(*result)
       ensure
-	[pw[1], pr[0], pe[0]].each{|p| p.close unless p.closed?}
+	parent_io.each{|io| io.close unless io.closed?}
         wait_thr.join
       end
     end
-    pi
+    result
   end
-  module_function :popen3
+  module_function :popen_run
+  class << self
+    private :popen_run
+  end
+
+  # Open3.poutput3 captures the standard output and the standard error of a command.
+  #
+  #   stdout_str, stderr_str, status = Open3.poutput3(cmd... [, opts])
+  #
+  # The arguments cmd and opts are passed to Open3.popen3 except opts[:stdin_data].
+  #
+  # If opts[:stdin_data] is specified, it is sent to the command's standard input.
+  #
+  # Example:
+  #
+  #   # dot is a command of graphviz.
+  #   graph = <<'End'
+  #     digraph g {
+  #       a -> b
+  #     }
+  #   End
+  #   layouted_graph, dot_log = Open3.poutput3("dot -v", :stdin_data=>graph)
+  #
+  #   o, e, s = Open3.poutput3("echo a; sort >&2", :stdin_data=>"foo\nbar\nbaz\n")
+  #   p o #=> "a\n"
+  #   p e #=> "bar\nbaz\nfoo\n"
+  #   p s #=> #<Process::Status: pid 32682 exit 0>
+  #
+  def poutput3(*cmd, &block)
+    if Hash === cmd.last
+      opts = cmd.pop.dup
+    else
+      opts = {}
+    end
+
+    stdin_data = opts.delete(:stdin_data) || ''
+
+    popen3(*cmd, opts) {|i, o, e, t|
+      out_reader = Thread.new { o.read }
+      err_reader = Thread.new { e.read }
+      i.write stdin_data
+      i.close
+      [out_reader.value, err_reader.value, t.value]
+    }
+  end
+  module_function :poutput3
+
+  # Open3.poutput2 captures the standard output of a command.
+  #
+  #   stdout_str, status = Open3.poutput2(cmd... [, opts])
+  #
+  # The arguments cmd and opts are passed to Open3.popen2 except opts[:stdin_data].
+  #
+  # If opts[:stdin_data] is specified, it is sent to the command's standard input.
+  #
+  #   # factor is a command for integer factorization
+  #   o, s = Open3.poutput2("factor", :stdin_data=>"42")    
+  #   p o #=> "42: 2 3 7\n"
+  #
+  def poutput2(*cmd, &block)
+    if Hash === cmd.last
+      opts = cmd.pop.dup
+    else
+      opts = {}
+    end
+
+    stdin_data = opts.delete(:stdin_data) || ''
+
+    popen2(*cmd, opts) {|i, o, t|
+      out_reader = Thread.new { o.read }
+      i.write stdin_data
+      i.close
+      [out_reader.value, t.value]
+    }
+  end
+  module_function :poutput2
+
+  # Open3.poutput2e captures the standard output and the standard error of a command.
+  #
+  #   stdout_and_stderr_str, status = Open3.poutput2e(cmd... [, opts])
+  #
+  # The arguments cmd and opts are passed to Open3.popen2e except opts[:stdin_data].
+  #
+  # If opts[:stdin_data] is specified, it is sent to the command's standard input.
+  #
+  def poutput2e(*cmd, &block)
+    if Hash === cmd.last
+      opts = cmd.pop.dup
+    else
+      opts = {}
+    end
+
+    stdin_data = opts.delete(:stdin_data) || ''
+
+    popen2e(*cmd, opts) {|i, oe, t|
+      outerr_reader = Thread.new { oe.read }
+      i.write stdin_data
+      i.close
+      [outerr_reader.value, t.value]
+    }
+  end
+  module_function :poutput2e
+
+  # Open3.pipeline_rw starts list of commands as a pipeline with pipes
+  # which connects stdin of the first command and stdout of the last command.
+  #
+  #   Open3.pipeline_rw(cmd1, cmd2, ... [, opts]) {|first_stdin, last_stdout, wait_threads|
+  #     ...
+  #   }
+  #
+  #   first_stdin, last_stdout, wait_threads = Open3.pipeline_rw(cmd1, cmd2, ... [, opts])
+  #   ...
+  #   first_stdin.close
+  #   last_stdout.close
+  #
+  # Each cmd is a string or an array.
+  # If it is an array, the elements are passed to Kernel#spawn.
+  #
+  # The option to pass Kernel#spawn is constructed by merging
+  # +opts+, the last hash element of the array and
+  # specification for the pipe between each commands.
+  #
+  # Example:
+  #
+  #   Open3.pipeline_rw("tr -dc A-Za-z", "wc -c") {|i,o,ts|
+  #     i.puts "All persons more than a mile high to leave the court."
+  #     i.close
+  #     p o.gets #=> "42\n"
+  #   }
+  #
+  #   Open3.pipeline_rw("sort", "cat -n") {|stdin, stdout, wait_thrs|
+  #     stdin.puts "foo"
+  #     stdin.puts "bar"
+  #     stdin.puts "baz"
+  #     stdin.close     # send EOF to sort.
+  #     p stdout.read   #=> "     1\tbar\n     2\tbaz\n     3\tfoo\n"
+  #   }
+  def pipeline_rw(*cmds, &block)
+    if Hash === cmds.last
+      opts = cmds.pop.dup
+    else
+      opts = {}
+    end
+
+    in_r, in_w = IO.pipe
+    opts[:in] = in_r
+    in_w.sync = true
+
+    out_r, out_w = IO.pipe
+    opts[:out] = out_w
+
+    pipeline_run(cmds, opts, [in_r, out_w], [in_w, out_r], &block)
+  end
+  module_function :pipeline_rw
+
+  # Open3.pipeline_r starts list of commands as a pipeline with a pipe
+  # which connects stdout of the last command.
+  #
+  #   Open3.pipeline_r(cmd1, cmd2, ... [, opts]) {|last_stdout, wait_threads|
+  #     ...
+  #   }
+  #
+  #   last_stdout, wait_threads = Open3.pipeline_r(cmd1, cmd2, ... [, opts])
+  #   ...
+  #   last_stdout.close
+  #
+  # Example:
+  #
+  #   fname = "/usr/share/man/man1/ls.1.gz"
+  #   Open3.pipeline_r(["zcat", fname], "nroff -man", "colcrt") {|r, ts|
+  #     IO.copy_stream(r, STDOUT)
+  #   }
+  #
+  #   Open3.pipeline_r("zcat /var/log/apache2/access.log.*.gz",
+  #                    [{"LANG"=>"C"}, "grep", "GET /favicon.ico"],
+  #                    "logresolve") {|r, ts|
+  #     r.each_line {|line|
+  #       ...
+  #     }
+  #   }
+  #
+  #   Open3.pipeline_r("yes", "head -10") {|r, ts|
+  #     p r.read      #=> "y\ny\ny\ny\ny\ny\ny\ny\ny\ny\n"
+  #     p ts[0].value #=> #<Process::Status: pid 24910 SIGPIPE (signal 13)>
+  #     p ts[1].value #=> #<Process::Status: pid 24913 exit 0>
+  #   }
+  #
+  def pipeline_r(*cmds, &block)
+    if Hash === cmds.last
+      opts = cmds.pop.dup
+    else
+      opts = {}
+    end
+
+    out_r, out_w = IO.pipe
+    opts[:out] = out_w
+
+    pipeline_run(cmds, opts, [out_w], [out_r], &block)
+  end
+  module_function :pipeline_r
+
+  # Open3.pipeline_w starts list of commands as a pipeline with a pipe
+  # which connects stdin of the first command.
+  #
+  #   Open3.pipeline_w(cmd1, cmd2, ... [, opts]) {|first_stdin, wait_threads|
+  #     ...
+  #   }
+  #
+  #   first_stdin, wait_threads = Open3.pipeline_w(cmd1, cmd2, ... [, opts])
+  #   ...
+  #   first_stdin.close
+  #
+  # Example:
+  #
+  #   Open3.pipeline_w("bzip2 -c", :out=>"/tmp/hello.bz2") {|w, ts|
+  #     w.puts "hello" 
+  #   }
+  #
+  def pipeline_w(*cmds, &block)
+    if Hash === cmds.last
+      opts = cmds.pop.dup
+    else
+      opts = {}
+    end
+
+    in_r, in_w = IO.pipe
+    opts[:in] = in_r
+    in_w.sync = true
+
+    pipeline_run(cmds, opts, [in_r], [in_w], &block)
+  end
+  module_function :pipeline_w
+
+  # Open3.pipeline_start starts list of commands as a pipeline.
+  # No pipe made for stdin of the first command and
+  # stdout of the last command.
+  #
+  #   Open3.pipeline_start(cmd1, cmd2, ... [, opts]) {|wait_threads|
+  #     ...
+  #   }
+  #
+  #   wait_threads = Open3.pipeline_start(cmd1, cmd2, ... [, opts])
+  #   ...
+  #
+  def pipeline_start(*cmds, &block)
+    if Hash === cmds.last
+      opts = cmds.pop.dup
+    else
+      opts = {}
+    end
+
+    pipeline_run(cmds, opts, [], [], &block)
+  end
+  module_function :pipeline_start
+
+  # Open3.pipeline starts list of commands as a pipeline.
+  # It waits the finish of the commands.
+  # No pipe made for stdin of the first command and
+  # stdout of the last command.
+  #
+  #   status_list = Open3.pipeline(cmd1, cmd2, ... [, opts])
+  #
+  # Example:
+  #
+  #   fname = "/usr/share/man/man1/ruby.1.gz"
+  #   p Open3.pipeline(["zcat", fname], "nroff -man", "less")   
+  #   #=> [#<Process::Status: pid 11817 exit 0>,
+  #   #    #<Process::Status: pid 11820 exit 0>,
+  #   #    #<Process::Status: pid 11828 exit 0>]
+  #
+  #   # count lines
+  #   Open3.pipeline("sort", "uniq -c", :in=>"names.txt", :out=>"count")
+  #
+  def pipeline(*cmds)
+    if Hash === cmds.last
+      opts = cmds.pop.dup
+    else
+      opts = {}
+    end
+
+    pipeline_run(cmds, opts, [], []) {|ts|
+      ts.map {|t| t.value }
+    }
+  end
+  module_function :pipeline
+
+  def pipeline_run(cmds, pipeline_opts, child_io, parent_io, &block) # :nodoc:
+    if cmds.empty?
+      raise ArgumentError, "no commands"
+    end
+
+    opts_base = pipeline_opts.dup
+    opts_base.delete :in
+    opts_base.delete :out
+
+    wait_thrs = []
+    r = nil
+    cmds.each_with_index {|cmd, i|
+      cmd_opts = opts_base.dup
+      if String === cmd
+        cmd = [cmd]
+      else
+        cmd_opts.update cmd.pop if Hash === cmd.last
+      end
+      if i == 0
+        if !cmd_opts.include?(:in)
+          if pipeline_opts.include?(:in)
+            cmd_opts[:in] = pipeline_opts[:in]
+          end
+        end
+      else
+        cmd_opts[:in] = r
+      end
+      if i != cmds.length - 1
+        r2, w2 = IO.pipe
+        cmd_opts[:out] = w2
+      else
+        if !cmd_opts.include?(:out)
+          if pipeline_opts.include?(:out)
+            cmd_opts[:out] = pipeline_opts[:out]
+          end
+        end
+      end
+      pid = spawn(*cmd, cmd_opts)
+      wait_thrs << Process.detach(pid)
+      r.close if r
+      w2.close if w2
+      r = r2
+    }
+    result = parent_io + [wait_thrs]
+    child_io.each {|io| io.close }
+    if defined? yield
+      begin
+	return yield(*result)
+      ensure
+	parent_io.each{|io| io.close unless io.closed?}
+        wait_thrs.each {|t| t.join }
+      end
+    end
+    result
+  end
+  module_function :pipeline_run
+  class << self
+    private :pipeline_run
+  end
+
 end
 
 if $0 == __FILE__
Index: mvm/lib/forwardable.rb
===================================================================
--- mvm/lib/forwardable.rb	(revision 20561)
+++ mvm/lib/forwardable.rb	(revision 20562)
@@ -70,9 +70,30 @@
 #   Ruby
 #   nil
 #
-# Forwardable can be used to setup delegation at the object level as well.
+# SingleForwardable can be used to setup delegation at the object level as well.
 #
 #    printer = String.new
+#    printer.extend SingleForwardable        # prepare object for delegation
+#    printer.def_delegator "STDOUT", "puts"  # add delegation for STDOUT.puts()
+#    printer.puts "Howdy!"
+#
+# Also, SingleForwardable can be use to Class or Module.
+#
+#    module Facade
+#      extend SingleForwardable
+#      def_delegator :Implementation, :service
+#
+#      class Implementation
+#	  def service...
+#      end
+#    end
+#
+# If you want to use both Forwardable and SingleForwardable, you can
+# use methods def_instance_delegator and def_single_delegator, etc.
+# 
+# If the object isn't a Module and Class, You can too extend
+# Forwardable module. 
+#    printer = String.new
 #    printer.extend Forwardable              # prepare object for delegation
 #    printer.def_delegator "STDOUT", "puts"  # add delegation for STDOUT.puts()
 #    printer.puts "Howdy!"
@@ -111,8 +132,13 @@
 # Also see the example at forwardable.rb.
 
 module Forwardable
-  FORWARDABLE_VERSION = "1.0.0"
-  
+  FORWARDABLE_VERSION = "1.1.0"
+
+  @debug = nil
+  class<<self
+    attr_accessor :debug
+  end
+
   # Takes a hash as its argument.  The key is a symbol or an array of
   # symbols.  These symbols correspond to method names.  The value is
   # the accessor to which the methods will be delegated.
@@ -121,7 +147,7 @@
   #    delegate method => accessor
   #    delegate [method, method, ...] => accessor
   #
-  def delegate(hash)
+  def instance_delegate(hash)
     hash.each{ |methods, accessor|
       methods = methods.to_s unless methods.respond_to?(:each)
       methods.each{ |method|
@@ -144,34 +170,101 @@
   def def_instance_delegators(accessor, *methods)
     methods.delete("__send__")
     methods.delete("__id__")
-    methods.each{ |method|
+    for method in methods
       def_instance_delegator(accessor, method)
-    }
+    end
   end
 
-  #
-  # Defines a method _method_ which delegates to _obj_ (i.e. it calls
-  # the method of the same name in _obj_).  If _new_name_ is
-  # provided, it is used as the name for the delegate method.
-  #
   def def_instance_delegator(accessor, method, ali = method)
-    str = %Q{
+    line_no = __LINE__; str = %{
       def #{ali}(*args, &block)
-        #{accessor}.send(:#{method}, *args, &block)
+	begin
+	  #{accessor}.__send__(:#{method}, *args, &block)
+	rescue Exception
+	  $@.delete_if{|s| %r"#{Regexp.quote(__FILE__)}"o =~ s} unless Forwardable::debug
+	  ::Kernel::raise
+	end
       end
     }
-
     # If it's not a class or module, it's an instance
     begin
-      module_eval(str)
+      module_eval(str, __FILE__, line_no)
     rescue
-      instance_eval(str)
+      instance_eval(str, __FILE__, line_no)
     end
+
   end
 
+  alias delegate instance_delegate
   alias def_delegators def_instance_delegators
   alias def_delegator def_instance_delegator
 end
 
-# compatibility
-SingleForwardable = Forwardable
+#
+# Usage of The SingleForwardable is like Fowadable module.
+#
+module SingleForwardable
+  # Takes a hash as its argument.  The key is a symbol or an array of
+  # symbols.  These symbols correspond to method names.  The value is
+  # the accessor to which the methods will be delegated.
+  #
+  # :call-seq:
+  #    delegate method => accessor
+  #    delegate [method, method, ...] => accessor
+  #
+  def single_delegate(hash)
+    hash.each{ |methods, accessor|
+      methods = methods.to_s unless methods.respond_to?(:each)
+      methods.each{ |method|
+        def_single_delegator(accessor, method)
+      }
+    }
+  end
+
+  #
+  # Shortcut for defining multiple delegator methods, but with no
+  # provision for using a different name.  The following two code
+  # samples have the same effect:
+  #
+  #   def_delegators :@records, :size, :<<, :map
+  #
+  #   def_delegator :@records, :size
+  #   def_delegator :@records, :<<
+  #   def_delegator :@records, :map
+  #
+  def def_single_delegators(accessor, *methods)
+    methods.delete("__send__")
+    methods.delete("__id__")
+    for method in methods
+      def_single_delegator(accessor, method)
+    end
+  end
+
+  #
+  # Defines a method _method_ which delegates to _obj_ (i.e. it calls
+  # the method of the same name in _obj_).  If _new_name_ is
+  # provided, it is used as the name for the delegate method.
+  #
+  def def_single_delegator(accessor, method, ali = method)
+    line_no = __LINE__; str = %{
+      def #{ali}(*args, &block)
+	begin
+	  #{accessor}.__send__(:#{method}, *args, &block)
+	rescue Exception
+	  $@.delete_if{|s| %r"#{Regexp.quote(__FILE__)}"o =~ s} unless Forwardable::debug
+	  ::Kernel::raise
+	end
+      end
+    }
+
+    instance_eval(str, __FILE__, __LINE__)
+  end
+
+  alias delegate single_delegate
+  alias def_delegators def_single_delegators
+  alias def_delegator def_single_delegator
+end
+
+
+
+
Index: mvm/lib/rexml/xpath.rb
===================================================================
--- mvm/lib/rexml/xpath.rb	(revision 20561)
+++ mvm/lib/rexml/xpath.rb	(revision 20562)
@@ -15,10 +15,15 @@
     # 	node matching '*'.
     # namespaces::
     # 	If supplied, a Hash which defines a namespace mapping.
+    # variables::
+    #   If supplied, a Hash which maps $variables in the query
+    #   to values. This can be used to avoid XPath injection attacks
+    #   or to automatically handle escaping string values.
     #
     #  XPath.first( node )
     #  XPath.first( doc, "//b"} )
     #  XPath.first( node, "a/x:b", { "x"=>"http://doofus" } )
+    #  XPath.first( node, '/book/publisher/text()=$publisher', {}, {"publisher"=>"O'Reilly"})
     def XPath::first element, path=nil, namespaces=nil, variables={}
       raise "The namespaces argument, if supplied, must be a hash object." unless namespaces.nil? or namespaces.kind_of?(Hash)
       raise "The variables argument, if supplied, must be a hash object." unless variables.kind_of?(Hash)
@@ -38,10 +43,16 @@
     #   The xpath to search for.  If not supplied or nil, defaults to '*'
     # namespaces::
     # 	If supplied, a Hash which defines a namespace mapping
+    # variables::
+    #   If supplied, a Hash which maps $variables in the query
+    #   to values. This can be used to avoid XPath injection attacks
+    #   or to automatically handle escaping string values.
     #
     #  XPath.each( node ) { |el| ... }
     #  XPath.each( node, '/*[@attr='v']' ) { |el| ... }
     #  XPath.each( node, 'ancestor::x' ) { |el| ... }
+    #  XPath.each( node, '/book/publisher/text()=$publisher', {}, {"publisher"=>"O'Reilly"}) \
+    #    {|el| ... }
     def XPath::each element, path=nil, namespaces=nil, variables={}, &block
       raise "The namespaces argument, if supplied, must be a hash object." unless namespaces.nil? or namespaces.kind_of?(Hash)
       raise "The variables argument, if supplied, must be a hash object." unless variables.kind_of?(Hash)
Index: mvm/lib/rubygems/local_remote_options.rb
===================================================================
--- mvm/lib/rubygems/local_remote_options.rb	(revision 20561)
+++ mvm/lib/rubygems/local_remote_options.rb	(revision 20562)
@@ -99,7 +99,7 @@
   end
 
   ##
-  # Add the --source option
+  # Add the --update-source option
 
   def add_update_sources_option
 
Index: mvm/lib/rubygems/validator.rb
===================================================================
--- mvm/lib/rubygems/validator.rb	(revision 20561)
+++ mvm/lib/rubygems/validator.rb	(revision 20562)
@@ -200,6 +200,7 @@
     Dir.chdir(start_dir)
   end
 
+  private
   def remove_leading_dot_dir(path)
     path.sub(/^\.\//, "")
   end
Index: mvm/lib/net/protocol.rb
===================================================================
--- mvm/lib/net/protocol.rb	(revision 20561)
+++ mvm/lib/net/protocol.rb	(revision 20562)
@@ -131,9 +131,15 @@
     BUFSIZE = 1024 * 16
 
     def rbuf_fill
-      timeout(@read_timeout) {
-        @rbuf << @io.sysread(BUFSIZE)
-      }
+      begin
+        @rbuf << @io.read_nonblock(BUFSIZE)
+      rescue Errno::EWOULDBLOCK
+        if IO.select([@io], nil, nil, @read_timeout)
+          @rbuf << @io.read_nonblock(BUFSIZE)
+        else
+          raise Timeout::TimeoutError
+        end
+      end
     end
 
     def rbuf_consume(len)
Index: mvm/compile.c
===================================================================
--- mvm/compile.c	(revision 20561)
+++ mvm/compile.c	(revision 20562)
@@ -415,7 +415,7 @@
 }
 
 VALUE
-iseq_compile(VALUE self, NODE *node)
+ruby_iseq_compile(VALUE self, NODE *node)
 {
     DECL_ANCHOR(ret);
     rb_iseq_t *iseq;
@@ -502,7 +502,7 @@
 }
 
 int
-iseq_translate_threaded_code(rb_iseq_t *iseq)
+ruby_iseq_translate_threaded_code(rb_iseq_t *iseq)
 {
 #if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
     extern const void **vm_get_insns_address_table(void);
@@ -960,7 +960,7 @@
     iseq_set_optargs_table(iseq);
 
     debugs("[compile step 5 (iseq_translate_threaded_code)] \n");
-    iseq_translate_threaded_code(iseq);
+    ruby_iseq_translate_threaded_code(iseq);
 
     if (compile_debug > 1) {
 	VALUE str = ruby_iseq_disasm(iseq->self);
@@ -1355,7 +1355,8 @@
 				    rb_hash_aset(map, obj, INT2FIX(lobj->position - (pos+len)));
 				}
 				else {
-				    rb_warning("duplicated when clause is ignored");
+				    rb_compile_warning(RSTRING_PTR(iseq->filename), iobj->line_no,
+						       "duplicated when clause is ignored");
 				}
 			    }
 			    generated_iseq[pos + 1 + j] = map;
@@ -4974,14 +4975,14 @@
 }
 
 VALUE
-insns_name_array(void)
+ruby_insns_name_array(void)
 {
     VALUE ary = rb_ary_new();
     int i;
     for (i = 0; i < sizeof(insn_name_info) / sizeof(insn_name_info[0]); i++) {
-	rb_ary_push(ary, rb_str_new2(insn_name_info[i]));
+	rb_ary_push(ary, rb_obj_freeze(rb_str_new2(insn_name_info[i])));
     }
-    return ary;
+    return rb_obj_freeze(ary);
 }
 
 static LABEL *
@@ -5051,7 +5052,7 @@
 	    eiseqval = 0;
 	}
 	else {
-	    eiseqval = iseq_load(0, ptr[1], iseq->self, Qnil);
+	    eiseqval = ruby_iseq_load(ptr[1], iseq->self, Qnil);
 	}
 
 	lstart = register_label(iseq, labels_table, ptr[2]);
@@ -5064,8 +5065,6 @@
     return COMPILE_OK;
 }
 
-struct st_table *insn_make_insn_table(void);
-
 static int
 iseq_build_body(rb_iseq_t *iseq, LINK_ANCHOR *anchor,
 		VALUE body, struct st_table *labels_table)
@@ -5081,7 +5080,7 @@
     static struct st_table *insn_table;
 
     if (insn_table == 0) {
-	insn_table = insn_make_insn_table();
+	insn_table = ruby_insn_make_insn_table();
     }
 
     for (i=0; i<len; i++) {
@@ -5137,7 +5136,7 @@
 			{
 			    if (op != Qnil) {
 				if (TYPE(op) == T_ARRAY) {
-				    argv[j] = iseq_load(0, op, iseq->self, Qnil);
+				    argv[j] = ruby_iseq_load(op, iseq->self, Qnil);
 				}
 				else if (CLASS_OF(op) == rb_cISeq) {
 				    argv[j] = op;
@@ -5202,8 +5201,8 @@
 static inline VALUE CHECK_INTEGER(VALUE v) {NUM2LONG(v); return v;}
 
 VALUE
-iseq_build_from_ary(rb_iseq_t *iseq, VALUE locals, VALUE args,
-		    VALUE exception, VALUE body)
+ruby_iseq_build_from_ary(rb_iseq_t *iseq, VALUE locals, VALUE args,
+			 VALUE exception, VALUE body)
 {
     int i;
     ID *tbl;
Index: mvm/proc.c
===================================================================
--- mvm/proc.c	(revision 20561)
+++ mvm/proc.c	(revision 20562)
@@ -20,9 +20,12 @@
     NODE *body;
 };
 
+VALUE rb_iseq_parameters(const rb_iseq_t *iseq, int is_proc);
+
 static VALUE bmcall(VALUE, VALUE);
 static int method_arity(VALUE);
 static VALUE rb_obj_is_method(VALUE m);
+static rb_iseq_t *get_method_iseq(VALUE method);
 
 /* Proc */
 
@@ -603,15 +606,23 @@
 }
 
 static rb_iseq_t *
-get_proc_iseq(VALUE self)
+get_proc_iseq(VALUE self, int *is_proc)
 {
     rb_proc_t *proc;
     rb_iseq_t *iseq;
 
     GetProcPtr(self, proc);
     iseq = proc->block.iseq;
-    if (!RUBY_VM_NORMAL_ISEQ_P(iseq))
-	return 0;
+    if (is_proc) *is_proc = !proc->is_lambda;
+    if (!RUBY_VM_NORMAL_ISEQ_P(iseq)) {
+	NODE *node = (NODE *)iseq;
+	iseq = 0;
+	if (nd_type(node) == NODE_IFUNC && node->nd_cfnc == bmcall) {
+	    /* method(:foo).to_proc */
+	    iseq = get_method_iseq(node->nd_tval);
+	    if (is_proc) *is_proc = 0;
+	}
+    }
     return iseq;
 }
 
@@ -642,11 +653,48 @@
 VALUE
 rb_proc_location(VALUE self)
 {
-    return iseq_location(get_proc_iseq(self));
+    return iseq_location(get_proc_iseq(self, 0));
 }
 
+static VALUE
+unnamed_parameters(int arity)
+{
+    VALUE a, param = rb_ary_new2((arity < 0) ? -arity : arity);
+    int n = (arity < 0) ? ~arity : arity;
+    ID req, rest;
+    CONST_ID(req, "req");
+    a = rb_ary_new3(1, ID2SYM(req));
+    OBJ_FREEZE(a);
+    for (; n; --n) {
+	rb_ary_push(param, a);
+    }
+    if (arity < 0) {
+	CONST_ID(rest, "rest");
+	rb_ary_store(param, ~arity, rb_ary_new3(1, ID2SYM(rest)));
+    }
+    return param;
+}
+
 /*
  * call-seq:
+ *    proc.parameters  => array
+ *
+ * returns the parameter information of this proc
+ */
+
+static VALUE
+rb_proc_parameters(VALUE self)
+{
+    int is_proc;
+    rb_iseq_t *iseq = get_proc_iseq(self, &is_proc);
+    if (!iseq) {
+	return unnamed_parameters(proc_arity(self));
+    }
+    return rb_iseq_parameters(iseq, is_proc);
+}
+
+/*
+ * call-seq:
  *   prc == other_proc   =>  true or false
  *
  * Return <code>true</code> if <i>prc</i> is the same object as
@@ -1458,6 +1506,8 @@
     Data_Get_Struct(method, struct METHOD, data);
     body = data->body;
     switch (nd_type(body)) {
+      case NODE_BMETHOD:
+	return get_proc_iseq(body->nd_cval, 0);
       case RUBY_VM_METHOD_NODE:
 	GetISeqPtr((VALUE)body->nd_body, iseq);
 	if (RUBY_VM_NORMAL_ISEQ_P(iseq)) break;
@@ -1482,6 +1532,23 @@
 }
 
 /*
+ * call-seq:
+ *    meth.parameters  => array
+ *
+ * returns the parameter information of this method
+ */
+
+static VALUE
+rb_method_parameters(VALUE method)
+{
+    rb_iseq_t *iseq = get_method_iseq(method);
+    if (!iseq) {
+	return unnamed_parameters(method_arity(method));
+    }
+    return rb_iseq_parameters(iseq, 0);
+}
+
+/*
  *  call-seq:
  *   meth.to_s      =>  string
  *   meth.inspect   =>  string
@@ -1814,6 +1881,7 @@
     rb_define_method(rb_cProc, "binding", proc_binding, 0);
     rb_define_method(rb_cProc, "curry", proc_curry, -1);
     rb_define_method(rb_cProc, "source_location", rb_proc_location, 0);
+    rb_define_method(rb_cProc, "parameters", rb_proc_parameters, 0);
 
     /* Exceptions */
     rb_eLocalJumpError = rb_define_class("LocalJumpError", rb_eStandardError);
@@ -1849,6 +1917,7 @@
     rb_define_method(rb_cMethod, "owner", method_owner, 0);
     rb_define_method(rb_cMethod, "unbind", method_unbind, 0);
     rb_define_method(rb_cMethod, "source_location", rb_method_location, 0);
+    rb_define_method(rb_cMethod, "parameters", rb_method_parameters, 0);
     rb_define_method(rb_mKernel, "method", rb_obj_method, 1);
     rb_define_method(rb_mKernel, "public_method", rb_obj_public_method, 1);
 
@@ -1867,6 +1936,7 @@
     rb_define_method(rb_cUnboundMethod, "owner", method_owner, 0);
     rb_define_method(rb_cUnboundMethod, "bind", umethod_bind, 1);
     rb_define_method(rb_cUnboundMethod, "source_location", rb_method_location, 0);
+    rb_define_method(rb_cUnboundMethod, "parameters", rb_method_parameters, 0);
 
     /* Module#*_method */
     rb_define_method(rb_cModule, "instance_method", rb_mod_instance_method, 1);
Index: mvm/thread.c
===================================================================
--- mvm/thread.c	(revision 20561)
+++ mvm/thread.c	(revision 20562)
@@ -2087,6 +2087,34 @@
 /* for IO */
 
 #if defined(NFDBITS) && defined(HAVE_RB_FD_INIT)
+
+/*
+ * several Unix platform supports file descriptors bigger than FD_SETSIZE
+ * in select(2) system call.
+ *
+ * - Linux 2.2.12 (?)
+ * - NetBSD 1.2 (src/sys/kern/sys_generic.c:1.25)
+ *   select(2) documents how to allocate fd_set dynamically.
+ *   http://netbsd.gw.com/cgi-bin/man-cgi?select++NetBSD-4.0
+ * - FreeBSD 2.2 (src/sys/kern/sys_generic.c:1.19)
+ * - OpenBSD 2.0 (src/sys/kern/sys_generic.c:1.4)
+ *   select(2) documents how to allocate fd_set dynamically.
+ *   http://www.openbsd.org/cgi-bin/man.cgi?query=select&manpath=OpenBSD+4.4
+ * - HP-UX documents how to allocate fd_set dynamically. 
+ *   http://docs.hp.com/en/B2355-60105/select.2.html
+ * - Solaris 8 has select_large_fdset
+ *
+ * When fd_set is not big enough to hold big file descriptors,
+ * it should be allocated dynamically.
+ * Note that this assumes fd_set is structured as bitmap.
+ *
+ * rb_fd_init allocates the memory.
+ * rb_fd_term free the memory.
+ * rb_fd_set may re-allocates bitmap.
+ *
+ * So rb_fd_set doesn't reject file descriptors bigger than FD_SETSIZE.
+ */
+
 void
 rb_fd_init(volatile rb_fdset_t *fds)
 {
Index: mvm/spec/default.mspec
===================================================================
--- mvm/spec/default.mspec	(revision 20561)
+++ mvm/spec/default.mspec	(revision 20562)
@@ -1,12 +1,5 @@
+load File.dirname(__FILE__) + '/rubyspec/ruby.1.9.mspec'
 class MSpecScript
-  # An ordered list of the directories containing specs to run
-  # as the CI process.
-  set :ci_files, %w[
-    spec/rubyspec/1.9/core
-    spec/rubyspec/1.9/language
-    spec/rubyspec/1.9/library
-  ]
-
   builddir = File.expand_path(File.join(File.dirname(__FILE__), '..'))
   srcdir = ENV['SRCDIR']
   srcdir ||= $1 if File.read("#{builddir}/Makefile")[/^\s*srcdir\s*=\s*(.+)/i]
Index: mvm/win32/win32.c
===================================================================
--- mvm/win32/win32.c	(revision 20561)
+++ mvm/win32/win32.c	(revision 20562)
@@ -533,6 +533,18 @@
     return NULL;
 }
 
+static struct ChildRecord *
+FindChildSlotByHandle(HANDLE h)
+{
+
+    FOREACH_CHILD(child) {
+	if (child->hProcess == h) {
+	    return child;
+	}
+    } END_FOREACH_CHILD;
+    return NULL;
+}
+
 static void
 CloseChildHandle(struct ChildRecord *child)
 {
@@ -3062,7 +3074,7 @@
 	    return -1;
 	}
 
-	return poll_child_status(ChildRecord + ret, stat_loc);
+	return poll_child_status(FindChildSlotByHandle(events[ret]), stat_loc);
     }
     else {
 	struct ChildRecord* child = FindChildSlot(pid);
@@ -4304,6 +4316,10 @@
     if (is_socket(sock))
 	return rb_w32_recv(fd, buf, size, 0);
 
+    // validate fd by using _get_osfhandle() because we cannot access _nhandle
+    if (_get_osfhandle(fd) == -1) {
+	return -1;
+    }
     if (!(_osfile(fd) & FOPEN)) {
 	errno = EBADF;
 	return -1;
@@ -4379,11 +4395,15 @@
 
 	    if (!GetOverlappedResult((HANDLE)_osfhnd(fd), &ol, &read, TRUE) &&
 		(err = GetLastError()) != ERROR_HANDLE_EOF) {
-		errno = map_errno(err);
+		int ret = 0;
+		if (err != ERROR_BROKEN_PIPE) {
+		    errno = map_errno(err);
+		    ret = -1;
+		}
 		CloseHandle(ol.hEvent);
 		cancel_io((HANDLE)_osfhnd(fd));
 		MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
-		return -1;
+		return ret;
 	    }
 	}
     }
@@ -4418,6 +4438,10 @@
     if (is_socket(sock))
 	return rb_w32_send(fd, buf, size, 0);
 
+    // validate fd by using _get_osfhandle() because we cannot access _nhandle
+    if (_get_osfhandle(fd) == -1) {
+	return -1;
+    }
     if (!(_osfile(fd) & FOPEN)) {
 	errno = EBADF;
 	return -1;
@@ -4670,6 +4694,10 @@
 int
 rb_w32_isatty(int fd)
 {
+    // validate fd by using _get_osfhandle() because we cannot access _nhandle
+    if (_get_osfhandle(fd) == -1) {
+	return 0;
+    }
     if (!(_osfile(fd) & FOPEN)) {
 	errno = EBADF;
 	return 0;
Index: mvm/vm_method.c
===================================================================
--- mvm/vm_method.c	(revision 20561)
+++ mvm/vm_method.c	(revision 20562)
@@ -1058,15 +1058,6 @@
     return 0;
 }
 
-/*
- *  call-seq:
- *     obj.respond_to?(symbol, include_private=false) => true or false
- *
- *  Returns +true+> if _obj_ responds to the given
- *  method. Private methods are included in the search only if the
- *  optional second parameter evaluates to +true+.
- */
-
 int
 rb_obj_respond_to(VALUE obj, ID id, int priv)
 {
@@ -1095,7 +1086,7 @@
  *  call-seq:
  *     obj.respond_to?(symbol, include_private=false) => true or false
  *
- *  Returns +true+> if _obj_ responds to the given
+ *  Returns +true+ if _obj_ responds to the given
  *  method. Private methods are included in the search only if the
  *  optional second parameter evaluates to +true+.
  */
Index: mvm/gc.c
===================================================================
--- mvm/gc.c	(revision 20561)
+++ mvm/gc.c	(revision 20562)
@@ -1053,10 +1053,10 @@
     return STACK_LENGTH;
 }
 
-int
-ruby_stack_check(void)
+static int
+stack_check(void)
 {
-    int ret = 0;
+    int ret;
     rb_thread_t *th = GET_THREAD();
 
     SET_STACK_END;
@@ -1070,6 +1070,16 @@
     return ret;
 }
 
+int
+ruby_stack_check(void)
+{
+#if defined(POSIX_SIGNAL) && defined(SIGSEGV) && defined(HAVE_SIGALTSTACK)
+    return 0;
+#else
+    return stack_check();
+#endif
+}
+
 static void
 init_mark_stack(rb_objspace_t *objspace)
 {
@@ -1276,7 +1286,7 @@
     if (obj->as.basic.flags & FL_MARK) return;  /* already marked */
     obj->as.basic.flags |= FL_MARK;
 
-    if (lev > GC_LEVEL_MAX || (lev == 0 && ruby_stack_check())) {
+    if (lev > GC_LEVEL_MAX || (lev == 0 && stack_check())) {
 	if (!mark_stack_overflow) {
 	    if (mark_stack_ptr - mark_stack < MARK_STACK_MAX) {
 		*mark_stack_ptr = ptr;
Index: mvm/strftime.c
===================================================================
--- mvm/strftime.c	(revision 20561)
+++ mvm/strftime.c	(revision 20562)
@@ -319,6 +319,7 @@
 			goto unknown;
 
 		case '%':
+			FILL_PADDING(1);
 			*s++ = '%';
 			continue;
 
Index: mvm/parse.y
===================================================================
--- mvm/parse.y	(revision 20561)
+++ mvm/parse.y	(revision 20562)
@@ -1176,12 +1176,12 @@
 			$$ = dispatch3(binary, $1, ripper_intern("or"), $3);
 		    %*/
 		    }
-		| keyword_not expr
+		| keyword_not opt_nl expr
 		    {
 		    /*%%%*/
-			$$ = call_uni_op(cond($2), '!');
+			$$ = call_uni_op(cond($3), '!');
 		    /*%
-			$$ = dispatch2(unary, ripper_intern("not"), $2);
+			$$ = dispatch2(unary, ripper_intern("not"), $3);
 		    %*/
 		    }
 		| '!' command_call
Index: mvm/process.c
===================================================================
--- mvm/process.c	(revision 20561)
+++ mvm/process.c	(revision 20562)
@@ -1211,6 +1211,7 @@
     EXEC_OPTION_DUP2,
     EXEC_OPTION_CLOSE,
     EXEC_OPTION_OPEN,
+    EXEC_OPTION_DUP2_CHILD,
     EXEC_OPTION_CLOSE_OTHERS
 };
 
@@ -1222,6 +1223,17 @@
     if (FIXNUM_P(v)) {
         fd = FIX2INT(v);
     }
+    else if (SYMBOL_P(v)) {
+        ID id = SYM2ID(v);
+        if (id == rb_intern("in"))
+            fd = 0;
+        else if (id == rb_intern("out"))
+            fd = 1;
+        else if (id == rb_intern("err"))
+            fd = 2;
+        else
+            goto wrong;
+    }
     else if (!NIL_P(tmp = rb_check_convert_type(v, T_FILE, "IO", "to_io"))) {
         rb_io_t *fptr;
         GetOpenFile(tmp, fptr);
@@ -1233,6 +1245,7 @@
         rb_raise(rb_eArgError, "wrong exec redirect");
     }
     if (fd < 0) {
+      wrong:
         rb_raise(rb_eArgError, "negative file descriptor");
     }
     return INT2FIX(fd);
@@ -1253,6 +1266,18 @@
             index = EXEC_OPTION_CLOSE;
             param = Qnil;
         }
+        else if (id == rb_intern("in")) {
+            index = EXEC_OPTION_DUP2;
+            param = INT2FIX(0);
+        }
+        else if (id == rb_intern("out")) {
+            index = EXEC_OPTION_DUP2;
+            param = INT2FIX(1);
+        }
+        else if (id == rb_intern("err")) {
+            index = EXEC_OPTION_DUP2;
+            param = INT2FIX(2);
+        }
         else {
             rb_raise(rb_eArgError, "wrong exec redirect symbol: %s",
                                    rb_id2name(id));
@@ -1268,20 +1293,27 @@
         break;
 
       case T_ARRAY:
-        index = EXEC_OPTION_OPEN;
         path = rb_ary_entry(val, 0);
-        FilePathValue(path);
-        flags = rb_ary_entry(val, 1);
-        if (NIL_P(flags))
-            flags = INT2NUM(O_RDONLY);
-        else if (TYPE(flags) == T_STRING)
-            flags = INT2NUM(rb_io_modestr_oflags(StringValueCStr(flags)));
-        else
-            flags = rb_to_int(flags);
-        perm = rb_ary_entry(val, 2);
-        perm = NIL_P(perm) ? INT2FIX(0644) : rb_to_int(perm);
-        param = hide_obj(rb_ary_new3(3, hide_obj(rb_str_dup(path)),
-                                        flags, perm));
+        if (RARRAY_LEN(val) == 2 && SYMBOL_P(path) &&
+            SYM2ID(path) == rb_intern("child")) {
+            index = EXEC_OPTION_DUP2_CHILD;
+            param = check_exec_redirect_fd(rb_ary_entry(val, 1));
+        }
+        else {
+            index = EXEC_OPTION_OPEN;
+            FilePathValue(path);
+            flags = rb_ary_entry(val, 1);
+            if (NIL_P(flags))
+                flags = INT2NUM(O_RDONLY);
+            else if (TYPE(flags) == T_STRING)
+                flags = INT2NUM(rb_io_modestr_oflags(StringValueCStr(flags)));
+            else
+                flags = rb_to_int(flags);
+            perm = rb_ary_entry(val, 2);
+            perm = NIL_P(perm) ? INT2FIX(0644) : rb_to_int(perm);
+            param = hide_obj(rb_ary_new3(3, hide_obj(rb_str_dup(path)),
+                                            flags, perm));
+        }
         break;
 
       case T_STRING:
@@ -1468,7 +1500,7 @@
     int index, i;
     int maxhint = -1;
 
-    for (index = EXEC_OPTION_DUP2; index <= EXEC_OPTION_OPEN; index++) {
+    for (index = EXEC_OPTION_DUP2; index <= EXEC_OPTION_DUP2_CHILD; index++) {
         ary = rb_ary_entry(options, index);
         if (NIL_P(ary))
             continue;
@@ -1478,16 +1510,53 @@
             if (RTEST(rb_hash_lookup(h, INT2FIX(fd)))) {
                 rb_raise(rb_eArgError, "fd %d specified twice", fd);
             }
-            rb_hash_aset(h, INT2FIX(fd), Qtrue);
+            if (index == EXEC_OPTION_OPEN || index == EXEC_OPTION_DUP2)
+                rb_hash_aset(h, INT2FIX(fd), Qtrue);
+            else if (index == EXEC_OPTION_DUP2_CHILD)
+                rb_hash_aset(h, INT2FIX(fd), RARRAY_PTR(elt)[1]);
+            else /* index == EXEC_OPTION_CLOSE */
+                rb_hash_aset(h, INT2FIX(fd), INT2FIX(-1));
             if (maxhint < fd)
                 maxhint = fd;
-            if (index == EXEC_OPTION_DUP2) {
+            if (index == EXEC_OPTION_DUP2 || index == EXEC_OPTION_DUP2_CHILD) {
                 fd = FIX2INT(RARRAY_PTR(elt)[1]);
                 if (maxhint < fd)
                     maxhint = fd;
             }
         }
     }
+
+    ary = rb_ary_entry(options, EXEC_OPTION_DUP2_CHILD);
+    if (!NIL_P(ary)) {
+        for (i = 0; i < RARRAY_LEN(ary); i++) {
+            VALUE elt = RARRAY_PTR(ary)[i];
+            int newfd = FIX2INT(RARRAY_PTR(elt)[0]);
+            int oldfd = FIX2INT(RARRAY_PTR(elt)[1]);
+            int lastfd = oldfd;
+            VALUE val = rb_hash_lookup(h, INT2FIX(lastfd));
+            long depth = 0;
+            while (FIXNUM_P(val) && 0 <= FIX2INT(val)) {
+                lastfd = FIX2INT(val);
+                val = rb_hash_lookup(h, val);
+                if (RARRAY_LEN(ary) < depth)
+                    rb_raise(rb_eArgError, "cyclic child fd redirection from %d", oldfd);
+                depth++;
+            }
+            if (val != Qtrue)
+                rb_raise(rb_eArgError, "child fd %d is not redirected", oldfd);
+            if (oldfd != lastfd) {
+                VALUE val2;
+                rb_ary_store(elt, 1, INT2FIX(lastfd));
+                rb_hash_aset(h, INT2FIX(newfd), INT2FIX(lastfd));
+                val = INT2FIX(oldfd);
+                while (FIXNUM_P(val2 = rb_hash_lookup(h, val))) {
+                    rb_hash_aset(h, val, INT2FIX(lastfd));
+                    val = val2;
+                }
+            }
+        }
+    }
+
     if (rb_ary_entry(options, EXEC_OPTION_CLOSE_OTHERS) != Qfalse) {
         rb_ary_store(options, EXEC_OPTION_CLOSE_OTHERS, INT2FIX(maxhint));
     }
@@ -1637,25 +1706,34 @@
 
 /*
  *  call-seq:
- *     exec([env,] command [, arg, ...] [,options])
+ *     exec([env,] command... [,options])
  *
  *  Replaces the current process by running the given external _command_.
- *  If optional arguments, sequence of +arg+, are not given, that argument is
- *  taken as a line that is subject to shell expansion before being
- *  executed. If one or more +arg+ given, they
- *  are passed as parameters to _command_ with no shell
- *  expansion. If +command+ is a two-element array, the first
- *  element is the command to be executed, and the second argument is
- *  used as the <code>argv[0]</code> value, which may show up in process
- *  listings. In order to execute the command, one of the <code>exec(2)</code> 
+ *  _command..._ is one of following forms.
+ *
+ *    commandline                 : command line string which is passed to a shell
+ *    cmdname, arg1, ...          : command name and one or more arguments (no shell)
+ *    [cmdname, argv0], arg1, ... : command name and arguments including argv[0] (no shell)
+ *
+ *  If single string is given as the command,
+ *  it is taken as a command line that is subject to shell expansion before being executed.
+ *
+ *  If two or more +string+ given,
+ *  the first is taken as a command name and
+ *  the rest are passed as parameters to command with no shell expansion.
+ *
+ *  If a two-element array at the beginning of the command,
+ *  the first element is the command to be executed,
+ *  and the second argument is used as the <code>argv[0]</code> value,
+ *  which may show up in process listings.
+ *
+ *  In order to execute the command, one of the <code>exec(2)</code> 
  *  system calls is used, so the running command may inherit some of the environment 
  *  of the original program (including open file descriptors).
- *
- *  The hash arguments, env and options, are same as
- *  <code>system</code> and <code>spawn</code>.
+ *  This behavior is modified by env and options.
  *  See <code>spawn</code> for details.
  *
- *  Raises SystemCallError if the _command_ couldn't execute (typically
+ *  Raises SystemCallError if the command couldn't execute (typically
  *  <code>Errno::ENOENT</code> when it was not found).
  *
  *     exec "echo *"       # echoes list of files in current directory
@@ -1692,7 +1770,11 @@
     va_list ap;
     FILE *tty;
     int save = errno;
+#ifdef _WIN32
+    tty = fopen("con", "w");
+#else
     tty = fopen("/dev/tty", "w");
+#endif
     if (!tty)
         return;
 
@@ -1801,6 +1883,12 @@
 }
 
 static int
+intrcmp(const void *a, const void *b)
+{
+    return *(int*)b - *(int*)a;
+}
+
+static int
 run_exec_dup2(VALUE ary, VALUE save)
 {
     int n, i;
@@ -1825,7 +1913,10 @@
     }
 
     /* sort the table by oldfd: O(n log n) */
-    qsort(pairs, n, sizeof(struct fd_pair), intcmp);
+    if (!RTEST(save))
+        qsort(pairs, n, sizeof(struct fd_pair), intcmp);
+    else
+        qsort(pairs, n, sizeof(struct fd_pair), intrcmp);
 
     /* initialize older_index and num_newer: O(n log n) */
     for (i = 0; i < n; i++) {
@@ -1969,6 +2060,23 @@
     return 0;
 }
 
+static int
+run_exec_dup2_child(VALUE ary, VALUE save)
+{
+    int i, ret;
+    for (i = 0; i < RARRAY_LEN(ary); i++) {
+        VALUE elt = RARRAY_PTR(ary)[i];
+        int newfd = FIX2INT(RARRAY_PTR(elt)[0]);
+        int oldfd = FIX2INT(RARRAY_PTR(elt)[1]);
+
+        if (save_redirect_fd(newfd, save) < 0)
+            return -1;
+        ret = redirect_dup2(oldfd, newfd);
+        if (ret == -1) return -1;
+    }
+    return 0;
+}
+
 #ifdef HAVE_SETPGID
 static int
 run_exec_pgroup(VALUE obj, VALUE save)
@@ -2137,6 +2245,12 @@
             return -1;
     }
 
+    obj = rb_ary_entry(options, EXEC_OPTION_DUP2_CHILD);
+    if (!NIL_P(obj)) {
+        if (run_exec_dup2_child(obj, soptions) == -1)
+            return -1;
+    }
+
     return 0;
 }
 
@@ -2668,17 +2782,25 @@
 
 /*
  *  call-seq:
- *     system([env,] cmd [, arg, ...] [,options])    => true, false or nil
+ *     system([env,] command... [,options])    => true, false or nil
  *
- *  Executes _cmd_ in a subshell, returning +true+ if the command
- *  gives zero exit status, +false+ for non zero exit status. Returns
- *  +nil+ if command execution fails.  An error status is available in
- *  <code>$?</code>. The arguments are processed in the same way as
- *  for <code>Kernel::exec</code>.
+ *  Executes _command..._ in a subshell.
+ *  _command..._ is one of following forms.
  *
+ *    commandline                 : command line string which is passed to a shell
+ *    cmdname, arg1, ...          : command name and one or more arguments (no shell)
+ *    [cmdname, argv0], arg1, ... : command name and arguments including argv[0] (no shell)
+ *
+ *  system returns +true+ if the command gives zero exit status,
+ *  +false+ for non zero exit status.
+ *  Returns +nil+ if command execution fails.
+ *  An error status is available in <code>$?</code>.
+ *  The arguments are processed in the same way as
+ *  for <code>Kernel.spawn</code>.
+ *
  *  The hash arguments, env and options, are same as
  *  <code>exec</code> and <code>spawn</code>.
- *  See <code>spawn</code> for details.
+ *  See <code>Kernel.spawn</code> for details.
  *
  *     system("echo *")
  *     system("echo", "*")
@@ -2722,11 +2844,57 @@
 
 /*
  *  call-seq:
- *     spawn([env,] cmd [, arg, ...] [,options])     => pid
+ *     spawn([env,] command... [,options])     => pid
+ *     Process.spawn([env,] command... [,options])     => pid
  *
- *  Similar to <code>Kernel::system</code> except for not waiting for
- *  end of _cmd_, but returns its <i>pid</i>.
+ *  spawn executes specified command and return its pid.
+ *  It doesn't wait for end of the command.
  *
+ *  spawn has bunch of options to specify process attributes:
+ *
+ *    env: hash
+ *      name => val : set the environment variable
+ *      name => nil : unset the environment variable
+ *    command...:
+ *      commandline                 : command line string which is passed to a shell
+ *      cmdname, arg1, ...          : command name and one or more arguments (no shell)
+ *      [cmdname, argv0], arg1, ... : command name and arguments including argv[0] (no shell)
+ *    options: hash
+ *      clearing environment variables:
+ *        :unsetenv_others => true   : clear environment variables except specified by env
+ *        :unsetenv_others => false  : don't clear (default)
+ *      process group:
+ *        :pgroup => true or 0 : process leader
+ *        :pgroup => pgid      : join to specified process group 
+ *      resource limit: resourcename is core, cpu, data, etc.  See Process.setrlimit.
+ *        :rlimit_resourcename => limit
+ *        :rlimit_resourcename => [cur_limit, max_limit]
+ *      current directory:
+ *        :chdir => str
+ *      umask:
+ *        :umask => int
+ *      redirection:
+ *        key:
+ *          FD              : single file descriptor in child process
+ *          [FD, FD, ...]   : multiple file descriptor in child process
+ *        value:
+ *          FD                        : redirect to the file descriptor in parent process
+ *          string                    : redirect to file with open(string, "r" or "w")
+ *          [string]                  : redirect to file with open(string, File::RDONLY)
+ *          [string, open_mode]       : redirect to file with open(string, open_mode, 0644)
+ *          [string, open_mode, perm] : redirect to file with open(string, open_mode, perm)
+ *          [:child, FD]              : redirect to the redirected file descriptor
+ *          :close                    : close the file descriptor in child process
+ *        FD is one of follows
+ *          :in     : the file descriptor 0
+ *          :out    : the file descriptor 1
+ *          :err    : the file descriptor 2
+ *          integer : the file descriptor of specified the integer
+ *          io      : the file descriptor specified as io.fileno
+ *      file descriptor inheritance: close non-redirected non-standard fds (3, 4, 5, ...) or not
+ *        :close_others => false : inherit fds (default for system and exec)
+ *        :close_others => true  : don't inherit (default for spawn and IO.popen)
+ *
  *  If a hash is given as +env+, the environment is
  *  updated by +env+ before <code>exec(2)</code> in the child process.
  *  If a pair in +env+ has nil as the value, the variable is deleted.
@@ -2779,44 +2947,46 @@
  *  The :in, :out, :err, a fixnum, an IO and an array key specifies a redirect.
  *  The redirection maps a file descriptor in the child process.
  *
- *  For example, stderr can be merged into stdout:
+ *  For example, stderr can be merged into stdout as follows:
  *
  *    pid = spawn(command, :err=>:out)
+ *    pid = spawn(command, 2=>1)
+ *    pid = spawn(command, STDERR=>:out)
  *    pid = spawn(command, STDERR=>STDOUT)
- *    pid = spawn(command, 2=>1)
  *
  *  The hash keys specifies a file descriptor
  *  in the child process started by <code>spawn</code>.
- *  :err, STDERR and 2 specifies the standard error stream.
+ *  :err, 2 and STDERR specifies the standard error stream (stderr).
  *
  *  The hash values specifies a file descriptor
  *  in the parent process which invokes <code>spawn</code>.
- *  :out, STDOUT and 1 specifies the standard output stream.
+ *  :out, 1 and STDOUT specifies the standard output stream (stdout).
  *
- *  The standard output in the child process is not specified.
+ *  In the above example,
+ *  the standard output in the child process is not specified.
  *  So it is inherited from the parent process.
  *
- *  The standard input stream can be specifed by :in, STDIN and 0.
+ *  The standard input stream (stdin) can be specifed by :in, 0 and STDIN.
  *  
  *  A filename can be specified as a hash value.
  *
- *    pid = spawn(command, STDIN=>"/dev/null") # read mode
- *    pid = spawn(command, STDOUT=>"/dev/null") # write mode
- *    pid = spawn(command, STDERR=>"log") # write mode
+ *    pid = spawn(command, :in=>"/dev/null") # read mode
+ *    pid = spawn(command, :out=>"/dev/null") # write mode
+ *    pid = spawn(command, :err=>"log") # write mode
  *    pid = spawn(command, 3=>"/dev/null") # read mode
  *
- *  For standard output and standard error,
+ *  For stdout and stderr,
  *  it is opened in write mode.
  *  Otherwise read mode is used.
  *
  *  For specifying flags and permission of file creation explicitly,
  *  an array is used instead.
  *
- *    pid = spawn(command, STDIN=>["file"]) # read mode is assumed
- *    pid = spawn(command, STDIN=>["file", "r"])
- *    pid = spawn(command, STDOUT=>["log", "w"]) # 0644 assumed
- *    pid = spawn(command, STDOUT=>["log", "w", 0600])
- *    pid = spawn(command, STDOUT=>["log", File::WRONLY|File::EXCL|File::CREAT, 0600])
+ *    pid = spawn(command, :in=>["file"]) # read mode is assumed
+ *    pid = spawn(command, :in=>["file", "r"])
+ *    pid = spawn(command, :out=>["log", "w"]) # 0644 assumed
+ *    pid = spawn(command, :out=>["log", "w", 0600])
+ *    pid = spawn(command, :out=>["log", File::WRONLY|File::EXCL|File::CREAT, 0600])
  *
  *  The array specifies a filename, flags and permission.
  *  The flags can be a string or an integer.
@@ -2827,9 +2997,28 @@
  *  If an array of IOs and integers are specified as a hash key,
  *  all the elemetns are redirected.
  *
- *    # standard output and standard error is redirected to log file.
- *    pid = spawn(command, [STDOUT, STDERR]=>["log", "w"])
+ *    # stdout and stderr is redirected to log file.
+ *    # The file "log" is opened just once.
+ *    pid = spawn(command, [:out, :err]=>["log", "w"])
  *
+ *  Another way to merge multiple file descriptors is [:child, fd].
+ *  [:child, fd] means the file descriptor in the child process.
+ *  This is different from fd.
+ *  For example, :err=>:out means redirecting child stderr to parent stdout.
+ *  But :err=>[:child, :out] means redirecting child stderr to child stdout.
+ *  They differs if stdout is redirected in the child process as follows.
+ *
+ *    # stdout and stderr is redirected to log file.
+ *    # The file "log" is opened just once.
+ *    pid = spawn(command, :out=>["log", "w"], :err=>[:child, :out])
+ *
+ *  [:child, :out] can be used to merge stderr into stdout in IO.popen.
+ *  In this case, IO.popen redirects stdout to a pipe in the child process
+ *  and [:child, :out] refers the redirected stdout.
+ *
+ *    io = IO.popen(["sh", "-c", "echo out; echo err >&2", :err=>[:child, :out]])
+ *    p io.read #=> "out\nerr\n"
+ *
  *  spawn closes all non-standard unspecified descriptors by default.
  *  The "standard" descriptors are 0, 1 and 2.
  *  This behavior is specified by :close_others option.
@@ -2845,7 +3034,7 @@
  *
  *    # similar to r = IO.popen(command)
  *    r, w = IO.pipe
- *    pid = spawn(command, STDOUT=>w)   # r, w is closed in the child process.
+ *    pid = spawn(command, :out=>w)   # r, w is closed in the child process.
  *    w.close
  *
  *  :close is specified as a hash value to close a fd individualy.
@@ -2853,13 +3042,23 @@
  *    f = open(foo)
  *    system(command, f=>:close)        # don't inherit f.
  *
+ *  If a file descriptor need to be inherited,
+ *  io=>io can be used.
+ *
+ *    # valgrind has --log-fd option for log destination.
+ *    # log_w=>log_w indicates log_w.fileno inherits to child process.
+ *    log_r, log_w = IO.pipe
+ *    pid = spawn("valgrind", "--log-fd=#{log_w.fileno}", "echo", "a", log_w=>log_w)
+ *    log_w.close
+ *    p log_r.read
+ *
  *  It is also possible to exchange file descriptors.
  *
- *    pid = spawn(command, STDOUT=>STDERR, STDERR=>STDOUT)
+ *    pid = spawn(command, :out=>:err, :err=>:out)
  *
  *  The hash keys specify file descriptors in the child process.
  *  The hash values specifies file descriptors in the parent process.
- *  So the above specifies exchanging STDOUT and STDERR.
+ *  So the above specifies exchanging stdout and stderr.
  *  Internally, +spawn+ uses an extra file descriptor to resolve such cyclic
  *  file descriptor mapping.
  *
Index: mvm/ext/bigdecimal/bigdecimal.c
===================================================================
--- mvm/ext/bigdecimal/bigdecimal.c	(revision 20561)
+++ mvm/ext/bigdecimal/bigdecimal.c	(revision 20562)
@@ -1012,7 +1012,9 @@
 
     if(VpIsNaN(a) || VpIsNaN(b)) goto NaN;
     if(VpIsInf(a) || VpIsInf(b)) goto NaN;
-    if(VpIsZero(b))              goto NaN;
+    if(VpIsZero(b)) {
+	rb_raise(rb_eZeroDivError, "divided by 0");
+    }
     if(VpIsZero(a)) {
        GUARD_OBJ(c,VpCreateRbObject(1, "0"));
        GUARD_OBJ(d,VpCreateRbObject(1, "0"));
@@ -1169,9 +1171,6 @@
        Real *mod;
        obj = BigDecimal_DoDivmod(self,b,&div,&mod);
        if(obj!=(VALUE)0) return obj;
-       if(VpIsNaN(div) && rb_equal(b, INT2FIX(0))) {
-	   rb_raise(rb_eZeroDivError, "divided by 0");
-       }
        return BigDecimal_to_i(ToValue(div));
     } else {    /* div in BigDecimal sense */
        U_LONG ix = (U_LONG)GetPositiveInt(n);
Index: mvm/ext/curses/curses.c
===================================================================
--- mvm/ext/curses/curses.c	(revision 20561)
+++ mvm/ext/curses/curses.c	(revision 20562)
@@ -416,7 +416,7 @@
     curses_stdscr();
     c = getch();
     if (c == EOF) return Qnil;
-    if (ISPRINT(c)) {
+    if (rb_isprint(c)) {
 	char ch = (char)c;
 
 	return rb_locale_str_new(&ch, 1);
@@ -1131,7 +1131,7 @@
     GetWINDOW(obj, winp);
     c = wgetch(winp->window);
     if (c == EOF) return Qnil;
-    if (ISPRINT(c)) {
+    if (rb_isprint(c)) {
 	char ch = (char)c;
 
 	return rb_locale_str_new(&ch, 1);
Index: mvm/ext/pty/pty.c
===================================================================
--- mvm/ext/pty/pty.c	(revision 20561)
+++ mvm/ext/pty/pty.c	(revision 20562)
@@ -438,7 +438,7 @@
     cPTY = rb_define_module("PTY");
     rb_define_module_function(cPTY,"getpty",pty_getpty,-1);
     rb_define_module_function(cPTY,"spawn",pty_getpty,-1);
-    rb_define_singleton_function(cPTY,"check",pty_check,-1);
+    rb_define_singleton_method(cPTY,"check",pty_check,-1);
 
     eChildExited = rb_define_class_under(cPTY,"ChildExited",rb_eRuntimeError);
     rb_define_method(eChildExited,"status",echild_status,0);
Index: mvm/ext/tk/tcltklib.c
===================================================================
--- mvm/ext/tk/tcltklib.c	(revision 20561)
+++ mvm/ext/tk/tcltklib.c	(revision 20562)
@@ -4,7 +4,7 @@
  *              Oct. 24, 1997   Y. Matsumoto
  */
 
-#define TCLTKLIB_RELEASE_DATE "2008-10-20"
+#define TCLTKLIB_RELEASE_DATE "2008-12-03"
 
 #include "ruby.h"
 
@@ -3090,22 +3090,20 @@
     /* get args */
     args = rb_ary_new2(argc - 2);
     for(i = 3; i < argc; i++) {
+        VALUE s;
 #if TCL_MAJOR_VERSION >= 8
         str = Tcl_GetStringFromObj(argv[i], &len);
+        s = rb_tainted_str_new(str, len);
+#else /* TCL_MAJOR_VERSION < 8 */
+        str = argv[i];
+        s = rb_tainted_str_new2(str);
+#endif
         DUMP2("arg:%s",str);
 #ifndef HAVE_STRUCT_RARRAY_LEN
-	rb_ary_push(args, rb_tainted_str_new(str, len));
+        rb_ary_push(args, s);
 #else
-        RARRAY(args)->as.heap.ptr[RARRAY(args)->as.heap.len++] = rb_tainted_str_new(str, len);
+        RARRAY(args)->ptr[RARRAY(args)->len++] = s;
 #endif
-#else /* TCL_MAJOR_VERSION < 8 */
-        DUMP2("arg:%s",argv[i]);
-#ifndef HAVE_STRUCT_RARRAY_LEN
-	rb_ary_push(args, rb_tainted_str_new2(argv[i]));
-#else
-        RARRAY(args)->as.heap.ptr[RARRAY(args)->as.heap.len++] = rb_tainted_str_new2(argv[i]);
-#endif
-#endif
     }
 
     if (old_gc == Qfalse) rb_gc_enable();
@@ -8295,7 +8293,7 @@
     DUMP2("back from handler (current thread:%lx)", current);
 
     /* get result & free allocated memory */
-    ret = RARRAY(result)->as.heap.ptr[0];
+    ret = RARRAY_PTR(result)[0];
 #if 0 /* use Tcl_EventuallyFree */
     Tcl_EventuallyFree((ClientData)alloc_done, TCL_DYNAMIC); /* XXXXXXXX */
 #else
Index: mvm/ext/tk/lib/tk.rb
===================================================================
--- mvm/ext/tk/lib/tk.rb	(revision 20561)
+++ mvm/ext/tk/lib/tk.rb	(revision 20562)
@@ -1109,7 +1109,7 @@
   include TkComm
   extend TkComm
 
-  WITH_RUBY_VM  = Object.const_defined?(:VM) && ::VM.class == Class
+  WITH_RUBY_VM  = Object.const_defined?(:RubyVM) && ::RubyVM.class == Class
   WITH_ENCODING = defined?(::Encoding.default_external) && true
   #WITH_ENCODING = Object.const_defined?(:Encoding) && ::Encoding.class == Class
   #if TclTkLib::WINDOWING_SYSTEM == 'aqua'
@@ -5529,7 +5529,7 @@
 #Tk.freeze
 
 module Tk
-  RELEASE_DATE = '2008-10-20'.freeze
+  RELEASE_DATE = '2008-12-04'.freeze
 
   autoload :AUTO_PATH,        'tk/variable'
   autoload :TCL_PACKAGE_PATH, 'tk/variable'
Index: mvm/ext/tk/lib/tk/menu.rb
===================================================================
--- mvm/ext/tk/lib/tk/menu.rb	(revision 20561)
+++ mvm/ext/tk/lib/tk/menu.rb	(revision 20562)
@@ -569,7 +569,7 @@
     keys = _symbolkey2str(keys)
 
     parent = nil
-    if args[0].kind_of?(TkWindow) || args[0] == nil
+    if !args.empty? && (args[0].kind_of?(TkWindow) || args[0] == nil)
       keys.delete('parent') # ignore
       parent = args.shift 
     else
@@ -577,7 +577,7 @@
     end
 
     @variable = nil
-    if args[0].kind_of?(TkVariable) || args[0] == nil
+    if !args.empty? && (args[0].kind_of?(TkVariable) || args[0] == nil)
       keys.delete('variable') # ignore
       @variable = args.shift 
     else
Index: mvm/ext/openssl/ossl_ssl.c
===================================================================
--- mvm/ext/openssl/ossl_ssl.c	(revision 20561)
+++ mvm/ext/openssl/ossl_ssl.c	(revision 20562)
@@ -12,6 +12,14 @@
  */
 #include "ossl.h"
 
+#define rb_sys_fail_path(path) rb_sys_fail(NIL_P(path) ? 0 : RSTRING_PTR(path))
+
+#if defined(HAVE_FCNTL_H) || defined(_WIN32)
+#include <fcntl.h>
+#elif defined(HAVE_SYS_FCNTL_H)
+#include <sys/fcntl.h>
+#endif
+
 #if defined(HAVE_UNISTD_H)
 #  include <unistd.h> /* for read(), and write() */
 #endif
@@ -1003,6 +1011,71 @@
 static VALUE
 ossl_ssl_read(int argc, VALUE *argv, VALUE self)
 {
+  SSL *ssl;
+  int ilen, nread = 0;
+  VALUE len, str;
+  rb_io_t *fptr;
+
+  rb_scan_args(argc, argv, "11", &len, &str);
+  ilen = NUM2INT(len);
+  if(NIL_P(str)) str = rb_str_new(0, ilen);
+  else{
+    StringValue(str);
+    rb_str_modify(str);
+    rb_str_resize(str, ilen);
+  }
+  if(ilen == 0) return str;
+
+  Data_Get_Struct(self, SSL, ssl);
+  GetOpenFile(ossl_ssl_get_io(self), fptr);
+  if (ssl) {
+    if(SSL_pending(ssl) <= 0)
+      rb_thread_wait_fd(FPTR_TO_FD(fptr));
+    for (;;){
+      nread = SSL_read(ssl, RSTRING_PTR(str), RSTRING_LEN(str));
+      switch(ssl_get_error(ssl, nread)){
+        case SSL_ERROR_NONE:
+          goto end;
+        case SSL_ERROR_ZERO_RETURN:
+          rb_eof_error();
+        case SSL_ERROR_WANT_WRITE:
+          rb_io_wait_writable(FPTR_TO_FD(fptr));
+          continue;
+        case SSL_ERROR_WANT_READ:
+          rb_io_wait_readable(FPTR_TO_FD(fptr));
+          continue;
+        case SSL_ERROR_SYSCALL:
+          if(ERR_peek_error() == 0 && nread == 0) rb_eof_error();
+          rb_sys_fail(0);
+        default:
+          ossl_raise(eSSLError, "SSL_read:");
+      }
+    }
+  }
+  else {
+    rb_warning("SSL session is not started yet.");
+    return rb_funcall(ossl_ssl_get_io(self), rb_intern("read_nonblock"), 2, len, str);
+  }
+
+end:
+  rb_str_set_len(str, nread);
+  OBJ_TAINT(str);
+
+  return str;
+}
+
+/*
+ * call-seq:
+ *    ssl.read_nonblock(length) => string
+ *    ssl.read_nonblock(length, buffer) => buffer
+ *
+ * === Parameters
+ * * +length+ is a positive integer.
+ * * +buffer+ is a string used to store the result.
+ */
+static VALUE
+ossl_ssl_read_nonblock(int argc, VALUE *argv, VALUE self)
+{
     SSL *ssl;
     int ilen, nread = 0;
     VALUE len, str;
@@ -1020,12 +1093,11 @@
 
     Data_Get_Struct(self, SSL, ssl);
     GetOpenFile(ossl_ssl_get_io(self), fptr);
+    rb_io_set_nonblock(fptr);
     if (ssl) {
-	if(SSL_pending(ssl) <= 0)
-	    rb_thread_wait_fd(FPTR_TO_FD(fptr));
 	for (;;){
 	    nread = SSL_read(ssl, RSTRING_PTR(str), RSTRING_LEN(str));
-	    switch(ssl_get_error(ssl, nread)){
+	    switch(SSL_get_error(ssl, nread)){
 	    case SSL_ERROR_NONE:
 		goto end;
 	    case SSL_ERROR_ZERO_RETURN:
@@ -1034,7 +1106,7 @@
                 rb_io_wait_writable(FPTR_TO_FD(fptr));
                 continue;
 	    case SSL_ERROR_WANT_READ:
-                rb_io_wait_readable(FPTR_TO_FD(fptr));
+	        rb_sys_fail_path(fptr->pathv);
 		continue;
 	    case SSL_ERROR_SYSCALL:
 		if(ERR_peek_error() == 0 && nread == 0) rb_eof_error();
@@ -1045,9 +1117,8 @@
         }
     }
     else {
-        ID id_sysread = rb_intern("sysread");
         rb_warning("SSL session is not started yet.");
-        return rb_funcall(ossl_ssl_get_io(self), id_sysread, 2, len, str);
+        return rb_funcall(ossl_ssl_get_io(self), rb_intern("sysread"), 2, len, str);
     }
 
   end:
@@ -1421,6 +1492,7 @@
     rb_define_method(cSSLSocket, "sysread",    ossl_ssl_read, -1);
     rb_define_method(cSSLSocket, "syswrite",   ossl_ssl_write, 1);
     rb_define_method(cSSLSocket, "sysclose",   ossl_ssl_close, 0);
+    rb_define_method(cSSLSocket, "read_nonblock",    ossl_ssl_read_nonblock, -1);
     rb_define_method(cSSLSocket, "cert",       ossl_ssl_get_cert, 0);
     rb_define_method(cSSLSocket, "peer_cert",  ossl_ssl_get_peer_cert, 0);
     rb_define_method(cSSLSocket, "peer_cert_chain", ossl_ssl_get_peer_cert_chain, 0);
Index: mvm/ext/socket/socket.c
===================================================================
--- mvm/ext/socket/socket.c	(revision 20561)
+++ mvm/ext/socket/socket.c	(revision 20562)
@@ -926,9 +926,8 @@
 #endif
 
 static struct addrinfo*
-sock_addrinfo(VALUE host, VALUE port, int socktype, int flags)
+sock_getaddrinfo(VALUE host, VALUE port, struct addrinfo *hints)
 {
-    struct addrinfo hints;
     struct addrinfo* res = NULL;
     char *hostp, *portp;
     int error;
@@ -937,15 +936,11 @@
     hostp = host_str(host, hbuf, sizeof(hbuf));
     portp = port_str(port, pbuf, sizeof(pbuf));
 
-    if (socktype == 0 && flags == 0 && str_isnumber(portp)) {
-       socktype = SOCK_DGRAM;
+    if (hints->ai_socktype == 0 && hints->ai_flags == 0 && str_isnumber(portp)) {
+       hints->ai_socktype = SOCK_DGRAM;
     }
 
-    MEMZERO(&hints, struct addrinfo, 1);
-    hints.ai_family = AF_UNSPEC;
-    hints.ai_socktype = socktype;
-    hints.ai_flags = flags;
-    error = getaddrinfo(hostp, portp, &hints, &res);
+    error = getaddrinfo(hostp, portp, hints, &res);
     if (error) {
 	if (hostp && hostp[strlen(hostp)-1] == '\n') {
 	    rb_raise(rb_eSocket, "newline at the end of hostname");
@@ -958,7 +953,7 @@
 	struct addrinfo *r;
 	r = res;
 	while (r) {
-	    if (! r->ai_socktype) r->ai_socktype = hints.ai_socktype;
+	    if (! r->ai_socktype) r->ai_socktype = hints->ai_socktype;
 	    if (! r->ai_protocol) {
 		if (r->ai_socktype == SOCK_DGRAM) {
 		    r->ai_protocol = IPPROTO_UDP;
@@ -974,6 +969,18 @@
     return res;
 }
 
+static struct addrinfo*
+sock_addrinfo(VALUE host, VALUE port, int socktype, int flags)
+{
+    struct addrinfo hints;
+
+    MEMZERO(&hints, struct addrinfo, 1);
+    hints.ai_family = AF_UNSPEC;
+    hints.ai_socktype = socktype;
+    hints.ai_flags = flags;
+    return sock_getaddrinfo(host, port, &hints);
+}
+
 static VALUE
 ipaddr(struct sockaddr *sockaddr, int norevlookup)
 {
@@ -3271,33 +3278,10 @@
 sock_s_getaddrinfo(int argc, VALUE *argv)
 {
     VALUE host, port, family, socktype, protocol, flags, ret;
-    char hbuf[1024], pbuf[1024];
-    char *hptr, *pptr, *ap;
+    char *ap;
     struct addrinfo hints, *res;
-    int error;
 
-    host = port = family = socktype = protocol = flags = Qnil;
     rb_scan_args(argc, argv, "24", &host, &port, &family, &socktype, &protocol, &flags);
-    if (NIL_P(host)) {
-	hptr = NULL;
-    }
-    else {
-	strncpy(hbuf, StringValuePtr(host), sizeof(hbuf));
-	hbuf[sizeof(hbuf) - 1] = '\0';
-	hptr = hbuf;
-    }
-    if (NIL_P(port)) {
-	pptr = NULL;
-    }
-    else if (FIXNUM_P(port)) {
-	snprintf(pbuf, sizeof(pbuf), "%ld", FIX2LONG(port));
-	pptr = pbuf;
-    }
-    else {
-	strncpy(pbuf, StringValuePtr(port), sizeof(pbuf));
-	pbuf[sizeof(pbuf) - 1] = '\0';
-	pptr = pbuf;
-    }
 
     MEMZERO(&hints, struct addrinfo, 1);
     if (NIL_P(family)) {
@@ -3326,10 +3310,7 @@
     if (!NIL_P(flags)) {
 	hints.ai_flags = NUM2INT(flags);
     }
-    error = getaddrinfo(hptr, pptr, &hints, &res);
-    if (error) {
-	raise_socket_error("getaddrinfo", error);
-    }
+    res = sock_getaddrinfo(host, port, &hints);
 
     ret = make_addrinfo(res);
     freeaddrinfo(res);
Index: mvm/ext/stringio/stringio.c
===================================================================
--- mvm/ext/stringio/stringio.c	(revision 20561)
+++ mvm/ext/stringio/stringio.c	(revision 20562)
@@ -749,7 +749,7 @@
 
 /*
  * call-seq:
- *   strio.readchar   -> fixnum
+ *   strio.readchar   -> string
  *
  * See IO#readchar.
  */
Index: mvm/man/rake.1
===================================================================
--- mvm/man/rake.1	(revision 0)
+++ mvm/man/rake.1	(revision 20562)
@@ -0,0 +1,169 @@
+.Dd November 30, 2008
+.Dt RAKE(1) "" "Ruby Programmers Reference Guide"
+.Os UNIX
+.Sh NAME
+.Nm rake
+.Nd Ruby Make
+.Sh SYNOPSIS
+.Nm
+.Op Fl -f Ar Rakefile
+.Op Fl -version
+.Op Fl CGNPgnqstv
+.Op Fl D Op Ar PATTERN
+.Op Fl E Ar CODE
+.Op Fl I Ar LIBDIR
+.Op Fl R Ar RAKELIBDIR
+.Op Fl T Op Ar PATTERN
+.Op Fl e Ar CODE
+.Op Fl p Ar CODE
+.Op Fl r Ar MODULE
+.Op Fl -rules
+.Op Ar variable Ns = Ns Ar value
+.Ar target ...
+.Sh DESCRIPTION
+.Nm Rake
+is a simple 
+.Xr ruby 1
+build program with capabilities similar to the regular 
+.Xr make 1
+command.
+
+.Nm Rake
+has the following features:
+.Bl -bullet
+.It
+Rakefiles (Rake's version of Makefiles) are completely defined in standard Ruby syntax. 
+No XML files to edit. No quirky Makefile syntax to worry about (is that a tab or a space?).
+.It
+Users can specify tasks with prerequisites.
+.It
+Rake supports rule patterns to sythesize implicit tasks.
+.It
+Flexible FileLists that act like arrays but know about manipulating file names and paths.
+.It
+A library of prepackaged tasks to make building rakefiles easier. 
+.El
+.Pp
+.Sh OPTIONS
+.Bl -tag -width "--execute-continue" -compact
+.Pp
+.It Fl -version
+Display the program version.
+.Pp
+.It Fl C
+.It Fl -classic-namespace
+Put Task and FileTask in the top level namespace
+.Pp
+.It Fl D Op Ar PATTERN
+.It Fl -describe Op Ar PATTERN
+Describe the tasks (matching optional 
+.Ar PATTERN Ns
+), then exit.
+.Pp
+.It Fl E Ar CODE
+.It Fl -execute-continue Ar CODE
+Execute some Ruby code, then continue with normal task processing.
+.Pp
+.It Fl G
+.It Fl -no-system
+.It Fl -nosystem
+Use standard project Rakefile search paths, ignore system wide rakefiles.
+.Pp
+.It Fl I Ar LIBDIR
+.It Fl -libdir Ar LIBDIR
+Include 
+.Ar LIBDIR
+in the search path for required modules.
+.Pp
+.It Fl N
+.It Fl -no-search
+.It Fl -nosearch
+Do not search parent directories for the Rakefile.
+.Pp
+.It Fl P
+.It Fl -prereqs
+Display the tasks and dependencies, then exit.
+.Pp
+.It Fl R Ar RAKELIBDIR
+.It Fl -rakelib Ar RAKELIBDIR
+.It Fl -rakelibdir Ar RAKELIBDIR
+Auto-import any .rake files in
+.Ar RAKELIBDIR .
+(default is 
+.Pa rakelib
+)
+.Pp
+.It Fl T Op Ar PATTERN
+.It Fl -tasks Op Ar PATTERN
+Display the tasks (matching optional
+.Ar PATTERN Ns
+) with descriptions, then exit.
+.Pp
+.It Fl e Ar CODE
+.It Fl -execute Ar CODE
+Execute some Ruby code and exit.
+.Pp
+.It Fl f Ar FILE
+.It Fl -rakefile Ar FILE
+Use FILE as the rakefile.
+.Pp
+.It Fl h
+.It Fl -help
+Prints a summary of options.
+.Pp
+.It Fl g
+.It Fl -system
+Using system wide (global) rakefiles (usually 
+.Pa ~/.rake/*.rake
+).
+.Pp
+.It Fl n
+.It Fl -dry-run
+Do a dry run without executing actions.
+.Pp
+.It Fl p Ar CODE
+.It Fl -execute-print Ar CODE
+Execute some Ruby code, print the result, then exit.
+.Pp
+.It Fl q
+.It Fl -quiet
+Do not log messages to standard output.
+.Pp
+.It Fl r Ar MODULE
+.It Fl -require Ar MODULE
+Require MODULE before executing rakefile.
+.Pp
+.It Fl s
+.It Fl -silent
+Like 
+.Fl -quiet ,
+but also suppresses the 'in directory' announcement.
+.Pp
+.It Fl t
+.It Fl -trace
+Turn on invoke/execute tracing, enable full backtrace.
+.Pp
+.It Fl v
+.It Fl -verbose
+Log message to standard output (default).
+.Pp
+.It Fl -rules
+Trace the rules resolution.
+.Pp
+.El
+.Pp
+.Sh SEE ALSO
+.Xr ruby 1
+.Xr make 1
+.Pp
+http://rake.rubyforge.org/
+.Sh REPORTING BUGS
+Bugs, features requests and other issues can be logged at 
+<\fBhttp://onestepback.org/redmine/projects/show/rake\fR>.
+.Pp
+You will need an account to before you can post issues. Register at <\fBhttp://onestepback.org/redmine/account/register\fR>.
+Or you can send an email to the author.
+.Sh AUTHOR
+.Nm Rake
+is written by 
+.An Jim Weirich Aq jim@w...

Property changes on: mvm/man/rake.1
___________________________________________________________________
Name: svn:eol-style
   + LF
Name: svn:keywords
   + Author Id Revision

Index: mvm/man/goruby.1
===================================================================
--- mvm/man/goruby.1	(revision 20561)
+++ mvm/man/goruby.1	(revision 20562)
@@ -13,7 +13,7 @@
 .Op Ar argument ...
 .Sh DESCRIPTION
 .Sy goruby
-is a kind of Ruby language processor, 
+is a kind of Ruby language processor
 which recognizes extremely shorten programs as bellow;
 .Bd -literal -offset indent
 rq"date";s De.td
Index: mvm/man/irb.1
===================================================================
--- mvm/man/irb.1	(revision 20561)
+++ mvm/man/irb.1	(revision 20562)
@@ -40,7 +40,7 @@
 .It Fl m
 Bc mode (load mathn, fraction or matrix are available)
 .Pp
-.It Fl -r Ar load-module
+.It Fl r Ar load-module
 Same as `ruby -r'
 .Pp
 .It Fl I Ar path
@@ -108,6 +108,24 @@
 .Pp
 .El
 .Pp
+.Sh EXAMPLES
+.Dl % irb
+.Dl irb(main):001:0> Ic 1 + 1
+.Dl 2
+.Dl irb(main):002:0> Ic def t(x)
+.Dl irb(main):003:1> Ic   x+1
+.Dl irb(main):004:1> Ic end
+.Dl => nil
+.Dl irb(main):005:0> Ic t(3)
+.Dl => 4
+.Dl irb(main):006:0> Ic if t(3) == 4
+.Dl irb(main):007:1> Ic p :ok
+.Dl irb(main):008:1> Ic end
+.Dl :ok
+.Dl => :ok
+.Dl irb(main):009:0> Ic quit
+.Dl % 
+.Pp
 .Sh SEE ALSO
 .Xr ruby 1 .
 .Pp
Index: mvm/.merged-trunk-revision
===================================================================
--- mvm/.merged-trunk-revision	(revision 20561)
+++ mvm/.merged-trunk-revision	(revision 20562)
@@ -1 +1 @@
-20375
+20561
Index: mvm/numeric.c
===================================================================
--- mvm/numeric.c	(revision 20561)
+++ mvm/numeric.c	(revision 20562)
@@ -670,6 +670,7 @@
 {
     double div, mod;
 
+    if (y == 0.0) rb_num_zerodiv();
 #ifdef HAVE_FMOD
     mod = fmod(x, y);
 #else
Index: mvm/cont.c
===================================================================
--- mvm/cont.c	(revision 20561)
+++ mvm/cont.c	(revision 20562)
@@ -25,6 +25,7 @@
 typedef struct rb_context_struct {
     enum context_type type;
     VALUE self;
+    int argc;
     VALUE value;
     VALUE *vm_stack;
 #ifdef CAPTURE_JUST_VALID_VM_STACK
@@ -60,8 +61,10 @@
 #define GetContPtr(obj, ptr)  \
   Data_Get_Struct(obj, rb_context_t, ptr)
 
-#define GetFiberPtr(obj, ptr)  \
-  Data_Get_Struct(obj, rb_fiber_t, ptr)
+#define GetFiberPtr(obj, ptr)  do {\
+  ptr = (rb_fiber_t*)DATA_PTR(obj);\
+  if (!ptr) rb_raise(rb_eFiberError, "uninitialized fiber");\
+} while(0)
 
 NOINLINE(static VALUE cont_capture(volatile int *stat));
 
@@ -552,6 +555,7 @@
 	}
     }
 
+    cont->argc = argc;
     cont->value = make_passing_arg(argc, argv);
 
     cont_restore_0(cont, &contval);
@@ -564,26 +568,33 @@
 
 #define FIBER_VM_STACK_SIZE (4 * 1024)
 
-static rb_fiber_t *
+static VALUE
 fiber_alloc(VALUE klass)
 {
-    rb_fiber_t *fib;
-    volatile VALUE fibval = Data_Make_Struct(klass, rb_fiber_t, fiber_mark, fiber_free, fib);
+    return Data_Wrap_Struct(klass, fiber_mark, fiber_free, 0);
+}
 
+static rb_fiber_t*
+fiber_t_alloc(VALUE fibval)
+{
+    rb_fiber_t *fib = ALLOC(rb_fiber_t);
+
+    memset(fib, 0, sizeof(rb_fiber_t));
     fib->cont.self = fibval;
     fib->cont.type = FIBER_CONTEXT;
     cont_init(&fib->cont);
     fib->prev = Qnil;
     fib->status = CREATED;
 
+    DATA_PTR(fibval) = fib;
+
     return fib;
 }
 
 static VALUE
-fiber_new(VALUE klass, VALUE proc)
+fiber_init(VALUE fibval, VALUE proc)
 {
-    rb_fiber_t *fib = fiber_alloc(klass);
-    VALUE fibval = fib->cont.self;
+    rb_fiber_t *fib = fiber_t_alloc(fibval);
     rb_context_t *cont = &fib->cont;
     rb_thread_t *th = &cont->saved_thread;
 
@@ -619,16 +630,16 @@
     return fibval;
 }
 
-VALUE
-rb_fiber_new(VALUE (*func)(ANYARGS), VALUE obj)
+static VALUE
+rb_fiber_init(VALUE fibval)
 {
-    return fiber_new(rb_cFiber, rb_proc_new(func, obj));
+    return fiber_init(fibval, rb_block_proc());
 }
 
-static VALUE
-rb_fiber_s_new(VALUE self)
+VALUE
+rb_fiber_new(VALUE (*func)(ANYARGS), VALUE obj)
 {
-    return fiber_new(self, rb_block_proc());
+    return fiber_init(fiber_alloc(rb_cFiber), rb_proc_new(func, obj));
 }
 
 static VALUE
@@ -672,7 +683,6 @@
     rb_fiber_t *fib;
     rb_context_t *cont;
     rb_proc_t *proc;
-    VALUE args;
     int state;
 
     GetFiberPtr(th->fiber, fib);
@@ -680,15 +690,18 @@
 
     TH_PUSH_TAG(th);
     if ((state = EXEC_TAG()) == 0) {
+	int argc;
+	VALUE *argv, args;
 	GetProcPtr(cont->saved_thread.first_proc, proc);
 	args = cont->value;
+	argv = (argc = cont->argc) > 1 ? RARRAY_PTR(args) : &args;
 	cont->value = Qnil;
 	th->errinfo = Qnil;
 	th->local_lfp = proc->block.lfp;
 	th->local_svar = Qnil;
 
 	fib->status = RUNNING;
-	cont->value = vm_invoke_proc(th, proc, proc->block.self, 1, &args, 0);
+	cont->value = vm_invoke_proc(th, proc, proc->block.self, argc, argv, 0);
     }
     TH_POP_TAG();
 
@@ -713,7 +726,7 @@
     rb_fiber_t *fib;
 
     /* no need to allocate vm stack */
-    fib = fiber_alloc(rb_cFiber);
+    fib = fiber_t_alloc(fiber_alloc(rb_cFiber));
     fib->cont.type = ROOT_FIBER_CONTEXT;
     fib->prev_fiber = fib->next_fiber = fib;
 
@@ -785,6 +798,7 @@
 	fib->prev = rb_fiber_current();
     }
 
+    cont->argc = argc;
     cont->value = make_passing_arg(argc, argv);
 
     if ((value = fiber_store(fib)) == Qundef) {
@@ -863,10 +877,10 @@
 InitVM_Cont(ruby_vm_t *vm)
 {
     rb_cFiber = rb_define_class("Fiber", rb_cObject);
-    rb_undef_alloc_func(rb_cFiber);
+    rb_define_alloc_func(rb_cFiber, fiber_alloc);
     rb_eFiberError = rb_define_class("FiberError", rb_eStandardError);
-    rb_define_singleton_method(rb_cFiber, "new", rb_fiber_s_new, 0);
     rb_define_singleton_method(rb_cFiber, "yield", rb_fiber_s_yield, -1);
+    rb_define_method(rb_cFiber, "initialize", rb_fiber_init, 0);
     rb_define_method(rb_cFiber, "resume", rb_fiber_m_resume, -1);
 }
 
Index: mvm/vm.c
===================================================================
--- mvm/vm.c	(revision 20561)
+++ mvm/vm.c	(revision 20562)
@@ -1726,7 +1726,6 @@
     return Qnil;
 }
 
-VALUE insns_name_array(void);
 
 /* debug functions */
 
@@ -1834,7 +1833,7 @@
 #endif
 
     /* ::VM::InsnNameArray */
-    rb_define_const(rb_cRubyVM, "INSTRUCTION_NAMES", insns_name_array());
+    rb_define_const(rb_cRubyVM, "INSTRUCTION_NAMES", ruby_insns_name_array());
 
     /* debug functions ::VM::SDR(), ::VM::NSDR() */
 #if VMDEBUG
Index: mvm/version.h
===================================================================
--- mvm/version.h	(revision 20561)
+++ mvm/version.h	(revision 20562)
@@ -1,15 +1,15 @@
-#define RUBY_VERSION "1.9.0"
-#define RUBY_RELEASE_DATE "2008-11-30"
-#define RUBY_VERSION_CODE 190
-#define RUBY_RELEASE_CODE 20081130
-#define RUBY_PATCHLEVEL 0
+#define RUBY_VERSION "1.9.1"
+#define RUBY_RELEASE_DATE "2008-12-06"
+#define RUBY_VERSION_CODE 191
+#define RUBY_RELEASE_CODE 20081206
+#define RUBY_PATCHLEVEL 5000
 
 #define RUBY_VERSION_MAJOR 1
 #define RUBY_VERSION_MINOR 9
-#define RUBY_VERSION_TEENY 0
+#define RUBY_VERSION_TEENY 1
 #define RUBY_RELEASE_YEAR 2008
-#define RUBY_RELEASE_MONTH 11
-#define RUBY_RELEASE_DAY 30
+#define RUBY_RELEASE_MONTH 12
+#define RUBY_RELEASE_DAY 6
 
 #ifdef RUBY_EXTERN
 RUBY_EXTERN const char ruby_version[];
Index: mvm/test/bigdecimal/test_bigdecimal.rb
===================================================================
--- mvm/test/bigdecimal/test_bigdecimal.rb	(revision 20561)
+++ mvm/test/bigdecimal/test_bigdecimal.rb	(revision 20562)
@@ -419,9 +419,7 @@
     assert_equal([0, 0], BigDecimal.new("0").divmod(2))
 
     BigDecimal.mode(BigDecimal::EXCEPTION_NaN, false)
-    a, b = BigDecimal.new("0").divmod(0)
-    assert_equal(true, a.nan?)
-    assert_equal(true, b.nan?)
+    assert_raise(ZeroDivisionError){BigDecimal.new("0").divmod(0)}
   end
 
   def test_add_bigdecimal
Index: mvm/test/ruby/test_fiber.rb
===================================================================
--- mvm/test/ruby/test_fiber.rb	(revision 20561)
+++ mvm/test/ruby/test_fiber.rb	(revision 20562)
@@ -14,6 +14,10 @@
     assert_equal([:a, :b], Fiber.new{|a, b| [a, b]}.resume(:a, :b))
   end
 
+  def test_argument
+    assert_equal(4, Fiber.new {|i=4| i}.resume)
+  end
+
   def test_term
     assert_equal(:ok, Fiber.new{:ok}.resume)
     assert_equal([:a, :b, :c, :d, :e],
Index: mvm/test/ruby/test_regexp.rb
===================================================================
--- mvm/test/ruby/test_regexp.rb	(revision 20561)
+++ mvm/test/ruby/test_regexp.rb	(revision 20562)
@@ -604,11 +604,13 @@
     check(/\Aa{0}+\z/, "", %w(a aa aab))
     check(/\Aa{1}+\z/, %w(a aa), ["", "aab"])
     check(/\Aa{1,2}b{1,2}\z/, %w(ab aab abb aabb), ["", "aaabb", "abbb"])
+    check(/(?!x){0,1}/, [ ['', 'ab'], ['', ''] ])
+    check(/c\z{0,1}/, [ ['c', 'abc'], ['c', 'cab']], ['abd'])
+    check(/\A{0,1}a/, [ ['a', 'abc'], ['a', '____abc']], ['bcd'])
     failcheck('.{100001}')
     failcheck('.{0,100001}')
     failcheck('.{1,0}')
     failcheck('{0}')
-    failcheck('(?!x){0,1}')
   end
 
   def test_parse_comment
Index: mvm/test/ruby/test_range.rb
===================================================================
--- mvm/test/ruby/test_range.rb	(revision 20561)
+++ mvm/test/ruby/test_range.rb	(revision 20562)
@@ -267,4 +267,13 @@
     def o.end; 0; end
     assert_equal([], [0, 1, 2][o])
   end
+
+  class CyclicRange < Range
+    def <=>(other); true; end
+  end
+  def test_cyclic_range_inspect
+    o = CyclicRange.allocate
+    o.instance_eval { initialize(o, 1) }
+    assert_equal("(... .. ...)..1", o.inspect)
+  end
 end
Index: mvm/test/ruby/test_proc.rb
===================================================================
--- mvm/test/ruby/test_proc.rb	(revision 20561)
+++ mvm/test/ruby/test_proc.rb	(revision 20562)
@@ -673,4 +673,47 @@
     }.call(1,2,3,4,5)
     assert_equal([1,2,[3],4,5], r, "[ruby-core:19485]")
   end
+
+  def test_parameters
+    assert_equal([], proc {}.parameters)
+    assert_equal([], proc {||}.parameters)
+    assert_equal([[:opt, :a, nil]], proc {|a|}.parameters)
+    assert_equal([[:opt, :a, nil], [:opt, :b, nil]], proc {|a, b|}.parameters)
+    assert_equal([[:opt, :a, :a], [:block, :b]], proc {|a=:a, &b|}.parameters)
+    assert_equal([[:opt, :a, nil], [:opt, :b, :b]], proc {|a, b=:b|}.parameters)
+    assert_equal([[:rest, :a]], proc {|*a|}.parameters)
+    assert_equal([[:opt, :a, nil], [:rest, :b], [:block, :c]], proc {|a, *b, &c|}.parameters)
+    assert_equal([[:opt, :a, nil], [:rest, :b], [:opt, :c, nil]], proc {|a, *b, c|}.parameters)
+    assert_equal([[:opt, :a, nil], [:rest, :b], [:opt, :c, nil], [:block, :d]], proc {|a, *b, c, &d|}.parameters)
+    assert_equal([[:opt, :a, nil], [:opt, :b, :b], [:rest, :c], [:opt, :d, nil], [:block, :e]], proc {|a, b=:b, *c, d, &e|}.parameters)
+    assert_equal([[:opt, nil, nil], [:block, :b]], proc {|(a), &b|}.parameters)
+    assert_equal([[:opt, :a, nil], [:opt, :b, nil], [:opt, :c, :c], [:opt, :d, :d], [:rest, :e], [:opt, :f, nil], [:opt, :g, nil], [:block, :h]], proc {|a,b,c=:c,d=:d,*e,f,g,&h|}.parameters) 
+  end
+
+  def pm0() end
+  def pm1(a) end
+  def pm2(a, b) end
+  def pmo1(a = :a, &b) end
+  def pmo2(a, b = :b) end
+  def pmo3(*a) end
+  def pmo4(a, *b, &c) end
+  def pmo5(a, *b, c) end
+  def pmo6(a, *b, c, &d) end
+  def pmo7(a, b = :b, *c, d, &e) end
+  def pma1((a), &b) end
+
+
+  def test_bound_parameters
+    assert_equal([], method(:pm0).to_proc.parameters)
+    assert_equal([[:req, :a]], method(:pm1).to_proc.parameters)
+    assert_equal([[:req, :a], [:req, :b]], method(:pm2).to_proc.parameters)
+    assert_equal([[:opt, :a, :a], [:block, :b]], method(:pmo1).to_proc.parameters)
+    assert_equal([[:req, :a], [:opt, :b, :b]], method(:pmo2).to_proc.parameters)
+    assert_equal([[:rest, :a]], method(:pmo3).to_proc.parameters)
+    assert_equal([[:req, :a], [:rest, :b], [:block, :c]], method(:pmo4).to_proc.parameters)
+    assert_equal([[:req, :a], [:rest, :b], [:req, :c]], method(:pmo5).to_proc.parameters)
+    assert_equal([[:req, :a], [:rest, :b], [:req, :c], [:block, :d]], method(:pmo6).to_proc.parameters)
+    assert_equal([[:req, :a], [:opt, :b, :b], [:rest, :c], [:req, :d], [:block, :e]], method(:pmo7).to_proc.parameters)
+    assert_equal([[:req], [:block, :b]], method(:pma1).to_proc.parameters)
+  end
 end
Index: mvm/test/ruby/test_float.rb
===================================================================
--- mvm/test/ruby/test_float.rb	(revision 20561)
+++ mvm/test/ruby/test_float.rb	(revision 20562)
@@ -172,9 +172,7 @@
     assert_raise(TypeError) { 2.0.divmod(nil) }
 
     inf = 1.0 / 0.0
-    a, b = inf.divmod(0)
-    assert(a.infinite?)
-    assert(b.nan?)
+    assert_raise(ZeroDivisionError) {inf.divmod(0)}
 
     a, b = (2.0**32).divmod(1.0)
     assert_equal(2**32, a)
Index: mvm/test/ruby/test_string.rb
===================================================================
--- mvm/test/ruby/test_string.rb	(revision 20561)
+++ mvm/test/ruby/test_string.rb	(revision 20562)
@@ -1714,4 +1714,47 @@
   def test_gsub_enumerator
     assert_normal_exit %q{"abc".gsub(/./).next}, "[ruby-dev:34828]"
   end
+
+  def test_clear_nonasciicompat
+    assert_equal("", "\u3042".encode("ISO-2022-JP").clear)
+  end
+
+  def test_try_convert
+    assert_equal(nil, String.try_convert(1))
+    assert_equal("foo", String.try_convert("foo"))
+  end
+
+  def test_substr_negative_begin
+    assert_equal("\u3042", ("\u3042" * 100)[-1])
+  end
+
+  def test_compare_different_encoding_string
+    s1 = "\xff".force_encoding("UTF-8")
+    s2 = "\xff".force_encoding("ISO-2022-JP")
+    #assert_equal([-1, 1], [s1 <=> s2, s2 <=> s1].sort)
+  end
+
+  def test_casecmp
+    assert_equal(1, "\u3042B".casecmp("\u3042a"))
+  end
+
+  def test_upcase2
+    assert_equal("\u3042AB", "\u3042aB".upcase)
+  end
+
+  def test_downcase2
+    assert_equal("\u3042ab", "\u3042aB".downcase)
+  end
+
+  def test_rstrip
+    assert_equal("\u3042", "\u3042   ".rstrip)
+    assert_raise(Encoding::CompatibilityError) { "\u3042".encode("ISO-2022-JP").rstrip }
+  end
+
+  def test_symbol_table_overflow
+    return
+    assert_in_out_err([], <<-INPUT, [], /symbol table overflow \(symbol [a-z]{8}\) \(RuntimeError\)/)
+      ("aaaaaaaa".."zzzzzzzz").each {|s| s.to_sym }
+    INPUT
+  end
 end
Index: mvm/test/ruby/test_method.rb
===================================================================
--- mvm/test/ruby/test_method.rb	(revision 20561)
+++ mvm/test/ruby/test_method.rb	(revision 20562)
@@ -20,6 +20,8 @@
   def mo4(a, *b, &c) end
   def mo5(a, *b, c) end
   def mo6(a, *b, c, &d) end
+  def mo7(a, b = nil, *c, d, &e) end
+  def ma1((a), &b) end
 
   class Base
     def foo() :base end
@@ -237,4 +239,72 @@
     assert !M.public_instance_methods.include?(:func), 'module methods are private by default'
     assert M.public_instance_methods.include?(:meth), 'normal methods are public by default'
   end
+
+  define_method(:pm0) {||}
+  define_method(:pm1) {|a|}
+  define_method(:pm2) {|a, b|}
+  define_method(:pmo1) {|a = nil, &b|}
+  define_method(:pmo2) {|a, b = nil|}
+  define_method(:pmo3) {|*a|}
+  define_method(:pmo4) {|a, *b, &c|}
+  define_method(:pmo5) {|a, *b, c|}
+  define_method(:pmo6) {|a, *b, c, &d|}
+  define_method(:pmo7) {|a, b = nil, *c, d, &e|}
+  define_method(:pma1) {|(a), &b|}
+
+  def test_bound_parameters
+    assert_equal([], method(:m0).parameters)
+    assert_equal([[:req, :a]], method(:m1).parameters)
+    assert_equal([[:req, :a], [:req, :b]], method(:m2).parameters)
+    assert_equal([[:opt, :a, nil], [:block, :b]], method(:mo1).parameters)
+    assert_equal([[:req, :a], [:opt, :b, nil]], method(:mo2).parameters)
+    assert_equal([[:rest, :a]], method(:mo3).parameters)
+    assert_equal([[:req, :a], [:rest, :b], [:block, :c]], method(:mo4).parameters)
+    assert_equal([[:req, :a], [:rest, :b], [:req, :c]], method(:mo5).parameters)
+    assert_equal([[:req, :a], [:rest, :b], [:req, :c], [:block, :d]], method(:mo6).parameters)
+    assert_equal([[:req, :a], [:opt, :b, nil], [:rest, :c], [:req, :d], [:block, :e]], method(:mo7).parameters)
+    assert_equal([[:req], [:block, :b]], method(:ma1).parameters)
+  end
+
+  def test_unbound_parameters
+    assert_equal([], self.class.instance_method(:m0).parameters)
+    assert_equal([[:req, :a]], self.class.instance_method(:m1).parameters)
+    assert_equal([[:req, :a], [:req, :b]], self.class.instance_method(:m2).parameters)
+    assert_equal([[:opt, :a, nil], [:block, :b]], self.class.instance_method(:mo1).parameters)
+    assert_equal([[:req, :a], [:opt, :b, nil]], self.class.instance_method(:mo2).parameters)
+    assert_equal([[:rest, :a]], self.class.instance_method(:mo3).parameters)
+    assert_equal([[:req, :a], [:rest, :b], [:block, :c]], self.class.instance_method(:mo4).parameters)
+    assert_equal([[:req, :a], [:rest, :b], [:req, :c]], self.class.instance_method(:mo5).parameters)
+    assert_equal([[:req, :a], [:rest, :b], [:req, :c], [:block, :d]], self.class.instance_method(:mo6).parameters)
+    assert_equal([[:req, :a], [:opt, :b, nil], [:rest, :c], [:req, :d], [:block, :e]], self.class.instance_method(:mo7).parameters)
+    assert_equal([[:req], [:block, :b]], self.class.instance_method(:ma1).parameters)
+  end
+
+  def test_bmethod_bound_parameters
+    assert_equal([], method(:pm0).parameters)
+    assert_equal([[:req, :a]], method(:pm1).parameters)
+    assert_equal([[:req, :a], [:req, :b]], method(:pm2).parameters)
+    assert_equal([[:opt, :a, nil], [:block, :b]], method(:pmo1).parameters)
+    assert_equal([[:req, :a], [:opt, :b, nil]], method(:pmo2).parameters)
+    assert_equal([[:rest, :a]], method(:pmo3).parameters)
+    assert_equal([[:req, :a], [:rest, :b], [:block, :c]], method(:pmo4).parameters)
+    assert_equal([[:req, :a], [:rest, :b], [:req, :c]], method(:pmo5).parameters)
+    assert_equal([[:req, :a], [:rest, :b], [:req, :c], [:block, :d]], method(:pmo6).parameters)
+    assert_equal([[:req, :a], [:opt, :b, nil], [:rest, :c], [:req, :d], [:block, :e]], method(:pmo7).parameters)
+    assert_equal([[:req], [:block, :b]], method(:pma1).parameters)
+  end
+
+  def test_bmethod_unbound_parameters
+    assert_equal([], self.class.instance_method(:pm0).parameters)
+    assert_equal([[:req, :a]], self.class.instance_method(:pm1).parameters)
+    assert_equal([[:req, :a], [:req, :b]], self.class.instance_method(:pm2).parameters)
+    assert_equal([[:opt, :a, nil], [:block, :b]], self.class.instance_method(:pmo1).parameters)
+    assert_equal([[:req, :a], [:opt, :b, nil]], self.class.instance_method(:pmo2).parameters)
+    assert_equal([[:rest, :a]], self.class.instance_method(:pmo3).parameters)
+    assert_equal([[:req, :a], [:rest, :b], [:block, :c]], self.class.instance_method(:pmo4).parameters)
+    assert_equal([[:req, :a], [:rest, :b], [:req, :c]], self.class.instance_method(:pmo5).parameters)
+    assert_equal([[:req, :a], [:rest, :b], [:req, :c], [:block, :d]], self.class.instance_method(:pmo6).parameters)
+    assert_equal([[:req, :a], [:opt, :b, nil], [:rest, :c], [:req, :d], [:block, :e]], self.class.instance_method(:pmo7).parameters)
+    assert_equal([[:req], [:block, :b]], self.class.instance_method(:pma1).parameters)
+  end
 end
Index: mvm/test/ruby/test_process.rb
===================================================================
--- mvm/test/ruby/test_process.rb	(revision 20561)
+++ mvm/test/ruby/test_process.rb	(revision 20562)
@@ -127,6 +127,7 @@
   end
 
   def test_execopts_pgroup
+    skip "system(:pgroup) is not supported" if /mswin|bccwin|mingw/ =~ RUBY_PLATFORM
     assert_nothing_raised { system(*TRUECOMMAND, :pgroup=>false) }
 
     io = IO.popen([RUBY, "-e", "print Process.getpgrp"])
@@ -306,6 +307,11 @@
       Process.wait Process.spawn(*ECHO["e"], STDOUT=>["out", File::WRONLY|File::CREAT|File::TRUNC, 0644],
                                  3=>STDOUT, 4=>STDOUT, 5=>STDOUT, 6=>STDOUT, 7=>STDOUT)
       assert_equal("e", File.read("out").chomp)
+      Process.wait Process.spawn(*ECHO["ee"], STDOUT=>["out", File::WRONLY|File::CREAT|File::TRUNC, 0644],
+                                 3=>0, 4=>:in, 5=>STDIN,
+                                 6=>1, 7=>:out, 8=>STDOUT,
+                                 9=>2, 10=>:err, 11=>STDERR)
+      assert_equal("ee", File.read("out").chomp)
       File.open("out", "w") {|f|
         h = {STDOUT=>f, f=>STDOUT}
         3.upto(30) {|i| h[i] = STDOUT if f.fileno != i }
@@ -410,6 +416,35 @@
     }
   end
 
+  def test_execopts_redirect_dup2_child
+    with_tmpchdir {|d|
+      Process.wait spawn(RUBY, "-e", "STDERR.print 'err'; STDOUT.print 'out'",
+                         STDOUT=>"out", STDERR=>[:child, STDOUT])
+      assert_equal("errout", File.read("out"))
+
+      Process.wait spawn(RUBY, "-e", "STDERR.print 'err'; STDOUT.print 'out'",
+                         STDERR=>"out", STDOUT=>[:child, STDERR])
+      assert_equal("errout", File.read("out"))
+
+      Process.wait spawn(RUBY, "-e", "STDERR.print 'err'; STDOUT.print 'out'",
+                         STDOUT=>"out", 
+                         STDERR=>[:child, 3],
+                         3=>[:child, 4], 
+                         4=>[:child, STDOUT]
+                        )
+      assert_equal("errout", File.read("out"))
+
+      IO.popen([RUBY, "-e", "STDERR.print 'err'; STDOUT.print 'out'", STDERR=>[:child, STDOUT]]) {|io|
+        assert_equal("errout", io.read)
+      }
+
+      assert_raise(ArgumentError) { Process.wait spawn(*TRUECOMMAND, STDOUT=>[:child, STDOUT]) }
+      assert_raise(ArgumentError) { Process.wait spawn(*TRUECOMMAND, 3=>[:child, 4], 4=>[:child, 3]) }
+      assert_raise(ArgumentError) { Process.wait spawn(*TRUECOMMAND, 3=>[:child, 4], 4=>[:child, 5], 5=>[:child, 3]) }
+      assert_raise(ArgumentError) { Process.wait spawn(*TRUECOMMAND, STDOUT=>[:child, 3]) }
+    }
+  end
+
   def test_execopts_exec
     with_tmpchdir {|d|
       write_file("s", 'exec "echo aaa", STDOUT=>"foo"')
@@ -461,6 +496,7 @@
   end
 
   def test_fd_inheritance
+    skip "inheritance of fd>=3 is not supported" if /mswin|bccwin|mingw/ =~ RUBY_PLATFORM
     with_pipe {|r, w|
       system(RUBY, '-e', 'IO.new(ARGV[0].to_i).puts(:ba)', w.fileno.to_s)
       w.close
@@ -564,14 +600,18 @@
   end
 
   def test_execopts_redirect_self
-    with_pipe {|r, w|
-      w << "haha\n"
-      w.close
-      r.close_on_exec = true
-      IO.popen([RUBY, "-e", "print IO.new(#{r.fileno}).read", r.fileno=>r.fileno, :close_others=>false]) {|io|
-        assert_equal("haha\n", io.read)
+    begin
+      with_pipe {|r, w|
+        w << "haha\n"
+        w.close
+        r.close_on_exec = true
+        IO.popen([RUBY, "-e", "print IO.new(#{r.fileno}).read", r.fileno=>r.fileno, :close_others=>false]) {|io|
+          assert_equal("haha\n", io.read)
+        }
       }
-    }
+    rescue NotImplementedError
+      skip "IO#close_on_exec= is not supported"
+    end
   end
 
   def test_execopts_duplex_io
Index: mvm/test/ruby/test_complex.rb
===================================================================
--- mvm/test/ruby/test_complex.rb	(revision 20561)
+++ mvm/test/ruby/test_complex.rb	(revision 20562)
@@ -27,7 +27,7 @@
       c2 = c - 1
       assert_instance_of(ComplexSub, c2)
 
-      c3 = c - c
+      c3 = c - c2
       assert_instance_of(ComplexSub, c3)
 
       s = Marshal.dump(c)
@@ -71,6 +71,12 @@
 
     h[Complex(0.0,0.0)] = 9.0
     assert_equal(5, h.size)
+
+    if (0.0/0).nan? && !((0.0/0).eql?(0.0/0))
+      h = {}
+      3.times{h[Complex(0.0/0)] = 1}
+      assert_equal(3, h.size)
+    end
   end
 
   def test_freeze
@@ -124,6 +130,13 @@
     assert_raise(ArgumentError){Complex(Object.new)}
     assert_raise(ArgumentError){Complex()}
     assert_raise(ArgumentError){Complex(1,2,3)}
+
+    if (0.0/0).nan?
+      assert_nothing_raised{Complex(0.0/0)}
+    end
+    if (1.0/0).infinite?
+      assert_nothing_raised{Complex(1.0/0)}
+    end
   end
 
   def test_attr
@@ -483,6 +496,13 @@
     assert_equal(true, Complex(2,1) != Complex(1))
     assert_equal(false, Complex(1) == nil)
     assert_equal(false, Complex(1) == '')
+
+    nan = 0.0 / 0
+    if nan.nan? && nan != nan
+      assert_equal(false, Complex(nan, 0) == Complex(nan, 0))
+      assert_equal(false, Complex(0, nan) == Complex(0, nan))
+      assert_equal(false, Complex(nan, nan) == Complex(nan, nan))
+    end
   end
 
   def test_unify
@@ -564,6 +584,16 @@
       assert_equal('1-2/3i', Complex(1,Rational(-2,3)).to_s)
       assert_equal('-1-2/3i', Complex(-1,Rational(-2,3)).to_s)
     end
+
+    nan = 0.0 / 0
+    inf = 1.0 / 0
+    if nan.nan?
+      assert_equal('NaN+NaN*i', Complex(nan,nan).to_s)
+    end
+    if inf.infinite?
+      assert_equal('Infinity+Infinity*i', Complex(inf,inf).to_s)
+      assert_equal('Infinity-Infinity*i', Complex(inf,-inf).to_s)
+    end
   end
 
   def test_inspect
@@ -812,6 +842,13 @@
 
     c = Complex(1,2).to_c
     assert_equal([1, 2], [c.real, c.imag])
+
+    if (0.0/0).nan?
+      assert_nothing_raised{(0.0/0).to_c}
+    end
+    if (1.0/0).infinite?
+      assert_nothing_raised{(1.0/0).to_c}
+    end
   end
 
   def test_supp
Index: mvm/test/ruby/test_rational.rb
===================================================================
--- mvm/test/ruby/test_rational.rb	(revision 20561)
+++ mvm/test/ruby/test_rational.rb	(revision 20562)
@@ -129,6 +129,13 @@
     assert_raise(ArgumentError){Rational(Object.new)}
     assert_raise(ArgumentError){Rational()}
     assert_raise(ArgumentError){Rational(1,2,3)}
+
+    if (0.0/0).nan?
+      assert_raise(FloatDomainError){Rational(0.0/0)}
+    end
+    if (1.0/0).infinite?
+      assert_raise(FloatDomainError){Rational(1.0/0)}
+    end
   end
 
   def test_attr
@@ -935,6 +942,13 @@
 	assert_raise(RangeError){Complex(1,2).to_r}
       end
     end
+
+    if (0.0/0).nan?
+      assert_raise(FloatDomainError){(0.0/0).to_r}
+    end
+    if (1.0/0).infinite?
+      assert_raise(FloatDomainError){(1.0/0).to_r}
+    end
   end
 
   def test_gcdlcm
Index: mvm/test/test_open3.rb
===================================================================
--- mvm/test/test_open3.rb	(revision 0)
+++ mvm/test/test_open3.rb	(revision 20562)
@@ -0,0 +1,234 @@
+require 'test/unit'
+require 'open3'
+require 'shellwords'
+require_relative 'ruby/envutil'
+
+class TestOpen3 < Test::Unit::TestCase
+  RUBY = EnvUtil.rubybin
+
+  def test_exit_status
+    Open3.popen3(RUBY, '-e', 'exit true') {|i,o,e,t|
+      assert_equal(true, t.value.success?)
+    }
+    Open3.popen3(RUBY, '-e', 'exit false') {|i,o,e,t|
+      assert_equal(false, t.value.success?)
+    }
+  end
+
+  def test_stdin
+    Open3.popen3(RUBY, '-e', 'exit STDIN.gets.chomp == "t"') {|i,o,e,t|
+      i.puts 't'
+      assert_equal(true, t.value.success?)
+    }
+    Open3.popen3(RUBY, '-e', 'exit STDIN.gets.chomp == "t"') {|i,o,e,t|
+      i.puts 'f'
+      assert_equal(false, t.value.success?)
+    }
+  end
+
+  def test_stdout
+    Open3.popen3(RUBY, '-e', 'STDOUT.print "foo"') {|i,o,e,t|
+      assert_equal("foo", o.read)
+    }
+  end
+
+  def test_stderr
+    Open3.popen3(RUBY, '-e', 'STDERR.print "bar"') {|i,o,e,t|
+      assert_equal("bar", e.read)
+    }
+  end
+
+  def test_block
+    r = Open3.popen3(RUBY, '-e', 'STDOUT.print STDIN.read') {|i,o,e,t|
+      i.print "baz"
+      i.close
+      assert_equal("baz", o.read)
+      "qux"
+    }
+    assert_equal("qux", r)
+  end
+
+  def test_noblock
+    i,o,e,t = Open3.popen3(RUBY, '-e', 'STDOUT.print STDIN.read')
+    i.print "baz"
+    i.close
+    assert_equal("baz", o.read)
+  ensure
+    i.close if !i.closed?
+    o.close if !o.closed?
+    e.close if !e.closed?
+  end
+
+  def test_commandline
+    commandline = Shellwords.join([RUBY, '-e', 'print "quux"'])
+    Open3.popen3(commandline) {|i,o,e,t|
+      assert_equal("quux", o.read)
+    }
+  end
+
+  def test_pid
+    Open3.popen3(RUBY, '-e', 'print $$') {|i,o,e,t|
+      pid = o.read.to_i
+      assert_equal(pid, t[:pid])
+      assert_equal(pid, t.pid)
+    }
+  end
+
+  def with_pipe
+    r, w = IO.pipe
+    yield r, w
+  ensure
+    r.close if !r.closed?
+    w.close if !w.closed?
+  end
+
+  def with_reopen(io, arg)
+    old = io.dup
+    io.reopen(arg)
+    yield old
+  ensure
+    io.reopen(old)
+    old.close if old && !old.closed?
+  end
+
+  def test_popen2
+    with_pipe {|r, w|
+      with_reopen(STDERR, w) {|old|
+        w.close
+        Open3.popen2(RUBY, '-e', 's=STDIN.read; STDOUT.print s+"o"; STDERR.print s+"e"') {|i,o,t|
+          assert_kind_of(Thread, t)
+          i.print "z"
+          i.close
+          STDERR.reopen(old)
+          assert_equal("zo", o.read)
+          assert_equal("ze", r.read)
+        }
+      }
+    }
+  end
+
+  def test_popen2e
+    with_pipe {|r, w|
+      with_reopen(STDERR, w) {|old|
+        w.close
+        Open3.popen2e(RUBY, '-e', 's=STDIN.read; STDOUT.print s+"o"; STDOUT.flush; STDERR.print s+"e"') {|i,o,t|
+          assert_kind_of(Thread, t)
+          i.print "y"
+          i.close
+          STDERR.reopen(old)
+          assert_equal("yoye", o.read)
+          assert_equal("", r.read)
+        }
+      }
+    }
+  end
+
+  def test_poutput3
+    o, e, s = Open3.poutput3(RUBY, '-e', 'i=STDIN.read; print i+"o"; STDOUT.flush; STDERR.print i+"e"', :stdin_data=>"i")
+    assert_equal("io", o)
+    assert_equal("ie", e)
+    assert(s.success?)
+  end
+
+  def test_poutput3_flip
+    o, e, s = Open3.poutput3(RUBY, '-e', 'STDOUT.sync=true; 1000.times { print "o"*1000; STDERR.print "e"*1000 }')
+    assert_equal("o"*1000000, o)
+    assert_equal("e"*1000000, e)
+    assert(s.success?)
+  end
+
+  def test_poutput2
+    o, s = Open3.poutput2(RUBY, '-e', 'i=STDIN.read; print i+"o"', :stdin_data=>"i")
+    assert_equal("io", o)
+    assert(s.success?)
+  end
+
+  def test_poutput2e
+    oe, s = Open3.poutput2e(RUBY, '-e', 'i=STDIN.read; print i+"o"; STDOUT.flush; STDERR.print i+"e"', :stdin_data=>"i")
+    assert_equal("ioie", oe)
+    assert(s.success?)
+  end
+
+  def test_pipeline_rw
+    Open3.pipeline_rw([RUBY, '-e', 'print STDIN.read + "1"'],
+                      [RUBY, '-e', 'print STDIN.read + "2"']) {|i,o,ts|
+      assert_kind_of(IO, i)
+      assert_kind_of(IO, o)
+      assert_kind_of(Array, ts)
+      assert_equal(2, ts.length)
+      ts.each {|t| assert_kind_of(Thread, t) }
+      i.print "0"
+      i.close
+      assert_equal("012", o.read)
+      ts.each {|t|
+        assert(t.value.success?)
+      }
+    }
+  end
+
+  def test_pipeline_r
+    Open3.pipeline_r([RUBY, '-e', 'print "1"'],
+                     [RUBY, '-e', 'print STDIN.read + "2"']) {|o,ts|
+      assert_kind_of(IO, o)
+      assert_kind_of(Array, ts)
+      assert_equal(2, ts.length)
+      ts.each {|t| assert_kind_of(Thread, t) }
+      assert_equal("12", o.read)
+      ts.each {|t|
+        assert(t.value.success?)
+      }
+    }
+  end
+
+  def test_pipeline_w
+    command = [RUBY, '-e', 's=STDIN.read; print s[1..-1]; exit s[0] == ?t']
+    str = 'ttftff'
+    Open3.pipeline_w(*[command]*str.length) {|i,ts|
+      assert_kind_of(IO, i)
+      assert_kind_of(Array, ts)
+      assert_equal(str.length, ts.length)
+      ts.each {|t| assert_kind_of(Thread, t) }
+      i.print str
+      i.close
+      ts.each_with_index {|t, i|
+        assert_equal(str[i] == ?t, t.value.success?)
+      }
+    }
+  end
+
+  def test_pipeline_start
+    command = [RUBY, '-e', 's=STDIN.read; print s[1..-1]; exit s[0] == ?t']
+    str = 'ttftff'
+    Open3.pipeline_start([RUBY, '-e', 'print ARGV[0]', str],
+                         *([command]*str.length)) {|ts|
+      assert_kind_of(Array, ts)
+      assert_equal(str.length+1, ts.length)
+      ts.each {|t| assert_kind_of(Thread, t) }
+      ts.each_with_index {|t, i|
+        if i == 0
+          assert(t.value.success?)
+        else
+          assert_equal(str[i-1] == ?t, t.value.success?)
+        end
+      }
+    }
+  end
+
+  def test_pipeline
+    command = [RUBY, '-e', 's=STDIN.read; print s[1..-1]; exit s[0] == ?t']
+    str = 'ttftff'
+    ss = Open3.pipeline([RUBY, '-e', 'print ARGV[0]', str],
+                        *([command]*str.length))
+    assert_kind_of(Array, ss)
+    assert_equal(str.length+1, ss.length)
+    ss.each {|s| assert_kind_of(Process::Status, s) }
+    ss.each_with_index {|s, i|
+      if i == 0
+        assert(s.success?)
+      else
+        assert_equal(str[i-1] == ?t, s.success?)
+      end
+    }
+  end
+
+end

Property changes on: mvm/test/test_open3.rb
___________________________________________________________________
Name: svn:eol-style
   + LF
Name: svn:keywords
   + Author Id Revision

Index: mvm/test/cgi/test_cgi_session.rb
===================================================================
--- mvm/test/cgi/test_cgi_session.rb	(revision 20561)
+++ mvm/test/cgi/test_cgi_session.rb	(revision 20562)
@@ -7,7 +7,7 @@
 
 class CGISessionTest < Test::Unit::TestCase
   def setup
-    @session_dir = Dir.mktmpdir('__test_dir__')+'/session_dir/'
+    @session_dir = Dir.tmpdir+'/__test_dir__/session_dir/'
     FileUtils.mkdir_p @session_dir
   end
 
Index: mvm/test/openssl/test_ssl.rb
===================================================================
--- mvm/test/openssl/test_ssl.rb	(revision 20561)
+++ mvm/test/openssl/test_ssl.rb	(revision 20562)
@@ -166,6 +166,21 @@
     assert_equal(ctx.setup, nil)
   end
 
+  def test_ssl_read_nonblock
+    start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true) { |server, port|
+      sock = TCPSocket.new("127.0.0.1", port)
+      ssl = OpenSSL::SSL::SSLSocket.new(sock)
+      ssl.sync_close = true
+      ssl.connect
+      assert_raise(Errno::EAGAIN, Errno::EWOULDBLOCK) { ssl.read_nonblock(100) }
+      ssl.write("abc\n")
+      IO.select [ssl]
+      assert_equal('a', ssl.read_nonblock(1))
+      assert_equal("bc\n", ssl.read_nonblock(100))
+      assert_raise(Errno::EAGAIN, Errno::EWOULDBLOCK) { ssl.read_nonblock(100) }
+    }
+  end
+
   def test_connect_and_close
     start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true){|server, port|
       sock = TCPSocket.new("127.0.0.1", port)
Index: mvm/test/socket/test_tcp.rb
===================================================================
--- mvm/test/socket/test_tcp.rb	(revision 20561)
+++ mvm/test/socket/test_tcp.rb	(revision 20562)
@@ -7,7 +7,6 @@
 
 class TestTCPSocket < Test::Unit::TestCase
   def test_recvfrom
-assert false, "TODO: doesn't work on mswin32/64" if /mswin/ =~ RUBY_PLATFORM
     svr = TCPServer.new("localhost", 0)
     th = Thread.new {
       c = svr.accept
@@ -15,11 +14,11 @@
       c.close
     }
     addr = svr.addr
-    sock = TCPSocket.open(addr[2], addr[1])
+    sock = TCPSocket.open(addr[3], addr[1])
     assert_equal(["foo", nil], sock.recvfrom(0x10000))
   ensure
-    th.kill
-    th.join
+    th.kill if th
+    th.join if th
   end
 
   def test_encoding
@@ -30,14 +29,14 @@
       c.close
     }
     addr = svr.addr
-    sock = TCPSocket.open(addr[2], addr[1])
+    sock = TCPSocket.open(addr[3], addr[1])
     assert_equal(true, sock.binmode?)
     s = sock.gets
     assert_equal("foo\r\n", s)
     assert_equal(Encoding.find("ASCII-8BIT"), s.encoding)
   ensure
-    th.kill
-    th.join
+    th.kill if th
+    th.join if th
     sock.close if sock
   end
 end if defined?(TCPSocket)
Index: mvm/rational.c
===================================================================
--- mvm/rational.c	(revision 20561)
+++ mvm/rational.c	(revision 20562)
@@ -25,8 +25,8 @@
 #define TWO INT2FIX(2)
 
 static ID id_abs, id_cmp, id_convert, id_equal_p, id_expt, id_floor,
-    id_format, id_hash, id_idiv, id_inspect, id_integer_p, id_negate,
-    id_to_f, id_to_i, id_to_s, id_truncate;
+    id_hash, id_idiv, id_inspect, id_integer_p, id_negate, id_to_f,
+    id_to_i, id_to_s, id_truncate;
 
 #define f_boolcast(x) ((x) ? Qtrue : Qfalse)
 
@@ -1109,19 +1109,34 @@
 }
 
 static VALUE
-nurat_to_s(VALUE self)
+nurat_format(VALUE self, VALUE (*func)(VALUE))
 {
+    VALUE s;
     get_dat1(self);
-    return rb_funcall(rb_mKernel, id_format, 3,
-		      rb_str_new2("%d/%d"), dat->num, dat->den);
+
+    s = (*func)(dat->num);
+    rb_str_cat2(s, "/");
+    rb_str_concat(s, (*func)(dat->den));
+
+    return s;
 }
 
 static VALUE
+nurat_to_s(VALUE self)
+{
+    return nurat_format(self, f_to_s);
+}
+
+static VALUE
 nurat_inspect(VALUE self)
 {
-    get_dat1(self);
-    return rb_funcall(rb_mKernel, id_format, 3,
-		      rb_str_new2("(%d/%d)"), dat->num, dat->den);
+    VALUE s;
+
+    s = rb_str_new2("(");
+    rb_str_concat(s, nurat_format(self, f_inspect));
+    rb_str_cat2(s, ")");
+
+    return s;
 }
 
 static VALUE
@@ -1488,7 +1503,6 @@
     id_equal_p = rb_intern("==");
     id_expt = rb_intern("**");
     id_floor = rb_intern("floor");
-    id_format = rb_intern("format");
     id_hash = rb_intern("hash");
     id_idiv = rb_intern("div");
     id_inspect = rb_intern("inspect");
Index: mvm/signal.c
===================================================================
--- mvm/signal.c	(revision 20561)
+++ mvm/signal.c	(revision 20562)
@@ -16,6 +16,7 @@
 #include "eval_intern.h"
 #include <signal.h>
 #include <stdio.h>
+#include <errno.h>
 
 #ifdef _WIN32
 typedef LONG rb_atomic_t;
@@ -447,8 +448,6 @@
     if (sigaltstack(&newSS, &oldSS) < 0) 
 	rb_bug("register_sigaltstack. error\n");
 }
-#else
-#define register_sigaltstack() ((void)0)
 #endif
 
 static void
@@ -477,8 +476,11 @@
     if (altstack)
 	sigact.sa_flags |= SA_ONSTACK;
 #endif
-    if (sigaction(signum, &sigact, old) < 0)
-        rb_bug("sigaction error.\n");
+    if (sigaction(signum, &sigact, old) < 0) {
+	if (errno != 0 && errno != EINVAL) {
+	    rb_bug("sigaction error.\n");
+	}
+    }
 }
 
 static sighandler_t
@@ -739,7 +741,9 @@
 #ifdef SIGSEGV
       case SIGSEGV:
         func = (sighandler_t)sigsegv;
+# ifdef USE_SIGALTSTACK
         register_sigaltstack();
+# endif
         break;
 #endif
 #ifdef SIGPIPE
@@ -1134,8 +1138,10 @@
 #endif
     }
 #ifdef SIGSEGV
+# ifdef USE_SIGALTSTACK
     register_sigaltstack();
     ruby_sigaction(SIGSEGV, sigsegv, Qtrue, NULL);
+# endif
 #endif
 #ifdef SIGPIPE
     install_sighandler(SIGPIPE, sigpipe);

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]