summaryrefslogtreecommitdiff
path: root/insnhelper.ci
diff options
context:
space:
mode:
authorko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2007-08-06 11:36:30 +0000
committerko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2007-08-06 11:36:30 +0000
commitae421c43dfda6e9a1e9af1edaa649a3de17ff07a (patch)
tree7f12a2d3d92ec0e7744f7104ed545b5f6fbb3a7e /insnhelper.ci
parent7e2b837a3939b0c7473728c12579dd8930c3cfaf (diff)
* 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
Diffstat (limited to 'insnhelper.ci')
-rw-r--r--insnhelper.ci307
1 files changed, 305 insertions, 2 deletions
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 *
@@ -836,6 +912,43 @@ get_cref(rb_iseq_t *iseq, VALUE *lfp)
}
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;
@@ -1004,6 +1117,196 @@ vm_search_super_klass(VALUE klass, VALUE recv)
}
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; i<iseq->catch_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)
{
rb_proc_call(data, rb_ary_new2(0));