Unsupported: th_call0 in 1.9

e$B5WJ]$G$9!#e(B

ruby 1.9 e$B$G0J2<$N>r7o$N$H$-!"e(B[BUG] unsupported: th_call0
e$B$H$J$j$^$7$?!#e(B

  1. private e$B$J%a%=%C%I$r%5%V%/%i%9$Ge(B public e$B$K$9$k!#e(B
  2. e$B3HD%%i%$%V%i%j$+$i%5%V%/%i%9$Ge(B public e$B$K$7$?%a%=%C%I$re(B
    rb_funcall
    e$B$G8F$S=P$9!#e(B

DateTime#hour
e$B$,$3$N$h$&$J%a%=%C%I$G!"3HD%%i%$%V%i%j$+$i8F$S=P$=$&$He(B
e$B$7$?$i%(%i!<$K$J$j$^$7$?!#e(Bruby 1.8 e$B$G$OLdBj$J$/;H$($^$7$?!#e(B

e$B0J2<!":F8=J}K!e(B

= e$B%=!<%9#3$De(B(extconf.rb, mytest.c, mytest.rb)

extconf.rb:
require ‘mkmf’
create_makefile(‘mytest’)

mytest.c:
/*

  • class MyTest
  • def self.run(arg)
  • arg.run
    
  • end
  • end
    */
    #include <ruby.h>

static VALUE mytest_run(VALUE klass, VALUE arg)
{
return rb_funcall(arg, rb_intern(“run”), 0);
}

void Init_mytest()
{
VALUE cMyTest = rb_define_class(“MyTest”, rb_cObject);
rb_define_singleton_method(cMyTest, “run”, mytest_run, 1);
}

mytest.rb:
require ‘./mytest.so’

class A
def run
‘OK’
end
private :run
end

class B < A
public :run
end

puts MyTest.run(B.new)

= e$B3HD%%i%$%V%i%je(B mytest.so e$B$r:n@.$7$Fe(B mytest.rb e$B$r<B9Te(B

ruby extconf.rb
make
ruby mytest.rb

= e$B<B9T7k2Le(B

– stack frame ------------
0000 (0xb7caa008): 00000004
0001 (0xb7caa00c): 00000005
0002 (0xb7caa010): 00000004
0003 (0xb7caa014): 00000001
0004 (0xb7caa018): 00000004
0005 (0xb7caa01c): b7d74b70
0006 (0xb7caa020): b7d748f0
0007 (0xb7caa024): 00000004
0008 (0xb7caa028): 00000001 <- lfp <- dfp
– control frame ----------
c:0004 p:---- s:0009 b:0009 l:000008 d:000008 CFUNC :run
c:0003 p:0057 s:0005 b:0004 l:000003 d:000003 TOP mytest.rb:14
c:0002 p:---- s:0002 b:0002 l:000001 d:000001 FINISH
c:0001 p:---- s:0000 b:-001 l:000000 d:000000 ------

DBG> : “mytest.rb:14:in `’”
– backtrace of native function call (Use addr2line) –
0x80d83da
0x80ef150
0x80d6fb2
0x805947f
0x8059936
0xb7e2f6b5
0x80d429e
0x80d666d
0x80d69b8
0x8058fdb
0x8059016
0x805c670
0x80567af
0xb7e4aea8
0x80566e1

[BUG] unsupported: th_call0
ruby 1.9.0 (2007-02-21) [i686-linux]

e$B%"%!<%H$7$^$7$?e(B

e$B$J$+$@$G$9!#e(B

At Wed, 21 Feb 2007 22:33:56 +0900,
KUBO Takehiro wrote in [ruby-dev:30396]:

ruby 1.9 e$B$G0J2<$N>r7o$N$H$-!"e(B[BUG] unsupported: th_call0 e$B$H$J$j$^$7$?!#e(B

  1. private e$B$J%a%=%C%I$r%5%V%/%i%9$Ge(B public e$B$K$9$k!#e(B
  2. e$B3HD%%i%$%V%i%j$+$i%5%V%/%i%9$Ge(B public e$B$K$7$?%a%=%C%I$re(B rb_funcall
    e$B$G8F$S=P$9!#e(B

e$B$3$l$G$I$&$G$7$g$&$+!#e(B

Index: eval.c

— eval.c (revision 11883)
+++ eval.c (working copy)
@@ -1550,6 +1550,6 @@ rb_method_missing(int argc, const VALUE
}

-static VALUE
-method_missing(VALUE obj, ID id, int argc, const VALUE *argv, int
call_status)
+VALUE
+rb_call_method_missing(VALUE obj, ID id, int argc, const VALUE *argv,
int call_status)
{
VALUE *nargv;
@@ -1588,6 +1588,6 @@ rb_call(VALUE klass, VALUE recv, ID mid,
if (ent->mid == mid && ent->klass == klass) {
if (!ent->method)

  •  return method_missing(recv, mid, argc, argv,
    
  •      scope == 2 ? NOEX_VCALL : 0);
    
  •  return rb_call_method_missing(recv, mid, argc, argv,
    
  •        scope == 2 ? NOEX_VCALL : 0);
    
    id = ent->mid0;
    noex = ent->method->nd_noex;
    @@ -1602,13 +1602,13 @@ rb_call(VALUE klass, VALUE recv, ID mid,
    else {
    if (scope == 3) {
  •  return method_missing(recv, mid, argc, argv, NOEX_SUPER);
    
  •  return rb_call_method_missing(recv, mid, argc, argv, NOEX_SUPER);
    
    }
  • return method_missing(recv, mid, argc, argv,
  •        scope == 2 ? NOEX_VCALL : 0);
    
  • return rb_call_method_missing(recv, mid, argc, argv,
  •          scope == 2 ? NOEX_VCALL : 0);
    
    }
    if (mid != missing) {
    /* receiver specified form for private method */
    if (((noex & NOEX_MASK) & NOEX_PRIVATE) && scope == 0) {
  •  return method_missing(recv, mid, argc, argv, NOEX_PRIVATE);
    
  •  return rb_call_method_missing(recv, mid, argc, argv, 
    

NOEX_PRIVATE);
}

@@ -1623,5 +1623,5 @@ rb_call(VALUE klass, VALUE recv, ID mid,
if (!rb_obj_is_kind_of(rb_frame_self(),
rb_class_real(defined_class))) {

  • return method_missing(recv, mid, argc, argv, NOEX_PROTECTED);
  • return rb_call_method_missing(recv, mid, argc, argv,
    NOEX_PROTECTED);
    }
    }
    Index: intern.h
    ===================================================================
    — intern.h (revision 11883)
    +++ intern.h (working copy)
    @@ -250,4 +250,5 @@ VALUE rb_binding_new(void);
    VALUE rb_obj_method(VALUE, VALUE);
    VALUE rb_method_call(int, VALUE*, VALUE);
    +VALUE rb_call_method_missing(VALUE, ID, int, const VALUE *, int);
    int rb_mod_method_arity(VALUE, ID);
    int rb_obj_method_arity(VALUE, ID);
    Index: vm.c
    ===================================================================
    — vm.c (revision 11883)
    +++ vm.c (working copy)
    @@ -502,4 +502,6 @@ th_invoke_bmethod(rb_thread_t *th, ID id
    }

+static VALUE th_call_super(rb_thread_t *, int, const VALUE *);
+
VALUE
th_call0(rb_thread_t *th, VALUE klass, VALUE recv,
@@ -521,63 +523,67 @@ th_call0(rb_thread_t *th, VALUE klass, V
switch (nd_type(body)) {
case RUBY_VM_METHOD_NODE:{

  • rb_control_frame_t *reg_cfp;
  • int i;
  • const int flag = 0;
  • th_set_finish_env(th);
  • reg_cfp = th->cfp;
  • for (i = 0; i < argc; i++) {
  •    *reg_cfp->sp++ = argv[i];
    
  • }
  • macro_eval_invoke_func(body->nd_body, recv, klass, blockptr,
  •     argc);
    
  • val = th_eval_body(th);
  • break;
  • rb_control_frame_t *reg_cfp;
  • int i;
  • const int flag = 0;
  • th_set_finish_env(th);
  • reg_cfp = th->cfp;
  • for (i = 0; i < argc; i++) {
  •  *reg_cfp->sp++ = argv[i];
    
  • }
  • macro_eval_invoke_func(body->nd_body, recv, klass, blockptr,
  •         argc);
    
  • val = th_eval_body(th);
  • break;
    }
  •  case NODE_CFUNC: {
    
  • rb_control_frame_t *reg_cfp = th->cfp;
  • rb_control_frame_t *cfp =
  •  case NODE_CFUNC:{
    
  • rb_control_frame_t *reg_cfp = th->cfp;
  • rb_control_frame_t *cfp =
    push_frame(th, 0, FRAME_MAGIC_CFUNC,
    recv, (VALUE)blockptr, 0, reg_cfp->sp, 0, 1);
  • cfp->callee_id = oid;
  • cfp->method_id = id;
  • cfp->method_klass = klass;
  • val = call_cfunc(body->nd_cfnc, recv, body->nd_argc, argc, argv);
  • if (reg_cfp != th->cfp + 1) {
  •    SDR2(reg_cfp);
    
  •    SDR2(th->cfp-5);
    
  •    rb_bug("cfp consistency error - call0");
    
  •    th->cfp = reg_cfp;
    
  • }
  • pop_frame(th);
  • cfp->callee_id = oid;
  • cfp->method_id = id;
  • cfp->method_klass = klass;
  • val = call_cfunc(body->nd_cfnc, recv, body->nd_argc, argc, argv);
  • if (reg_cfp != th->cfp + 1) {
  •  SDR2(reg_cfp);
    
  •  SDR2(th->cfp-5);
    
  •  rb_bug("cfp consistency error - call0");
    
  •  th->cfp = reg_cfp;
    
  • }
  • pop_frame(th);
  • break;
  • break;
    }
    case NODE_ATTRSET:{
  • if (argc != 1) {
  •    rb_raise(rb_eArgError, "wrong number of arguments (%d for 1)",
    
  •       argc);
    
  • }
  • val = rb_ivar_set(recv, body->nd_vid, argv[0]);
  • break;
  • if (argc != 1) {
  •  rb_raise(rb_eArgError, "wrong number of arguments (%d for 1)",
    
  •     argc);
    
  • }
  • val = rb_ivar_set(recv, body->nd_vid, argv[0]);
  • break;
  •  }
    
  •  case NODE_IVAR:{
    
  • if (argc != 0) {
  •  rb_raise(rb_eArgError, "wrong number of arguments (%d for 0)",
    
  •     argc);
    
  • }
  • val = rb_attr_get(recv, body->nd_vid);
  • break;
    }
  •  case NODE_IVAR: {
    
  • if (argc != 0) {
  •    rb_raise(rb_eArgError, "wrong number of arguments (%d for 0)",
    
  •       argc);
    
  • }
  • val = rb_attr_get(recv, body->nd_vid);
  • break;
  •  case NODE_ZSUPER:{
    
  • val = th_call_super(th, argc, argv);
  • break;
    }
    case NODE_BMETHOD:{
  • val = th_invoke_bmethod(th, id, body->nd_cval,
  •      recv, klass, argc, (VALUE *)argv);
    
  • break;
  • val = th_invoke_bmethod(th, id, body->nd_cval,
  •    recv, klass, argc, (VALUE *)argv);
    
  • break;
    }
    default:
  • rb_bug(“unsupported: th_call0”);
  • rb_bug(“unsupported: th_call0(%s)”, ruby_node_name(nd_type(body)));
    }
    RUBY_VM_CHECK_INTS();
    @@ -614,5 +620,5 @@ th_call_super(rb_thread_t *th, int argc,
    rb_control_frame_t *cfp = th->cfp;
  • if (!th->cfp->iseq) {
  • if (!cfp->iseq) {
    klass = cfp->method_klass;
    klass = RCLASS(klass)->super;
    @@ -634,4 +640,5 @@ th_call_super(rb_thread_t *th, int argc,
    }
    else {
  • rb_call_method_missing(recv, id, argc, (VALUE *)argv, NOEX_SUPER);
    dp(recv);
    dp(klass);

e$B5WJ]$G$9!#e(B

KUBO Takehiro wrote in [ruby-dev:30396]:

ruby 1.9 e$B$G0J2<$N>r7o$N$H$-!"e(B[BUG] unsupported: th_call0 e$B$H$J$j$^$7$?!#e(B

  1. private e$B$J%a%=%C%I$r%5%V%/%i%9$Ge(B public e$B$K$9$k!#e(B
  2. e$B3HD%%i%$%V%i%j$+$i%5%V%/%i%9$Ge(B public e$B$K$7$?%a%=%C%I$re(B rb_funcall
    e$B$G8F$S=P$9!#e(B

8e$B%v7nA0$N%a!<%k$G$9$,!"$3$N7o!"$:$C$H:$$C$F$$$?$N$Ge(B proc.c
e$B$Ne(B mnew()
e$B$r;29M$K%Q%C%A$r:n$j$^$7$?!#e(B
[ruby-dev:30396]e$B$N;n83%W%m%0%i%`$OF0$/$he(B
e$B$&$K$J$j$^$7$?!#e(B

scope e$B$N07$$$NItJ,$,<+?.$J$$$N$G$9$,!“e(BNODE_ZSUPER
e$B$N$H$-$O!”?Fe(B
e$B%/%i%9$N%a%=%C%I$Ne(B scope e$B$G$O$J$/!“e(BNODE_ZSUPER e$B<+?H$Ne(B
scope e$B$Ge(B
e$B$b$C$F%A%’%C%/$7$?$[$&$,NI$$$N$G$O$H;W$$!”:G=i$K8+IU$+$C$?%a%=%C%Ie(B
e$B$Ne(B noex e$B$r;HMQ$9$k$h$&$K$7$^$7$?!#e(B

e$B0J2<!"%Q%C%A$G$9!#e(B

— eval.c (revision 13745)
+++ eval.c (working copy)
@@ -1358,6 +1358,7 @@
rb_call(VALUE klass, VALUE recv, ID mid, int argc, const VALUE *argv,
int scope)
{
NODE *body, *method;

  • int noex_is_set = 0;
    int noex;
    ID id = mid;
    struct cache_entry *ent;
    @@ -1368,6 +1369,7 @@
    “method `%s’ called on terminated object (%p)”,
    rb_id2name(mid), (void *)recv);
    }
  • again:
    /* is it in the method cache? */
    ent = cache + EXPR1(klass, mid);

@@ -1376,12 +1378,18 @@
return method_missing(recv, mid, argc, argv,
scope == 2 ? NOEX_VCALL : 0);
id = ent->mid0;

  • noex = ent->method->nd_noex;
  • if (!noex_is_set) {
  •  noex = ent->method->nd_noex;
    
  •  noex_is_set = 1;
    
  • }
    klass = ent->method->nd_clss;
    body = ent->method->nd_body;
    }
  • else if ((method = rb_get_method_body(klass, id, &id)) != 0) {
  • noex = method->nd_noex;
  • else if ((method = rb_get_method_body(klass, mid, &id)) != 0) {
  • if (!noex_is_set) {
  •  noex = method->nd_noex;
    
  •  noex_is_set = 1;
    
  • }
    klass = method->nd_clss;
    body = method->nd_body;
    }
    @@ -1392,7 +1400,10 @@
    return method_missing(recv, mid, argc, argv,
    scope == 2 ? NOEX_VCALL : 0);
    }
  • if (nd_type(body) == NODE_ZSUPER) {

  • klass = RCLASS_SUPER(klass);

  • goto again;

  • }

    if (mid != missing) {
    /* receiver specified form for private method */

e$B5WJ]$G$9!#e(B

e$B;n83$9$k$NCY$l$F$9$_$^$;$s!#e(B

On 2/26/07, Nobuyoshi N. [email protected] wrote:

e$B$3$l$G$I$&$G$7$g$&$+!#e(B
svn trunk
e$B$K%Q%C%A$rEv$F$F$d$C$F$_$?$H$3$m!"0J2<$N$h$&$K$J$j$^$7$?!#e(B

$ ruby mytest.rb
mytest.rb:14:in run': super: no superclass method run’
(NoMethodError)
from mytest.rb:14:in `’

mytest.c e$B$GDj5A$7$F$k$N$HF1$8%/%i%9$re(B ruby e$B$G=q$/e(B(mytest.c
e$B$N@hF,$Ne(B
e$B%3%a%s%H$N=q$+$l$F$$$k%3!<%I$r;H$&e(B)e$B$H!"%(%i!<$K$J$i$:!"e(B
$ ruby mytest.rb
OK
e$B$H$J$j$^$9!#e(B

e$B$^$?!“e(Bmytest.rb e$B$Ne(B
class B < A
public :run
end
e$B$NItJ,$re(B
class B < A
def run
super
end
end
e$B$KJQ$($F$b@5>o$KF0$-$^$7$?!#e(B(patche$B$”$je(B/e$B$J$7N>J}$H$be(B)

e$B?F%/%i%9$Ge(B private e$B$J%a%=%C%I$r%5%V%/%i%9$Ge(B
public :e$B%a%=%C%IL>e(B
e$B$G%9%3!<%W$rJQ99$7$?$H$-$@$1!"$+$D!"3HD%%i%$%V%i%j$+$ie(B
e$BLdBj$N%a%=%C%I$rD>@\8F$S=P$7$?$H$-$@$15/$3$kLdBj$J$N$+$J!)e(B

e$B:XF#$H?=$7$^$9!#e(B

On Sun, 21 Oct 2007 00:45:46 +0900
“KUBO Takehiro” [email protected] wrote:

8e$B%v7nA0$N%a!<%k$G$9$,!“$3$N7o!”$:$C$H:$$C$F$$$?$N$Ge(B proc.c e$B$Ne(B mnew()
e$B$r;29M$K%Q%C%A$r:n$j$^$7$?!#e(B [ruby-dev:30396]e$B$N;n83%W%m%0%i%`$OF0$/$he(B
e$B$&$K$J$j$^$7$?!#e(B

e$B!D$H8@$&%a!<%k$+$i;M%v7n6a$/7P$D!“$@$$$V8E$$OC$G$9$,!”$3$N7o$O$=$N8ee(B
e$B$I$&$J$C$F$$$^$9$+e(B?

e$B<+J,$N<j85$G$O!"JQ$o$j$,$J$$$h$&$K8+$($^$9!#$9$J$o$Ae(B

$ ruby-trunk -v
ruby 1.9.0 (2008-02-14 revision 15234) [i686-linux]

e$B$H$$$&4D6-$Ge(B

e$B!&e(B[ruby-dev:30396] e$B$Ne(B [BUG] e$B$,:F8=$7$Fe(B
e$B!&e(B[ruby-dev:32111]
e$B$N%Q%C%A$GLdBj$J$/!Ve(BOKe$B!W$,I=<($5$l$ke(B

e$B$H$$$&>uBV$G$9!#e(B

e$BCf?H$O$^$C$?$/J,$+$j$^$;$s$,!"e(B[ruby-dev:32111]e$B$N5WJ]$5$s$N%Q%C%A$r!"e(B
e$B:#$Ne(Beval.ce$B$K9g$o$;$Fe(Brejectione$B$r2r7h$7$?$b$N$r:F7G$7$FCV$-$^$9!#e(B
e$B$*Lr$KN)$F$P9,$$$G$9!#e(B

Index: eval.c

— eval.c (revision 15464)
+++ eval.c (working copy)
@@ -1363,6 +1363,7 @@
rb_call0(VALUE klass, VALUE recv, ID mid, int argc, const VALUE *argv,
int scope, VALUE self)
{
NODE *body, *method;

  • int noex_is_set = 0;
    int noex;
    ID id = mid;
    struct cache_entry *ent;
    @@ -1373,6 +1374,7 @@
    “method `%s’ called on terminated object (%p)”,
    rb_id2name(mid), (void *)recv);
    }
  • again:
    /* is it in the method cache? */
    ent = cache + EXPR1(klass, mid);

@@ -1381,12 +1383,18 @@
return method_missing(recv, mid, argc, argv,
scope == 2 ? NOEX_VCALL : 0);
id = ent->mid0;

  • noex = ent->method->nd_noex;
  • if (!noex_is_set) {
  •  noex = ent->method->nd_noex;
    
  •  noex_is_set = 1;
    
  • }
    klass = ent->method->nd_clss;
    body = ent->method->nd_body;
    }
  • else if ((method = rb_get_method_body(klass, id, &id)) != 0) {
  • noex = method->nd_noex;
  • else if ((method = rb_get_method_body(klass, mid, &id)) != 0) {
  • if (!noex_is_set) {
  •  noex = method->nd_noex;
    
  •  noex_is_set = 1;
    
  • }
    klass = method->nd_clss;
    body = method->nd_body;
    }
    @@ -1397,7 +1405,10 @@
    return method_missing(recv, mid, argc, argv,
    scope == 2 ? NOEX_VCALL : 0);
    }
  • if (nd_type(body) == NODE_ZSUPER) {

  • klass = RCLASS_SUPER(klass);

  • goto again;

  • }

    if (mid != missing) {
    /* receiver specified form for private method */