1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

* 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
This commit is contained in:
ko1 2007-08-06 11:36:30 +00:00
parent 7e2b837a39
commit ae421c43df
7 changed files with 332 additions and 300 deletions

View file

@ -1,3 +1,9 @@
Mon Aug 6 20:29:22 2007 Koichi Sasada <ko1@atdot.net>
* 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 <ko1@atdot.net>
* lib/vm/instruction.rb (make_header_analysys): fix last commit.

View file

@ -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; 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)
{

View file

@ -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"
/**********************************************************/

310
insns.def
View file

@ -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; 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 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;

3
vm.c
View file

@ -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;

1
vm.h
View file

@ -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;

View file

@ -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)