From ae421c43dfda6e9a1e9af1edaa649a3de17ff07a Mon Sep 17 00:00:00 2001 From: ko1 Date: Mon, 6 Aug 2007 11:36:30 +0000 Subject: * insnhelper.ci, insns.def: move some statements to functions. * vm.c, vm.h, vm_evalbody.ci: fix include/typedef places. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12887 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 6 ++ insnhelper.ci | 307 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- insnhelper.h | 3 + insns.def | 310 +++------------------------------------------------------ vm.c | 3 +- vm.h | 1 + vm_evalbody.ci | 2 - 7 files changed, 332 insertions(+), 300 deletions(-) diff --git a/ChangeLog b/ChangeLog index ef50f57951..1e038f3f15 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +Mon Aug 6 20:29:22 2007 Koichi Sasada + + * insnhelper.ci, insns.def: move some statements to functions. + + * vm.c, vm.h, vm_evalbody.ci: fix include/typedef places. + Mon Aug 6 18:41:12 2007 Koichi Sasada * lib/vm/instruction.rb (make_header_analysys): fix last commit. diff --git a/insnhelper.ci b/insnhelper.ci index e77a1449d3..952af15af4 100644 --- a/insnhelper.ci +++ b/insnhelper.ci @@ -15,6 +15,11 @@ /* control stack frame */ + +#ifndef INLINE +#define INLINE inline +#endif + static inline rb_control_frame_t * vm_push_frame(rb_thread_t *th, rb_iseq_t *iseq, VALUE type, VALUE self, VALUE specval, VALUE *pc, @@ -552,6 +557,36 @@ vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp, return val; } +static inline void +vm_send_optimize(rb_control_frame_t *reg_cfp, + NODE **mn, rb_num_t *flag, rb_num_t *num, ID *id, VALUE klass) +{ + if (*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; + } + } +} + /* yield */ static inline int @@ -723,6 +758,47 @@ vm_yield_setup_args(rb_thread_t *th, rb_iseq_t *iseq, } } +static VALUE +vm_invoke_block(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_num_t num, rb_num_t flag) +{ + VALUE val; + rb_block_t *block = GET_BLOCK_PTR(); + rb_iseq_t *iseq; + int argc = num; + + if (GET_ISEQ()->local_iseq->type != ISEQ_TYPE_METHOD || block == 0) { + vm_localjump_error("no block given (yield)", Qnil, 0); + } + iseq = block->iseq; + + if (BUILTIN_TYPE(iseq) != T_NODE) { + int opt_pc; + + argc = caller_setup_args(th, GET_CFP(), flag, argc, 0, 0); + + CHECK_STACK_OVERFLOW(GET_CFP(), iseq->stack_max); + + DEC_SP(argc); + opt_pc = vm_yield_setup_args(th, iseq, argc, GET_SP(), 0, + block_proc_is_lambda(block->proc)); + argc = iseq->arg_size; + INC_SP(argc); + + vm_push_frame(th, iseq, + FRAME_MAGIC_BLOCK, block->self, (VALUE) block->dfp, + iseq->iseq_encoded + opt_pc, GET_SP(), block->lfp, + iseq->local_size - argc); + + reg_cfp->sp -= argc; + return Qundef; + } + else { + val = vm_yield_with_cfunc(th, block, block->self, num, STACK_ADDR_FROM_TOP(num)); + POPN(num); /* TODO: should put before C/yield? */ + return val; + } +} + /* cref */ static NODE * @@ -835,6 +911,43 @@ get_cref(rb_iseq_t *iseq, VALUE *lfp) return cref; } +static inline VALUE +vm_getspecial(rb_thread_t *th, VALUE *lfp, VALUE key, rb_num_t type) +{ + VALUE val; + + if (type == 0) { + if (FIXNUM_P(key)) key = FIX2INT(key); + val = lfp_svar_get(th, lfp, key); + } + else { + VALUE backref = lfp_svar_get(th, lfp, 1); + + if (type & 0x01) { + switch (type >> 1) { + case '&': + val = rb_reg_last_match(backref); + break; + case '`': + val = rb_reg_match_pre(backref); + break; + case '\'': + val = rb_reg_match_post(backref); + break; + case '+': + val = rb_reg_match_last(backref); + break; + default: + rb_bug("unexpected back-ref"); + } + } + else { + val = rb_reg_nth_match(type >> 1, backref); + } + } + return val; +} + static inline VALUE vm_get_ev_const(rb_thread_t *th, rb_iseq_t *iseq, VALUE klass, ID id, int is_defined) @@ -984,8 +1097,8 @@ vm_method_search(VALUE id, VALUE klass, IC ic) return mn; } -static VALUE -vm_search_super_klass(VALUE klass, VALUE recv) +static inline VALUE +vm_search_normal_super_klass(VALUE klass, VALUE recv) { if (BUILTIN_TYPE(klass) == T_CLASS) { klass = RCLASS(klass)->super; @@ -1003,6 +1116,196 @@ vm_search_super_klass(VALUE klass, VALUE recv) return klass; } +static void +vm_search_super_klass(rb_control_frame_t *reg_cfp, rb_iseq_t *ip, VALUE recv, VALUE sigval, ID *idp, VALUE *klassp) +{ + ID id; + VALUE klass; + + 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 = vm_search_normal_super_klass(lcfp->method_klass, recv); + + if (sigval == Qfalse) { + /* zsuper */ + rb_raise(rb_eRuntimeError, "implicit argument passing of super from method defined by define_method() is not supported. Specify all arguments explicitly."); + } + } + else { + klass = vm_search_normal_super_klass(ip->klass, recv); + } + + *idp = id; + *klassp = klass; +} + +static VALUE +vm_throw(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_num_t throw_state, VALUE throwobj) +{ + rb_num_t state = throw_state & 0xff; + rb_num_t flag = throw_state & 0x8000; + rb_num_t level = throw_state >> 16; + + if (state != 0) { + VALUE *pt; + int i; + if (flag != 0) { + if (throw_state & 0x4000) { + pt = (void *)1; + } + else { + pt = 0; + } + } + else { + if (state == TAG_BREAK) { + rb_control_frame_t *cfp = GET_CFP(); + VALUE *dfp = GET_DFP(); + int is_orphan = 1; + rb_iseq_t *base_iseq = GET_ISEQ(); + + search_parent: + if (cfp->iseq->type != ISEQ_TYPE_BLOCK) { + dfp = GC_GUARDED_PTR_REF((VALUE *) *dfp); + base_iseq = base_iseq->parent_iseq; + + while ((VALUE *) cfp < th->stack + th->stack_size) { + if (cfp->dfp == dfp) { + goto search_parent; + } + cfp++; + } + rb_bug("VM (throw): can't find break base."); + } + + if (VM_FRAME_TYPE(cfp) == FRAME_MAGIC_LAMBDA) { + /* lambda{... break ...} */ + is_orphan = 0; + pt = dfp; + } + else { + dfp = GC_GUARDED_PTR_REF((VALUE *) *dfp); + + while ((VALUE *)cfp < th->stack + th->stack_size) { + if (cfp->dfp == dfp) { + VALUE epc = epc = cfp->pc - cfp->iseq->iseq_encoded; + rb_iseq_t *iseq = cfp->iseq; + int i; + + for (i=0; icatch_table_size; i++) { + struct iseq_catch_table_entry *entry = &iseq->catch_table[i]; + + if (entry->type == CATCH_TYPE_BREAK && + entry->start < epc && entry->end >= epc) { + if (entry->cont == epc) { + goto found; + } + else { + break; + } + } + } + break; + + found: + pt = dfp; + is_orphan = 0; + break; + } + cfp++; + } + } + + if (is_orphan) { + vm_localjump_error("break from proc-closure", throwobj, TAG_BREAK); + } + } + else if (state == TAG_RETRY) { + pt = GC_GUARDED_PTR_REF((VALUE *) * GET_DFP()); + for (i = 0; i < level; i++) { + pt = GC_GUARDED_PTR_REF((VALUE *) * pt); + } + } + else if (state == TAG_RETURN) { + rb_control_frame_t *cfp = GET_CFP(); + VALUE *dfp = GET_DFP(); + int is_orphan = 1; + + /** + * check orphan: + */ + while ((VALUE *) cfp < th->stack + th->stack_size) { + if (GET_DFP() == dfp) { + if (VM_FRAME_TYPE(cfp) == FRAME_MAGIC_LAMBDA) { + /* in lambda */ + is_orphan = 0; + break; + } + } + cfp++; + if (GET_LFP() == cfp->lfp && + cfp->iseq->type == ISEQ_TYPE_METHOD) { + is_orphan = 0; + break; + } + } + + if (is_orphan) { + vm_localjump_error("unexpected return", throwobj, TAG_RETURN); + } + + pt = GET_LFP(); + } + else { + rb_bug("isns(throw): unsupport throw type"); + } + } + th->state = state; + return (VALUE)NEW_THROW_OBJECT(throwobj, (VALUE) pt, state); + } + else { + /* continue throw */ + VALUE err = throwobj; + + if (FIXNUM_P(err)) { + th->state = FIX2INT(err); + } + else if (SYMBOL_P(err)) { + th->state = TAG_THROW; + } + else if (BUILTIN_TYPE(err) == T_NODE) { + th->state = GET_THROWOBJ_STATE(err); + } + else { + th->state = FIX2INT(rb_ivar_get(err, idThrowState)); + } + return err; + } +} + static void call_end_proc(VALUE data) { diff --git a/insnhelper.h b/insnhelper.h index f8439f7725..59536b2e7a 100644 --- a/insnhelper.h +++ b/insnhelper.h @@ -14,6 +14,9 @@ #define _INSNHELPER_H_INCLUDED_ #include "ruby/ruby.h" +#include "ruby/node.h" +#include "eval_intern.h" +#include "vm_core.h" #include "vm.h" /**********************************************************/ diff --git a/insns.def b/insns.def index 21c7368bfb..c235426748 100644 --- a/insns.def +++ b/insns.def @@ -84,35 +84,7 @@ getspecial () (VALUE val) { - if (type == 0) { - if (FIXNUM_P(key)) key = FIX2INT(key); - val = lfp_svar_get(th, GET_LFP(), key); - } - else { - VALUE backref = lfp_svar_get(th, GET_LFP(), 1); - - if (type & 0x01) { - switch (type >> 1) { - case '&': - val = rb_reg_last_match(backref); - break; - case '`': - val = rb_reg_match_pre(backref); - break; - case '\'': - val = rb_reg_match_post(backref); - break; - case '+': - val = rb_reg_match_last(backref); - break; - default: - rb_bug("unexpected back-ref"); - } - } - else { - val = rb_reg_nth_match(type >> 1, backref); - } - } + val = vm_getspecial(th, GET_LFP(), key, type); } /** @@ -930,7 +902,7 @@ defined ip = ip->parent_iseq; } if (ip) { - VALUE klass = vm_search_super_klass(ip->klass, GET_SELF()); + VALUE klass = vm_search_normal_super_klass(ip->klass, GET_SELF()); if (rb_method_boundp(klass, ip->defined_method_id, 0)) { expr_type = "super"; } @@ -1124,49 +1096,18 @@ send NODE *mn; VALUE recv, klass; rb_block_t *blockptr = 0; - rb_num_t num = caller_setup_args(th, GET_CFP(), op_flag, op_argc, blockiseq, &blockptr); + rb_num_t num = caller_setup_args(th, GET_CFP(), op_flag, op_argc, (rb_iseq_t *)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); - } - + recv = (flag & VM_CALL_FCALL_BIT) ? GET_SELF() : TOPN(num); klass = CLASS_OF(recv); - mn = vm_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; - } + if (flag & VM_CALL_SEND_BIT) { + vm_send_optimize(GET_CFP(), &mn, &flag, &num, &id, klass); } CALL_METHOD(num, blockptr, flag, id, mn, recv, klass); @@ -1183,58 +1124,15 @@ invokesuper (...) (VALUE val) // inc += - op_argc; { - 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; + rb_block_t *blockptr = !(op_flag & VM_CALL_ARGS_BLOCKARG_BIT) ? GET_BLOCK_PTR() : 0; + int num = caller_setup_args(th, GET_CFP(), op_flag, op_argc, blockiseq, &blockptr); VALUE recv, klass; - ID id; NODE *mn; - - if (!blockptr && !(flag & VM_CALL_ARGS_BLOCKARG_BIT)) { - blockptr = GET_BLOCK_PTR(); - } + ID id; + const VALUE flag = VM_CALL_SUPER_BIT | 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 = vm_search_super_klass(lcfp->method_klass, recv); - - if (TOPN(num) == Qfalse) { - /* zsuper */ - rb_raise(rb_eRuntimeError, "implicit argument passing of super from method defined by define_method() is not supported. Specify all arguments explicitly."); - } - } - else { - klass = vm_search_super_klass(ip->klass, recv); - } - - flag = VM_CALL_SUPER_BIT | VM_CALL_FCALL_BIT; + vm_search_super_klass(GET_CFP(), GET_ISEQ(), recv, TOPN(num), &id, &klass); mn = rb_method_node(klass, id); CALL_METHOD(num, blockptr, flag, id, mn, recv, klass); @@ -1251,42 +1149,10 @@ invokeblock (...) (VALUE val) // inc += 1 - num; { - rb_block_t *block = GET_BLOCK_PTR(); - rb_iseq_t *iseq; - int argc = num; - - if (GET_ISEQ()->local_iseq->type != ISEQ_TYPE_METHOD || block == 0) { - vm_localjump_error("no block given (yield)", Qnil, 0); - } - iseq = block->iseq; - - if (BUILTIN_TYPE(iseq) != T_NODE) { - int opt_pc; - - argc = caller_setup_args(th, GET_CFP(), flag, argc, 0, 0); - - CHECK_STACK_OVERFLOW(GET_CFP(), iseq->stack_max); - - DEC_SP(argc); - opt_pc = vm_yield_setup_args(th, iseq, argc, GET_SP(), 0, - block_proc_is_lambda(block->proc)); - argc = iseq->arg_size; - INC_SP(argc); - - vm_push_frame(th, iseq, - FRAME_MAGIC_BLOCK, block->self, (VALUE) block->dfp, - iseq->iseq_encoded + opt_pc, GET_SP(), block->lfp, - iseq->local_size - argc); - - reg_cfp->sp -= argc; + val = vm_invoke_block(th, GET_CFP(), num, flag); + if (val == Qundef) { RESTORE_REGS(); NEXT_INSN(); - /* unreachable */ - } - else { - val = vm_yield_with_cfunc(th, block, block->self, - num, STACK_ADDR_FROM_TOP(num)); - POPN(num); } } @@ -1347,147 +1213,8 @@ throw (VALUE throwobj) (VALUE val) { - rb_num_t state = throw_state & 0xff; - rb_num_t flag = throw_state & 0x8000; - rb_num_t level = throw_state >> 16; - val = Qnil; /* dummy */ - - if (state != 0) { - VALUE *pt; - int i; - if (flag != 0) { - if (throw_state & 0x4000) { - pt = (void *)1; - } - else { - pt = 0; - } - } - else { - if (state == TAG_BREAK) { - rb_control_frame_t *cfp = GET_CFP(); - VALUE *dfp = GET_DFP(); - int is_orphan = 1; - rb_iseq_t *base_iseq = GET_ISEQ(); - - INSN_LABEL(search_parent): - if (cfp->iseq->type != ISEQ_TYPE_BLOCK) { - dfp = GC_GUARDED_PTR_REF((VALUE *) *dfp); - base_iseq = base_iseq->parent_iseq; - - while ((VALUE *) cfp < th->stack + th->stack_size) { - if (cfp->dfp == dfp) { - goto INSN_LABEL(search_parent); - } - cfp++; - } - rb_bug("VM (throw): can't find break base."); - } - - if (VM_FRAME_TYPE(cfp) == FRAME_MAGIC_LAMBDA) { - /* lambda{... break ...} */ - is_orphan = 0; - pt = dfp; - } - else { - dfp = GC_GUARDED_PTR_REF((VALUE *) *dfp); - - while ((VALUE *)cfp < th->stack + th->stack_size) { - if (cfp->dfp == dfp) { - VALUE epc = epc = cfp->pc - cfp->iseq->iseq_encoded; - rb_iseq_t *iseq = cfp->iseq; - int i; - - for (i=0; icatch_table_size; i++) { - struct iseq_catch_table_entry *entry = &iseq->catch_table[i]; - - if (entry->type == CATCH_TYPE_BREAK && - entry->start < epc && entry->end >= epc) { - if (entry->cont == epc) { - goto INSN_LABEL(found); - } - else { - break; - } - } - } - break; - - INSN_LABEL(found): - - pt = dfp; - is_orphan = 0; - break; - } - cfp++; - } - } - - if (is_orphan) { - vm_localjump_error("break from proc-closure", throwobj, TAG_BREAK); - } - } - else if (state == TAG_RETRY) { - pt = GC_GUARDED_PTR_REF((VALUE *) * GET_DFP()); - for (i = 0; i < level; i++) { - pt = GC_GUARDED_PTR_REF((VALUE *) * pt); - } - } - else if (state == TAG_RETURN) { - rb_control_frame_t *cfp = GET_CFP(); - VALUE *dfp = GET_DFP(); - int is_orphan = 1; - - /** - * check orphan: - */ - while ((VALUE *) cfp < th->stack + th->stack_size) { - if (GET_DFP() == dfp) { - if (VM_FRAME_TYPE(cfp) == FRAME_MAGIC_LAMBDA) { - /* in lambda */ - is_orphan = 0; - break; - } - } - cfp++; - if (GET_LFP() == cfp->lfp && - cfp->iseq->type == ISEQ_TYPE_METHOD) { - is_orphan = 0; - break; - } - } - - if (is_orphan) { - vm_localjump_error("unexpected return", throwobj, TAG_RETURN); - } - - pt = GET_LFP(); - } - else { - rb_bug("isns(throw): unsupport throw type"); - } - } - th->state = state; - THROW_EXCEPTION(NEW_THROW_OBJECT(throwobj, (VALUE) pt, state)); - } - else { - /* continue throw */ - VALUE err = throwobj; - - if (FIXNUM_P(err)) { - th->state = FIX2INT(err); - } - else if (SYMBOL_P(err)) { - th->state = TAG_THROW; - } - else if (BUILTIN_TYPE(err) == T_NODE) { - th->state = GET_THROWOBJ_STATE(err); - } - else { - th->state = FIX2INT(rb_ivar_get(err, idThrowState)); - } - THROW_EXCEPTION(err); - } + val = vm_throw(th, GET_CFP(), throw_state, throwobj); + THROW_EXCEPTION(val); /* unreachable */ } @@ -1936,18 +1663,13 @@ opt_mod double y = RFLOAT(obj)->value; double div, mod; - /* copied from numeric.c#flodivmod */ -#if 0 && defined(HAVE_FMOD) && !__x86_64__ /* temporary */ - mod = fmod(x, y); - printf("-- %f %% %f = %f\n", x, y, mod); -#else { double z; modf(x / y, &z); mod = x - z * y; } -#endif + div = (x - mod) / y; if (y * mod < 0) { mod += y; diff --git a/vm.c b/vm.c index 62cce9b07a..48e738dcd3 100644 --- a/vm.c +++ b/vm.c @@ -13,7 +13,6 @@ #include "ruby/node.h" #include "ruby/st.h" #include "gc.h" -#include "eval_intern.h" #include "insnhelper.h" #include "insnhelper.ci" @@ -505,7 +504,7 @@ vm_call_super(rb_thread_t *th, int argc, const VALUE *argv) klass = RCLASS(klass)->super; if (klass == 0) { - klass = vm_search_super_klass(cfp->method_klass, recv); + klass = vm_search_normal_super_klass(cfp->method_klass, recv); } id = cfp->method_id; diff --git a/vm.h b/vm.h index c496e59df3..0104203892 100644 --- a/vm.h +++ b/vm.h @@ -18,6 +18,7 @@ typedef unsigned long rb_num_t; typedef unsigned long lindex_t; typedef unsigned long dindex_t; typedef rb_num_t GENTRY; +typedef rb_iseq_t *ISEQ; extern VALUE rb_cEnv; extern VALUE ruby_vm_global_state_version; diff --git a/vm_evalbody.ci b/vm_evalbody.ci index 3ac3fa5192..6e1b15d84b 100644 --- a/vm_evalbody.ci +++ b/vm_evalbody.ci @@ -26,8 +26,6 @@ #endif /* #define DECL_SC_REG(r, reg) VALUE reg_##r */ -typedef rb_iseq_t *ISEQ; - #if !OPT_CALL_THREADED_CODE VALUE vm_eval(rb_thread_t *th, VALUE initial) -- cgit v1.2.3