ruby/vm_macro.def

326 строки
7.8 KiB
C

/* -*- c -*- */
/* do not use C++ style comment */
/* */
MACRO macro_eval_setup_send_arguments(num, blockptr, flag, blockiseq)
{
if (flag & VM_CALL_ARGS_BLOCKARG_BIT) {
rb_proc_t *po;
VALUE proc;
proc = TOPN(0);
if (proc != Qnil) {
if (!rb_obj_is_proc(proc)) {
proc = rb_check_convert_type(proc, T_DATA, "Proc", "to_proc");
if (!rb_obj_is_proc(proc)) {
rb_raise(rb_eTypeError,
"wrong argument type %s (expected Proc)",
rb_obj_classname(proc));
}
}
GetProcPtr(proc, po);
blockptr = &po->block;
RUBY_VM_GET_BLOCK_PTR_IN_CFP(reg_cfp)->proc = proc;
}
INC_SP(-1);
}
else if (blockiseq) {
blockptr = RUBY_VM_GET_BLOCK_PTR_IN_CFP(reg_cfp);
blockptr->iseq = blockiseq;
blockptr->proc = 0;
}
/* expand top of stack? */
if (flag & VM_CALL_ARGS_SPLAT_BIT) {
VALUE ary = TOPN(0);
VALUE *ptr, *dst;
int i;
VALUE tmp = rb_check_convert_type(ary, T_ARRAY, "Array", "to_splat");
if (NIL_P(tmp)) {
tmp = rb_ary_new3(1, ary);
}
ary = tmp;
ptr = RARRAY_PTR(ary);
dst = GET_SP() - 1;
for (i = 0; i < RARRAY_LEN(ary); i++) {
dst[i] = ptr[i];
}
num += i - 1;
INC_SP(i - 1);
}
}
MACRO macro_eval_invoke_cfunc(num, id, recv, klass, mn, blockptr)
{
EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, id, klass);
{
rb_control_frame_t *cfp =
push_frame(th, 0, FRAME_MAGIC_CFUNC,
recv, (VALUE) blockptr, 0, GET_SP(), 0, 1);
cfp->method_id = id;
cfp->method_klass = klass;
reg_cfp->sp -= num + 1;
val = call_cfunc(mn->nd_cfnc, recv, mn->nd_argc, num, reg_cfp->sp + 1);
if (reg_cfp != th->cfp + 1) {
SDR2(reg_cfp);
SDR2(th->cfp-5);
rb_bug("cfp consistency error - send");
th->cfp = reg_cfp;
}
pop_frame(th);
}
EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, recv, id, klass);
}
MACRO macro_eval_invoke_func(niseqval, recv, klass, blockptr, num)
{
rb_iseq_t *niseq;
VALUE *sp = GET_SP();
VALUE *rsp = sp - num - 1;
int opt_pc = 0, clear_local_size, i;
/* TODO: eliminate it */
GetISeqPtr(niseqval, niseq);
clear_local_size = niseq->local_size - num;
/* simple (only mandatory) arguments */
if (niseq->arg_simple) {
if (niseq->argc != num) {
rb_raise(rb_eArgError, "%d - wrong number of arguments (%lu for %d)",
0, (unsigned long)num, niseq->argc);
}
}
else {
/* optional arguments */
if (niseq->arg_opts) {
int iseq_argc = niseq->argc;
int opts = niseq->arg_opts - 1;
if (num < iseq_argc ||
(niseq->arg_rest == -1 && num > iseq_argc + opts)) {
if (0) {
printf("num: %lu, iseq_argc: %d, opts: %d\n",
(unsigned long)num, iseq_argc, opts);
}
rb_raise(rb_eArgError,
"%d - wrong number of arguments (%lu for %d)",
1, (unsigned long)num, iseq_argc);
}
if (0) printf("num: %lu, opts: %d, iseq_argc: %d\n",
(unsigned long)num, opts, iseq_argc);
if (num - iseq_argc < opts) {
opt_pc = niseq->arg_opt_tbl[num - iseq_argc];
sp += opts - (num - iseq_argc);
num += opts - (num - iseq_argc);
clear_local_size = niseq->local_size - (iseq_argc + opts);
}
else {
opt_pc = niseq->arg_opt_tbl[opts];
}
}
/* rest argument */
if (niseq->arg_rest != -1) {
int rest = niseq->arg_rest - 1 /* spec val */;
int pack_size = num - rest;
if (0) {
printf("num: %lu, rest: %d, ps: %d\n",
(unsigned long)num, rest, pack_size);
}
if (pack_size < 0) {
rb_raise(rb_eArgError,
"%d - wrong number of arguments (%lu for %d)",
2, (unsigned long)num, rest - niseq->arg_opts);
}
/*
* def m(x, y, z, *a) (rest: 3) =>
* x, y, z, a, b, c <SP> (num: 6, pack_size = 3)
* => x, y, z, [a,b,c] <SP> (num: 4)
*/
rsp[rest + 1] = rb_ary_new4(pack_size, &rsp[rest + 1]);
sp = &rsp[rest + 1 + 1];
num = rest + 1;
clear_local_size = niseq->local_size - (rest + 1);
}
/* block argument */
if (niseq->arg_block != -1) {
VALUE arg_block_val = Qnil;
if (!((num == niseq->arg_rest) ||
(niseq->arg_opts && num == niseq->argc + niseq->arg_opts - 1)
|| num == niseq->argc)) {
if (0) printf("num: %d, rest: %d, opts: %d, argc: %d\n",
num, niseq->arg_rest, niseq->arg_opts, niseq->argc);
rb_raise(rb_eArgError,
"%d - wrong number of arguments (%lu for %d)",
3, (unsigned long)num, niseq->argc);
}
if (blockptr) {
/* make Proc object */
if (blockptr->proc == 0) {
rb_proc_t *proc;
reg_cfp->sp = sp;
arg_block_val = th_make_proc(th, GET_CFP(), blockptr);
GetProcPtr(arg_block_val, proc);
blockptr = &proc->block;
}
else {
arg_block_val = blockptr->proc;
}
}
rsp[1 + niseq->arg_block - 1] = arg_block_val;
sp++;
clear_local_size--;
}
}
/* stack overflow check */
if (CHECK_STACK_OVERFLOW(th, GET_CFP(), niseq->stack_max + 0x100)) {
rb_exc_raise(sysstack_error);
}
for (i = 0; i < clear_local_size; i++) {
*sp++ = Qnil;
}
if (0 && (flag & VM_CALL_TAILCALL_BIT)) {
th->cfp++;
push_frame(th, niseq, FRAME_MAGIC_METHOD,
recv, (VALUE) blockptr,
niseq->iseq_encoded + opt_pc, sp, 0, 0);
}
else if (0 &&
(flag & VM_CALL_TAILRECURSION_BIT) && niseq == GET_ISEQ()) {
/* do nothing */
GET_CFP()->self = recv;
SET_LFP(sp);
SET_DFP(sp);
*sp++ = (VALUE) blockptr;
reg_cfp->sp = sp;
reg_cfp->bp = sp;
SET_PC(niseq->iseq_encoded + opt_pc);
}
else {
push_frame(th, niseq,
FRAME_MAGIC_METHOD, recv, (VALUE) blockptr,
niseq->iseq_encoded + opt_pc, sp, 0, 0);
reg_cfp->sp = rsp;
}
RESTORE_REGS();
}
MACRO macro_eval_invoke_method(recv, klass, id, num, mn, blockptr)
{
/* 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:{
macro_eval_invoke_func(node->nd_body, recv, klass,
blockptr, num);
NEXT_INSN();
}
case NODE_CFUNC:{
macro_eval_invoke_cfunc(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;
}
}
}
}