aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog21
-rw-r--r--common.mk7
-rw-r--r--insn_send.ci226
-rw-r--r--insnhelper.h16
-rw-r--r--insns.def236
-rw-r--r--test/ruby/test_super.rb2
-rw-r--r--vm.c172
-rw-r--r--vm_evalbody.ci4
8 files changed, 300 insertions, 384 deletions
diff --git a/ChangeLog b/ChangeLog
index d5c501db2b..0ab5402906 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,24 @@
+Sun Jun 24 22:00:17 2007 Koichi Sasada <ko1@atdot.net>
+
+ * insn_send.ci: removed.
+
+ * common.mk: ditto.
+
+ * vm.c (vm_call_bmethod), isnsn.def: added. fix to use this
+ function instead of using goto.
+
+ * vm.c (vm_call_bmethod): renamed from th_invoke_bmethod().
+
+ * vm.c (vm_method_missing): renamed from eval_methdo_missing().
+
+ * vm_evalbody.ci: remove tmp_* variables.
+
+ * insnhelper.h: add some macros.
+
+ * insns.def: forbid zsuper from method defined by define_method().
+
+ * test/ruby/test_super.rb: ditto.
+
Sun Jun 24 20:01:08 2007 Koichi Sasada <ko1@atdot.net>
* vm_macro.def: removed.
diff --git a/common.mk b/common.mk
index af8a93f476..e2df6060aa 100644
--- a/common.mk
+++ b/common.mk
@@ -552,21 +552,20 @@ compile.$(OBJEXT): {$(VPATH)}compile.c {$(VPATH)}yarvcore.h \
{$(VPATH)}compile.h {$(VPATH)}debug.h {$(VPATH)}ruby.h {$(VPATH)}config.h \
{$(VPATH)}defines.h {$(VPATH)}missing.h {$(VPATH)}intern.h \
{$(VPATH)}st.h {$(VPATH)}node.h {$(VPATH)}signal.h \
- {$(VPATH)}insns.inc {$(VPATH)}insns_info.inc {$(VPATH)}optinsn.inc \
+ {$(VPATH)}insns_info.inc {$(VPATH)}optinsn.inc \
{$(VPATH)}opt_sc.inc {$(VPATH)}optunifs.inc {$(VPATH)}vm_opts.h \
{$(VPATH)}thread_$(THREAD_MODEL).h
iseq.$(OBJEXT): {$(VPATH)}iseq.c {$(VPATH)}yarvcore.h {$(VPATH)}debug.h \
{$(VPATH)}ruby.h {$(VPATH)}defines.h {$(VPATH)}missing.h \
{$(VPATH)}intern.h {$(VPATH)}st.h {$(VPATH)}signal.h \
{$(VPATH)}gc.h {$(VPATH)}vm_opts.h {$(VPATH)}config.h {$(VPATH)}node.h \
- {$(VPATH)}thread_$(THREAD_MODEL).h\
- {$(VPATH)}insns.inc {$(VPATH)}insns_info.inc
+ {$(VPATH)}thread_$(THREAD_MODEL).h {$(VPATH)}insns_info.inc
vm.$(OBJEXT): {$(VPATH)}vm.c {$(VPATH)}vm.h {$(VPATH)}insnhelper.h \
{$(VPATH)}yarvcore.h {$(VPATH)}debug.h {$(VPATH)}ruby.h {$(VPATH)}config.h\
{$(VPATH)}node.h {$(VPATH)}util.h {$(VPATH)}signal.h {$(VPATH)}dln.h \
{$(VPATH)}vm_evalbody.ci {$(VPATH)}call_cfunc.ci \
{$(VPATH)}insns.inc {$(VPATH)}vm.inc {$(VPATH)}vmtc.inc \
- {$(VPATH)}insn_send.ci {$(VPATH)}vm_opts.h {$(VPATH)}eval_intern.h \
+ {$(VPATH)}vm_opts.h {$(VPATH)}eval_intern.h \
{$(VPATH)}defines.h {$(VPATH)}missing.h {$(VPATH)}intern.h \
{$(VPATH)}gc.h {$(VPATH)}thread_$(THREAD_MODEL).h
vm_dump.$(OBJEXT): {$(VPATH)}vm_dump.c {$(VPATH)}yarvcore.h {$(VPATH)}vm.h \
diff --git a/insn_send.ci b/insn_send.ci
deleted file mode 100644
index a37336f557..0000000000
--- a/insn_send.ci
+++ /dev/null
@@ -1,226 +0,0 @@
-/* -*-c-*- */
-/* send instruction body */
-
-{
- NODE *mn;
- VALUE recv;
- VALUE klass;
- rb_block_t *blockptr = 0;
- rb_num_t num;
- rb_num_t flag = op_flag;
- ID id = op_id;
-
- num = caller_setup_args(th, GET_CFP(), flag, op_argc, blockiseq, &blockptr);
-
- if (flag & VM_CALL_FCALL_BIT) {
- /* method(...) */
- recv = GET_SELF();
- }
- else {
- /* recv.method(...) */
- recv = TOPN(num);
- }
-
- klass = CLASS_OF(recv);
-
- mn = eval_method_search(id, klass, ic);
-
- if ((flag & VM_CALL_SEND_BIT) && mn && nd_type(mn->nd_body) == NODE_CFUNC) {
- NODE *node = mn->nd_body;
- extern VALUE rb_f_funcall(int argc, VALUE *argv, VALUE recv);
- extern VALUE rb_f_send(int argc, VALUE *argv, VALUE recv);
-
- if (node->nd_cfnc == rb_f_funcall || node->nd_cfnc == rb_f_send) {
- int i;
- VALUE sym = TOPN(num - 1);
- id = SYMBOL_P(sym) ? SYM2ID(sym) : rb_to_id(sym);
-
- /* shift arguments */
- for (i=num-1; i>0; i--) {
- TOPN(i) = TOPN(i-1);
- }
-
- mn = rb_method_node(klass, id);
-
- num -= 1;
- DEC_SP(1);
- }
-
- if (node->nd_cfnc == rb_f_funcall) {
- flag |= VM_CALL_FCALL_BIT;
- }
- }
-
-#if CURRENT_INSN_send || CURRENT_INSN_send_SC_xx_ax
-#if !YARV_AOT_COMPILED
- if (0) {
- if (0) {
- LABEL_IS_SC(start_init_in_send_for_opt_1):
- num = 1;
- recv = TOPN(1);
- }
- else if (0) {
- LABEL_IS_SC(start_init_in_send_for_opt_2):
- num = 2;
- recv = TOPN(2);
- }
- flag = 0;
- id = tmp_id;
- klass = CLASS_OF(recv);
- blockptr = 0;
- mn = rb_method_node(klass, id);
- }
- if (0) {
- LABEL_IS_SC(start_init_in_super):
- {
- rb_iseq_t *iseq = GET_ISEQ();
- rb_iseq_t *ip = iseq;
-
- num = tmp_num;
- flag = VM_CALL_FCALL_BIT;
- recv = GET_SELF();
-
- while (ip && !ip->klass) {
- ip = ip->parent_iseq;
- }
-
- if (ip == 0) {
- rb_raise(rb_eNoMethodError, "super called outside of method");
- }
-
- id = ip->defined_method_id;
-
- if (ip != ip->local_iseq) {
- /* defined by Module#define_method() */
- rb_control_frame_t *lcfp = GET_CFP();
-
- while (lcfp->iseq != ip) {
- VALUE *tdfp = GET_PREV_DFP(lcfp->dfp);
- while (1) {
- lcfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(lcfp);
- if (lcfp->dfp == tdfp) {
- break;
- }
- }
- }
-
- id = lcfp->method_id;
- klass = search_super_klass(lcfp->method_klass, recv);
-
- if (TOPN(num) == Qfalse) {
- /* for ZSUPER */
- int i;
- POPN(num);
- num = ip->argc;
- for (i = 0; i < ip->argc; i++) {
- PUSH(lcfp->dfp[i - ip->local_size]);
- }
- }
- }
- else {
- klass = search_super_klass(ip->klass, recv);
- }
-
- flag = VM_CALL_SUPER_BIT | VM_CALL_FCALL_BIT;
- blockptr = tmp_blockptr;
- mn = rb_method_node(klass, id);
- }
- }
- LABEL_IS_SC(start_method_dispatch):
-#endif
-#endif
- /* method missing */
- if (mn == 0) {
- /* temporarily */
- if (id == idMethodMissing) {
- rb_bug("method missing");
- }
- else {
- int stat = 0;
- if (flag & VM_CALL_VCALL_BIT) {
- stat |= NOEX_VCALL;
- }
- if (flag & VM_CALL_SUPER_BIT) {
- stat |= NOEX_SUPER;
- }
- val = eval_method_missing(th, id, recv, num, blockptr, stat);
- }
- }
- else if (!(flag & VM_CALL_FCALL_BIT) &&
- (mn->nd_noex & NOEX_MASK) & NOEX_PRIVATE) {
- int stat = NOEX_PRIVATE;
- if (flag & VM_CALL_VCALL_BIT) {
- stat |= NOEX_VCALL;
- }
- val = eval_method_missing(th, id, recv, num, blockptr, stat);
- }
- else if ((mn->nd_noex & NOEX_MASK) & NOEX_PROTECTED) {
- VALUE defined_class = mn->nd_clss;
-
- if (TYPE(defined_class) == T_ICLASS) {
- defined_class = RBASIC(defined_class)->klass;
- }
- if (!rb_obj_is_kind_of(GET_SELF(), rb_class_real(defined_class))) {
- val =
- eval_method_missing(th, id, recv, num, blockptr,
- NOEX_PROTECTED);
- }
- else {
- goto INSN_LABEL(normal_method_dispatch);
- }
- }
- else {
- NODE *node;
- INSN_LABEL(normal_method_dispatch):
-
- node = mn->nd_body;
- switch (nd_type(node)) {
- case RUBY_VM_METHOD_NODE:{
- vm_setup_method(th, GET_CFP(), num, blockptr, flag, (VALUE)node->nd_body, recv, klass);
- RESTORE_REGS();
- NEXT_INSN();
- }
- case NODE_CFUNC:{
- val = vm_call_cfunc(th, GET_CFP(), num, id, recv, klass, node, blockptr);
- break;
- }
- case NODE_ATTRSET:{
- val = rb_ivar_set(recv, node->nd_vid, TOPN(0));
- POPN(2);
- break;
- }
- case NODE_IVAR:{
- val = rb_ivar_get(recv, node->nd_vid);
- POP();
- break;
- }
- case NODE_BMETHOD:{
- VALUE *argv = GET_SP() - num;
- val = th_invoke_bmethod(th, id, node->nd_cval,
- recv, klass, num, argv);
- INC_SP(-num-1);
- break;
- }
- case NODE_ZSUPER:{
- klass = RCLASS(mn->nd_clss)->super;
- mn = rb_method_node(klass, id);
-
- if (mn != 0) {
- goto INSN_LABEL(normal_method_dispatch);
- }
- else {
- goto LABEL_IS_SC(start_method_dispatch);
- }
- }
- default:{
- printf("node: %s\n", ruby_node_name(nd_type(node)));
- rb_bug("eval_invoke_method: unreachable");
- /* unreachable */
- break;
- }
- }
- }
-
- RUBY_VM_CHECK_INTS();
-}
-
diff --git a/insnhelper.h b/insnhelper.h
index 3801e5a41b..1fe19128b7 100644
--- a/insnhelper.h
+++ b/insnhelper.h
@@ -146,4 +146,20 @@ while (0)
#define BASIC_OP_UNREDEFINED_P(op) ((yarv_redefined_flag & (op)) == 0)
#define HEAP_CLASS_OF(obj) RBASIC(obj)->klass
+#define CALL_METHOD(num, blockptr, flag, id, mn, recv, klass) do { \
+ VALUE v = vm_call_method(th, GET_CFP(), num, blockptr, flag, id, mn, recv, klass); \
+ if (v == Qundef) { \
+ RESTORE_REGS(); \
+ NEXT_INSN(); \
+ } \
+ else { \
+ val = v; \
+ } \
+} while (0)
+
+#define CALL_SIMPLE_METHOD(num, id, recv) do { \
+ VALUE klass = CLASS_OF(recv); \
+ CALL_METHOD(num, 0, 0, id, rb_method_node(klass, id), recv, CLASS_OF(recv)); \
+} while (0)
+
#endif /* _INSNHELPER_H_INCLUDED_ */
diff --git a/insns.def b/insns.def
index 4b16695877..6d16fe1b59 100644
--- a/insns.def
+++ b/insns.def
@@ -1152,7 +1152,55 @@ send
(...)
(VALUE val) // inc += - (op_argc + ((op_flag & VM_CALL_ARGS_BLOCKARG_BIT) ? 1 : 0));
{
-#include "insn_send.ci"
+ NODE *mn;
+ VALUE recv, klass, v;
+ rb_block_t *blockptr = 0;
+ rb_num_t num = caller_setup_args(th, GET_CFP(), op_flag, op_argc, blockiseq, &blockptr);
+ rb_num_t flag = op_flag;
+ ID id = op_id;
+
+ /* get receiver */
+ if (flag & VM_CALL_FCALL_BIT) {
+ /* method(...) */
+ recv = GET_SELF();
+ }
+ else {
+ /* recv.method(...) */
+ recv = TOPN(num);
+ }
+
+ klass = CLASS_OF(recv);
+
+ mn = eval_method_search(id, klass, ic);
+
+ /* send/funcall optimization */
+ if ((flag & VM_CALL_SEND_BIT) && mn && nd_type(mn->nd_body) == NODE_CFUNC) {
+ NODE *node = mn->nd_body;
+ extern VALUE rb_f_funcall(int argc, VALUE *argv, VALUE recv);
+ extern VALUE rb_f_send(int argc, VALUE *argv, VALUE recv);
+
+ if (node->nd_cfnc == rb_f_funcall || node->nd_cfnc == rb_f_send) {
+ int i;
+ VALUE sym = TOPN(num - 1);
+ id = SYMBOL_P(sym) ? SYM2ID(sym) : rb_to_id(sym);
+
+ /* shift arguments */
+ for (i=num-1; i>0; i--) {
+ TOPN(i) = TOPN(i-1);
+ }
+
+ mn = rb_method_node(klass, id);
+
+ num -= 1;
+ DEC_SP(1);
+ }
+
+ if (node->nd_cfnc == rb_f_funcall) {
+ flag |= VM_CALL_FCALL_BIT;
+ }
+ }
+
+ CALL_METHOD(num, blockptr, flag, id, mn, recv, klass);
}
/**
@@ -1162,21 +1210,65 @@ send
*/
DEFINE_INSN
invokesuper
-(rb_num_t op_argc, ISEQ blockiseq, rb_num_t flag)
+(rb_num_t op_argc, ISEQ blockiseq, rb_num_t op_flag)
(...)
(VALUE val) // inc += - op_argc;
{
-#if YARV_AOT_COMPILED
- /* TODO: */
- rb_bug("...");
-#else
- tmp_blockptr = 0;
- tmp_num = caller_setup_args(th, GET_CFP(), flag, op_argc, blockiseq, &tmp_blockptr);
- if (!tmp_blockptr && !(flag & VM_CALL_ARGS_BLOCKARG_BIT)) {
- tmp_blockptr = GET_BLOCK_PTR();
+ rb_block_t *blockptr = 0;
+ VALUE flag = op_flag;
+ int num = caller_setup_args(th, GET_CFP(), flag, op_argc, blockiseq, &blockptr);
+ rb_iseq_t *iseq = GET_ISEQ();
+ rb_iseq_t *ip = iseq;
+ VALUE recv, klass;
+ ID id;
+ NODE *mn;
+
+ if (!blockptr && !(flag & VM_CALL_ARGS_BLOCKARG_BIT)) {
+ blockptr = GET_BLOCK_PTR();
}
- goto LABEL_IS_SC(start_init_in_super);
-#endif
+
+ recv = GET_SELF();
+
+ while (ip && !ip->klass) {
+ ip = ip->parent_iseq;
+ }
+
+ if (ip == 0) {
+ rb_raise(rb_eNoMethodError, "super called outside of method");
+ }
+
+ id = ip->defined_method_id;
+
+ if (ip != ip->local_iseq) {
+ /* defined by Module#define_method() */
+ rb_control_frame_t *lcfp = GET_CFP();
+
+ while (lcfp->iseq != ip) {
+ VALUE *tdfp = GET_PREV_DFP(lcfp->dfp);
+ while (1) {
+ lcfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(lcfp);
+ if (lcfp->dfp == tdfp) {
+ break;
+ }
+ }
+ }
+
+ id = lcfp->method_id;
+ klass = search_super_klass(lcfp->method_klass, recv);
+
+ if (TOPN(num) == Qfalse) {
+ /* zsuper */
+ rb_raise(rb_eRuntimeError, "zsuper from method defined by define_method() is not supported. Specify all arguments.");
+ }
+ }
+ else {
+ klass = search_super_klass(ip->klass, recv);
+ }
+
+ flag = VM_CALL_SUPER_BIT | VM_CALL_FCALL_BIT;
+ mn = rb_method_node(klass, id);
+
+ CALL_METHOD(num, blockptr, flag, id, mn, recv, klass);
}
/**
@@ -1581,15 +1673,9 @@ opt_plus
}
else {
INSN_LABEL(normal_dispatch):
-
-#ifdef YARV_AOT_COMPILED
- val = rb_funcall(recv, idPLUS, 1, obj);
-#else
PUSH(recv);
PUSH(obj);
- tmp_id = idPLUS;
- goto LABEL_IS_SC(start_init_in_send_for_opt_1);
-#endif
+ CALL_SIMPLE_METHOD(1, idPLUS, recv);
}
}
@@ -1619,14 +1705,9 @@ opt_minus
}
else {
/* other */
-#ifdef YARV_AOT_COMPILED
- val = rb_funcall(recv, idMINUS, 1, obj);
-#else
PUSH(recv);
PUSH(obj);
- tmp_id = idMINUS;
- goto LABEL_IS_SC(start_init_in_send_for_opt_1);
-#endif
+ CALL_SIMPLE_METHOD(1, idMINUS, recv);
}
}
@@ -1675,16 +1756,9 @@ opt_mult
}
else {
INSN_LABEL(normal_dispatch):
-
- /* other */
-#ifdef YARV_AOT_COMPILED
- val = rb_funcall(recv, idMULT, 1, obj);
-#else
PUSH(recv);
PUSH(obj);
- tmp_id = idMULT;
- goto LABEL_IS_SC(start_init_in_send_for_opt_1);
-#endif
+ CALL_SIMPLE_METHOD(1, idMULT, recv);
}
}
@@ -1746,16 +1820,9 @@ opt_div
}
else {
INSN_LABEL(normal_dispatch):
-
- /* other */
-#ifdef YARV_AOT_COMPILED
- val = rb_funcall(recv, idDIV, 1, obj);
-#else
PUSH(recv);
PUSH(obj);
- tmp_id = idDIV;
- goto LABEL_IS_SC(start_init_in_send_for_opt_1);
-#endif
+ CALL_SIMPLE_METHOD(1, idDIV, recv);
}
}
@@ -1837,16 +1904,9 @@ opt_mod
}
else {
INSN_LABEL(normal_dispatch):
-
- /* other */
-#ifdef YARV_AOT_COMPILED
- val = rb_funcall(recv, idMOD, 1, obj);
-#else
PUSH(recv);
PUSH(obj);
- tmp_id = idMOD;
- goto LABEL_IS_SC(start_init_in_send_for_opt_1);
-#endif
+ CALL_SIMPLE_METHOD(1, idMOD, recv);
}
}
@@ -1916,14 +1976,9 @@ opt_eq
else {
INSN_LABEL(normal_dispatch):
/* other */
-#ifdef YARV_AOT_COMPILED
- val = rb_funcall(recv, idEq, 1, obj);
-#else
PUSH(recv);
PUSH(obj);
- tmp_id = idEq;
- goto LABEL_IS_SC(start_init_in_send_for_opt_1);
-#endif
+ CALL_SIMPLE_METHOD(1, idEq, recv);
}
}
@@ -1951,15 +2006,9 @@ opt_lt
}
}
else {
- /* other */
-#ifdef YARV_AOT_COMPILED
- val = rb_funcall(recv, idLT, 1, obj);
-#else
PUSH(recv);
PUSH(obj);
- tmp_id = idLT;
- goto LABEL_IS_SC(start_init_in_send_for_opt_1);
-#endif
+ CALL_SIMPLE_METHOD(1, idLT, recv);
}
}
@@ -1987,14 +2036,9 @@ opt_le
}
else {
/* other */
-#ifdef YARV_AOT_COMPILED
- val = rb_funcall(recv, idLE, 1, obj);
-#else
PUSH(recv);
PUSH(obj);
- tmp_id = idLE;
- goto LABEL_IS_SC(start_init_in_send_for_opt_1);
-#endif
+ CALL_SIMPLE_METHOD(1, idLE, recv);
}
}
@@ -2021,15 +2065,9 @@ opt_gt
}
}
else {
- /* other */
-#ifdef YARV_AOT_COMPILED
- val = rb_funcall(recv, idGT, 1, obj);
-#else
PUSH(recv);
PUSH(obj);
- tmp_id = idGT;
- goto LABEL_IS_SC(start_init_in_send_for_opt_1);
-#endif
+ CALL_SIMPLE_METHOD(1, idGT, recv);
}
}
@@ -2056,15 +2094,9 @@ opt_ge
}
}
else {
- /* other */
-#ifdef YARV_AOT_COMPILED
- val = rb_funcall(recv, idGE, 1, obj);
-#else
PUSH(recv);
PUSH(obj);
- tmp_id = idGE;
- goto LABEL_IS_SC(start_init_in_send_for_opt_1);
-#endif
+ CALL_SIMPLE_METHOD(1, idGE, recv);
}
}
@@ -2096,15 +2128,9 @@ opt_ltlt
}
else {
INSN_LABEL(normal_dispatch):
- /* other */
-#ifdef YARV_AOT_COMPILED
- val = rb_funcall(recv, idLTLT, 1, obj);
-#else
PUSH(recv);
PUSH(obj);
- tmp_id = idLTLT;
- goto LABEL_IS_SC(start_init_in_send_for_opt_1);
-#endif
+ CALL_SIMPLE_METHOD(1, idLTLT, recv);
}
}
@@ -2132,15 +2158,9 @@ opt_aref
}
else {
INSN_LABEL(normal_dispatch):
- /* other */
-#ifdef YARV_AOT_COMPILED
- val = rb_funcall(recv, idAREF, 1, obj);
-#else
PUSH(recv);
PUSH(obj);
- tmp_id = idAREF;
- goto LABEL_IS_SC(start_init_in_send_for_opt_1);
-#endif
+ CALL_SIMPLE_METHOD(1, idAREF, recv);
}
}
@@ -2171,16 +2191,10 @@ opt_aset
}
else {
INSN_LABEL(normal_dispatch):
- /* other */
-#ifdef YARV_AOT_COMPILED
- val = rb_funcall(recv, idASET, 2, obj, set);
-#else
PUSH(recv);
PUSH(obj);
PUSH(set);
- tmp_id = idASET;
- goto LABEL_IS_SC(start_init_in_send_for_opt_2);
-#endif
+ CALL_SIMPLE_METHOD(2, idASET, recv);
}
}
@@ -2212,12 +2226,8 @@ opt_length
}
else {
INSN_LABEL(normal_dispatch):
- /* other */
-#ifdef YARV_AOT_COMPILED
- val = rb_funcall(recv, idLength, 0);
-#else
- val = rb_funcall(recv, idLength, 0);
-#endif
+ PUSH(recv);
+ CALL_SIMPLE_METHOD(0, idLength, recv);
}
}
@@ -2262,12 +2272,8 @@ opt_succ
}
if (0) {
INSN_LABEL(normal_dispatch):
- /* other */
-#ifdef YARV_AOT_COMPILED
- val = rb_funcall(recv, idSucc, 0);
-#else
- val = rb_funcall(recv, idSucc, 0);
-#endif
+ PUSH(recv);
+ CALL_SIMPLE_METHOD(0, idSucc, recv);
}
}
diff --git a/test/ruby/test_super.rb b/test/ruby/test_super.rb
index 900fe997e6..d64fef514e 100644
--- a/test/ruby/test_super.rb
+++ b/test/ruby/test_super.rb
@@ -120,7 +120,7 @@ class TestSuper < Test::Unit::TestCase
def uu(a)
class << self
define_method(:tt) do |sym|
- super
+ super(sym)
end
end
end
diff --git a/vm.c b/vm.c
index b8acd9e523..8ac65d0e35 100644
--- a/vm.c
+++ b/vm.c
@@ -371,6 +371,38 @@ vm_call_cfunc(rb_thread_t *th, rb_control_frame_t *reg_cfp, int num,
return val;
}
+static inline VALUE
+vm_call_bmethod(rb_thread_t *th, ID id, VALUE procval, VALUE recv,
+ VALUE klass, int argc, VALUE *argv)
+{
+ rb_control_frame_t *cfp = th->cfp;
+ rb_proc_t *proc;
+ VALUE val;
+
+ /* control block frame */
+ (cfp-2)->method_id = id;
+ (cfp-2)->method_klass = klass;
+
+ GetProcPtr(procval, proc);
+ val = th_invoke_proc(th, proc, recv, argc, argv);
+ return val;
+}
+
+static inline VALUE
+vm_method_missing(rb_thread_t *th, ID id, VALUE recv, int num,
+ rb_block_t *blockptr, int opt)
+{
+ rb_control_frame_t *reg_cfp = th->cfp;
+ VALUE *argv = STACK_ADDR_FROM_TOP(num + 1);
+ VALUE val;
+ argv[0] = ID2SYM(id);
+ th->method_missing_reason = opt;
+ th->passed_block = blockptr;
+ val = rb_funcall2(recv, idMethodMissing, num + 1, argv);
+ POPN(num + 1);
+ return val;
+}
+
static inline void
vm_setup_method(rb_thread_t *th, rb_control_frame_t *cfp,
int argc, rb_block_t *blockptr, VALUE flag,
@@ -428,6 +460,110 @@ vm_setup_method(rb_thread_t *th, rb_control_frame_t *cfp,
}
}
+static inline VALUE
+vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp,
+ int num, rb_block_t *blockptr, VALUE flag,
+ ID id, NODE *mn, VALUE recv, VALUE klass)
+{
+ VALUE val;
+
+ start_method_dispatch:
+
+ /* method missing */
+ if (mn == 0) {
+ if (id == idMethodMissing) {
+ rb_bug("method missing");
+ }
+ else {
+ int stat = 0;
+ if (flag & VM_CALL_VCALL_BIT) {
+ stat |= NOEX_VCALL;
+ }
+ if (flag & VM_CALL_SUPER_BIT) {
+ stat |= NOEX_SUPER;
+ }
+ val = vm_method_missing(th, id, recv, num, blockptr, stat);
+ }
+ }
+ else if (!(flag & VM_CALL_FCALL_BIT) &&
+ (mn->nd_noex & NOEX_MASK) & NOEX_PRIVATE) {
+ int stat = NOEX_PRIVATE;
+ if (flag & VM_CALL_VCALL_BIT) {
+ stat |= NOEX_VCALL;
+ }
+ val = vm_method_missing(th, id, recv, num, blockptr, stat);
+ }
+ else if ((mn->nd_noex & NOEX_MASK) & NOEX_PROTECTED) {
+ VALUE defined_class = mn->nd_clss;
+
+ if (TYPE(defined_class) == T_ICLASS) {
+ defined_class = RBASIC(defined_class)->klass;
+ }
+
+ if (!rb_obj_is_kind_of(cfp->self, rb_class_real(defined_class))) {
+ val = vm_method_missing(th, id, recv, num, blockptr, NOEX_PROTECTED);
+ }
+ else {
+ goto normal_method_dispatch;
+ }
+ }
+
+ /* dispatch method */
+ else {
+ NODE *node;
+ normal_method_dispatch:
+
+ node = mn->nd_body;
+ switch (nd_type(node)) {
+ case RUBY_VM_METHOD_NODE:{
+ vm_setup_method(th, cfp, num, blockptr, flag, (VALUE)node->nd_body, recv, klass);
+ return Qundef;
+ }
+ case NODE_CFUNC:{
+ val = vm_call_cfunc(th, cfp, num, id, recv, klass, node, blockptr);
+ break;
+ }
+ case NODE_ATTRSET:{
+ val = rb_ivar_set(recv, node->nd_vid, *(cfp->sp - 1));
+ cfp->sp -= 2;
+ break;
+ }
+ case NODE_IVAR:{
+ val = rb_ivar_get(recv, node->nd_vid);
+ cfp->sp -= 1;
+ break;
+ }
+ case NODE_BMETHOD:{
+ VALUE *argv = cfp->sp - num;
+ val = vm_call_bmethod(th, id, node->nd_cval, recv, klass, num, argv);
+ cfp->sp += - num - 1;
+ break;
+ }
+ case NODE_ZSUPER:{
+ klass = RCLASS(mn->nd_clss)->super;
+ mn = rb_method_node(klass, id);
+
+ if (mn != 0) {
+ goto normal_method_dispatch;
+ }
+ else {
+ goto start_method_dispatch;
+ }
+ }
+ default:{
+ printf("node: %s\n", ruby_node_name(nd_type(node)));
+ rb_bug("eval_invoke_method: unreachable");
+ /* unreachable */
+ break;
+ }
+ }
+ }
+
+ RUBY_VM_CHECK_INTS();
+ return val;
+}
+
+
/* Env */
static void
@@ -735,23 +871,6 @@ th_make_proc(rb_thread_t *th,
return procval;
}
-static inline VALUE
-th_invoke_bmethod(rb_thread_t *th, ID id, VALUE procval, VALUE recv,
- VALUE klass, int argc, VALUE *argv)
-{
- rb_control_frame_t *cfp = th->cfp;
- rb_proc_t *proc;
- VALUE val;
-
- /* control block frame */
- (cfp-2)->method_id = id;
- (cfp-2)->method_klass = klass;
-
- GetProcPtr(procval, proc);
- val = th_invoke_proc(th, proc, recv, argc, argv);
- return val;
-}
-
VALUE
th_call0(rb_thread_t *th, VALUE klass, VALUE recv,
VALUE id, ID oid, int argc, const VALUE *argv,
@@ -829,8 +948,8 @@ th_call0(rb_thread_t *th, VALUE klass, VALUE recv,
break;
}
case NODE_BMETHOD:{
- val = th_invoke_bmethod(th, id, body->nd_cval,
- recv, klass, argc, (VALUE *)argv);
+ val = vm_call_bmethod(th, id, body->nd_cval,
+ recv, klass, argc, (VALUE *)argv);
break;
}
default:
@@ -1555,21 +1674,6 @@ eval_define_method(rb_thread_t *th, VALUE obj,
INC_VM_STATE_VERSION();
}
-EVALBODY_HELPER_FUNCTION VALUE
-eval_method_missing(rb_thread_t *th, ID id, VALUE recv, int num,
- rb_block_t *blockptr, int opt)
-{
- rb_control_frame_t *reg_cfp = th->cfp;
- VALUE *argv = STACK_ADDR_FROM_TOP(num + 1);
- VALUE val;
- argv[0] = ID2SYM(id);
- th->method_missing_reason = opt;
- th->passed_block = blockptr;
- val = rb_funcall2(recv, idMethodMissing, num + 1, argv);
- POPN(num + 1);
- return val;
-}
-
EVALBODY_HELPER_FUNCTION NODE *
eval_method_search(VALUE id, VALUE klass, IC ic)
{
diff --git a/vm_evalbody.ci b/vm_evalbody.ci
index 3497ac7ff1..d0c45b3a5b 100644
--- a/vm_evalbody.ci
+++ b/vm_evalbody.ci
@@ -76,10 +76,6 @@ th_eval(rb_thread_t *th, VALUE initial)
#define SET_PC(x) (reg_cfp->pc = REG_PC = (x))
#endif
- ID tmp_id;
- rb_block_t *tmp_blockptr;
- rb_num_t tmp_num;
-
#if OPT_TOKEN_THREADED_CODE || OPT_DIRECT_THREADED_CODE
#include "vmtc.inc"
if (th == 0) {