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:
parent
7e2b837a39
commit
ae421c43df
7 changed files with 332 additions and 300 deletions
|
@ -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>
|
Mon Aug 6 18:41:12 2007 Koichi Sasada <ko1@atdot.net>
|
||||||
|
|
||||||
* lib/vm/instruction.rb (make_header_analysys): fix last commit.
|
* lib/vm/instruction.rb (make_header_analysys): fix last commit.
|
||||||
|
|
307
insnhelper.ci
307
insnhelper.ci
|
@ -15,6 +15,11 @@
|
||||||
|
|
||||||
/* control stack frame */
|
/* control stack frame */
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef INLINE
|
||||||
|
#define INLINE inline
|
||||||
|
#endif
|
||||||
|
|
||||||
static inline rb_control_frame_t *
|
static inline rb_control_frame_t *
|
||||||
vm_push_frame(rb_thread_t *th, rb_iseq_t *iseq, VALUE type,
|
vm_push_frame(rb_thread_t *th, rb_iseq_t *iseq, VALUE type,
|
||||||
VALUE self, VALUE specval, VALUE *pc,
|
VALUE self, VALUE specval, VALUE *pc,
|
||||||
|
@ -552,6 +557,36 @@ vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp,
|
||||||
return val;
|
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 */
|
/* yield */
|
||||||
|
|
||||||
static inline int
|
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 */
|
/* cref */
|
||||||
|
|
||||||
static NODE *
|
static NODE *
|
||||||
|
@ -835,6 +911,43 @@ get_cref(rb_iseq_t *iseq, VALUE *lfp)
|
||||||
return cref;
|
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
|
static inline VALUE
|
||||||
vm_get_ev_const(rb_thread_t *th, rb_iseq_t *iseq,
|
vm_get_ev_const(rb_thread_t *th, rb_iseq_t *iseq,
|
||||||
VALUE klass, ID id, int is_defined)
|
VALUE klass, ID id, int is_defined)
|
||||||
|
@ -984,8 +1097,8 @@ vm_method_search(VALUE id, VALUE klass, IC ic)
|
||||||
return mn;
|
return mn;
|
||||||
}
|
}
|
||||||
|
|
||||||
static VALUE
|
static inline VALUE
|
||||||
vm_search_super_klass(VALUE klass, VALUE recv)
|
vm_search_normal_super_klass(VALUE klass, VALUE recv)
|
||||||
{
|
{
|
||||||
if (BUILTIN_TYPE(klass) == T_CLASS) {
|
if (BUILTIN_TYPE(klass) == T_CLASS) {
|
||||||
klass = RCLASS(klass)->super;
|
klass = RCLASS(klass)->super;
|
||||||
|
@ -1003,6 +1116,196 @@ vm_search_super_klass(VALUE klass, VALUE recv)
|
||||||
return klass;
|
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
|
static void
|
||||||
call_end_proc(VALUE data)
|
call_end_proc(VALUE data)
|
||||||
{
|
{
|
||||||
|
|
|
@ -14,6 +14,9 @@
|
||||||
#define _INSNHELPER_H_INCLUDED_
|
#define _INSNHELPER_H_INCLUDED_
|
||||||
|
|
||||||
#include "ruby/ruby.h"
|
#include "ruby/ruby.h"
|
||||||
|
#include "ruby/node.h"
|
||||||
|
#include "eval_intern.h"
|
||||||
|
#include "vm_core.h"
|
||||||
#include "vm.h"
|
#include "vm.h"
|
||||||
|
|
||||||
/**********************************************************/
|
/**********************************************************/
|
||||||
|
|
310
insns.def
310
insns.def
|
@ -84,35 +84,7 @@ getspecial
|
||||||
()
|
()
|
||||||
(VALUE val)
|
(VALUE val)
|
||||||
{
|
{
|
||||||
if (type == 0) {
|
val = vm_getspecial(th, GET_LFP(), key, type);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -930,7 +902,7 @@ defined
|
||||||
ip = ip->parent_iseq;
|
ip = ip->parent_iseq;
|
||||||
}
|
}
|
||||||
if (ip) {
|
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)) {
|
if (rb_method_boundp(klass, ip->defined_method_id, 0)) {
|
||||||
expr_type = "super";
|
expr_type = "super";
|
||||||
}
|
}
|
||||||
|
@ -1124,49 +1096,18 @@ send
|
||||||
NODE *mn;
|
NODE *mn;
|
||||||
VALUE recv, klass;
|
VALUE recv, klass;
|
||||||
rb_block_t *blockptr = 0;
|
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;
|
rb_num_t flag = op_flag;
|
||||||
ID id = op_id;
|
ID id = op_id;
|
||||||
|
|
||||||
/* get receiver */
|
/* get receiver */
|
||||||
if (flag & VM_CALL_FCALL_BIT) {
|
recv = (flag & VM_CALL_FCALL_BIT) ? GET_SELF() : TOPN(num);
|
||||||
/* method(...) */
|
|
||||||
recv = GET_SELF();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
/* recv.method(...) */
|
|
||||||
recv = TOPN(num);
|
|
||||||
}
|
|
||||||
|
|
||||||
klass = CLASS_OF(recv);
|
klass = CLASS_OF(recv);
|
||||||
|
|
||||||
mn = vm_method_search(id, klass, ic);
|
mn = vm_method_search(id, klass, ic);
|
||||||
|
|
||||||
/* send/funcall optimization */
|
/* send/funcall optimization */
|
||||||
if ((flag & VM_CALL_SEND_BIT) && mn && nd_type(mn->nd_body) == NODE_CFUNC) {
|
if (flag & VM_CALL_SEND_BIT) {
|
||||||
NODE *node = mn->nd_body;
|
vm_send_optimize(GET_CFP(), &mn, &flag, &num, &id, klass);
|
||||||
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);
|
CALL_METHOD(num, blockptr, flag, id, mn, recv, klass);
|
||||||
|
@ -1183,58 +1124,15 @@ invokesuper
|
||||||
(...)
|
(...)
|
||||||
(VALUE val) // inc += - op_argc;
|
(VALUE val) // inc += - op_argc;
|
||||||
{
|
{
|
||||||
rb_block_t *blockptr = 0;
|
rb_block_t *blockptr = !(op_flag & VM_CALL_ARGS_BLOCKARG_BIT) ? GET_BLOCK_PTR() : 0;
|
||||||
VALUE flag = op_flag;
|
int num = caller_setup_args(th, GET_CFP(), op_flag, op_argc, blockiseq, &blockptr);
|
||||||
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;
|
VALUE recv, klass;
|
||||||
ID id;
|
|
||||||
NODE *mn;
|
NODE *mn;
|
||||||
|
ID id;
|
||||||
if (!blockptr && !(flag & VM_CALL_ARGS_BLOCKARG_BIT)) {
|
const VALUE flag = VM_CALL_SUPER_BIT | VM_CALL_FCALL_BIT;
|
||||||
blockptr = GET_BLOCK_PTR();
|
|
||||||
}
|
|
||||||
|
|
||||||
recv = GET_SELF();
|
recv = GET_SELF();
|
||||||
|
vm_search_super_klass(GET_CFP(), GET_ISEQ(), recv, TOPN(num), &id, &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_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;
|
|
||||||
mn = rb_method_node(klass, id);
|
mn = rb_method_node(klass, id);
|
||||||
|
|
||||||
CALL_METHOD(num, blockptr, flag, id, mn, recv, klass);
|
CALL_METHOD(num, blockptr, flag, id, mn, recv, klass);
|
||||||
|
@ -1251,42 +1149,10 @@ invokeblock
|
||||||
(...)
|
(...)
|
||||||
(VALUE val) // inc += 1 - num;
|
(VALUE val) // inc += 1 - num;
|
||||||
{
|
{
|
||||||
rb_block_t *block = GET_BLOCK_PTR();
|
val = vm_invoke_block(th, GET_CFP(), num, flag);
|
||||||
rb_iseq_t *iseq;
|
if (val == Qundef) {
|
||||||
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;
|
|
||||||
RESTORE_REGS();
|
RESTORE_REGS();
|
||||||
NEXT_INSN();
|
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 throwobj)
|
||||||
(VALUE val)
|
(VALUE val)
|
||||||
{
|
{
|
||||||
rb_num_t state = throw_state & 0xff;
|
val = vm_throw(th, GET_CFP(), throw_state, throwobj);
|
||||||
rb_num_t flag = throw_state & 0x8000;
|
THROW_EXCEPTION(val);
|
||||||
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);
|
|
||||||
}
|
|
||||||
/* unreachable */
|
/* unreachable */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1936,18 +1663,13 @@ opt_mod
|
||||||
double y = RFLOAT(obj)->value;
|
double y = RFLOAT(obj)->value;
|
||||||
double div, mod;
|
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;
|
double z;
|
||||||
|
|
||||||
modf(x / y, &z);
|
modf(x / y, &z);
|
||||||
mod = x - z * y;
|
mod = x - z * y;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
div = (x - mod) / y;
|
div = (x - mod) / y;
|
||||||
if (y * mod < 0) {
|
if (y * mod < 0) {
|
||||||
mod += y;
|
mod += y;
|
||||||
|
|
3
vm.c
3
vm.c
|
@ -13,7 +13,6 @@
|
||||||
#include "ruby/node.h"
|
#include "ruby/node.h"
|
||||||
#include "ruby/st.h"
|
#include "ruby/st.h"
|
||||||
#include "gc.h"
|
#include "gc.h"
|
||||||
#include "eval_intern.h"
|
|
||||||
|
|
||||||
#include "insnhelper.h"
|
#include "insnhelper.h"
|
||||||
#include "insnhelper.ci"
|
#include "insnhelper.ci"
|
||||||
|
@ -505,7 +504,7 @@ vm_call_super(rb_thread_t *th, int argc, const VALUE *argv)
|
||||||
klass = RCLASS(klass)->super;
|
klass = RCLASS(klass)->super;
|
||||||
|
|
||||||
if (klass == 0) {
|
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;
|
id = cfp->method_id;
|
||||||
|
|
1
vm.h
1
vm.h
|
@ -18,6 +18,7 @@ typedef unsigned long rb_num_t;
|
||||||
typedef unsigned long lindex_t;
|
typedef unsigned long lindex_t;
|
||||||
typedef unsigned long dindex_t;
|
typedef unsigned long dindex_t;
|
||||||
typedef rb_num_t GENTRY;
|
typedef rb_num_t GENTRY;
|
||||||
|
typedef rb_iseq_t *ISEQ;
|
||||||
|
|
||||||
extern VALUE rb_cEnv;
|
extern VALUE rb_cEnv;
|
||||||
extern VALUE ruby_vm_global_state_version;
|
extern VALUE ruby_vm_global_state_version;
|
||||||
|
|
|
@ -26,8 +26,6 @@
|
||||||
#endif
|
#endif
|
||||||
/* #define DECL_SC_REG(r, reg) VALUE reg_##r */
|
/* #define DECL_SC_REG(r, reg) VALUE reg_##r */
|
||||||
|
|
||||||
typedef rb_iseq_t *ISEQ;
|
|
||||||
|
|
||||||
#if !OPT_CALL_THREADED_CODE
|
#if !OPT_CALL_THREADED_CODE
|
||||||
VALUE
|
VALUE
|
||||||
vm_eval(rb_thread_t *th, VALUE initial)
|
vm_eval(rb_thread_t *th, VALUE initial)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue