From 831e33c7809a92da6d14f0e518f960034c5dabd0 Mon Sep 17 00:00:00 2001 From: ko1 Date: Sun, 2 Nov 2014 23:14:21 +0000 Subject: * vm_core.h: change iseq parameter data structure. https://bugs.ruby-lang.org/issues/10440#change-49694 * change terminology `arg' to `param'. * move rb_iseq_t::arg_* to rb_iseq_t::param. * move rb_iseq_t::arg_size to rb_iseq_t::param::size. * move rb_iseq_t::argc to rb_iseq_t::param::lead_num. * move rb_iseq_t::arg_opts to rb_iseq_t::param::opt_num. * move rb_iseq_t::arg_rest to rb_iseq_t::param::rest_start. * move rb_iseq_t::arg_post_num to rb_iseq_t::param::post_num. * move rb_iseq_t::arg_post_start to rb_iseq_t::param::post_start. * move rb_iseq_t::arg_block to rb_iseq_t::param::block_start. * move rb_iseq_t::arg_keyword* to rb_iseq_t::param::keyword. rb_iseq_t::param::keyword is allocated only when keyword parameters are available. * introduce rb_iseq_t::param::flags to represent parameter availability. For example, rb_iseq_t::param::flags::has_kw represents that this iseq has keyword parameters and rb_iseq_t::param::keyword is allocated. We don't need to compare with -1 to check availability. * remove rb_iseq_t::arg_simple. * compile.c: catch up this change. * iseq.c: ditto. * proc.c: ditto. * vm.c, vm_args.c, vm_dump.c, vm_insnhelper.c: ditto. * iseq.c (iseq_data_to_ary): support keyword argument. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@48242 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 36 ++++++- compile.c | 323 +++++++++++++++++++++++++++----------------------------- iseq.c | 172 ++++++++++++++---------------- proc.c | 12 ++- vm.c | 2 +- vm_args.c | 60 +++++------ vm_core.h | 72 ++++++++----- vm_dump.c | 2 +- vm_insnhelper.c | 54 ++++++---- 9 files changed, 383 insertions(+), 350 deletions(-) diff --git a/ChangeLog b/ChangeLog index 3b29ce8b6c..7b082b43f7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,38 @@ -Mon Nov 3 03:39:04 2014 Koichi Sasada +Mon Nov 3 07:49:34 2014 Koichi Sasada + + * vm_core.h: change iseq parameter data structure. + https://bugs.ruby-lang.org/issues/10440#change-49694 + + * change terminology `arg' to `param'. + * move rb_iseq_t::arg_* to rb_iseq_t::param. + * move rb_iseq_t::arg_size to rb_iseq_t::param::size. + * move rb_iseq_t::argc to rb_iseq_t::param::lead_num. + * move rb_iseq_t::arg_opts to rb_iseq_t::param::opt_num. + * move rb_iseq_t::arg_rest to rb_iseq_t::param::rest_start. + * move rb_iseq_t::arg_post_num to rb_iseq_t::param::post_num. + * move rb_iseq_t::arg_post_start to rb_iseq_t::param::post_start. + * move rb_iseq_t::arg_block to rb_iseq_t::param::block_start. + * move rb_iseq_t::arg_keyword* to rb_iseq_t::param::keyword. + rb_iseq_t::param::keyword is allocated only when keyword + parameters are available. + * introduce rb_iseq_t::param::flags to represent parameter + availability. For example, rb_iseq_t::param::flags::has_kw + represents that this iseq has keyword parameters and + rb_iseq_t::param::keyword is allocated. + We don't need to compare with -1 to check availability. + * remove rb_iseq_t::arg_simple. + + * compile.c: catch up this change. + + * iseq.c: ditto. + + * proc.c: ditto. + + * vm.c, vm_args.c, vm_dump.c, vm_insnhelper.c: ditto. + + * iseq.c (iseq_data_to_ary): support keyword argument. + +xMon Nov 3 03:39:04 2014 Koichi Sasada * test/ruby/test_method.rb: r48239 makes this test green. diff --git a/compile.c b/compile.c index 860fe13759..c80bd55667 100644 --- a/compile.c +++ b/compile.c @@ -1076,8 +1076,9 @@ iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *optargs, NODE *node_args) } - iseq->argc = (int)args->pre_args_num; - debugs(" - argc: %d\n", iseq->argc); + iseq->param.lead_num = (int)args->pre_args_num; + if (iseq->param.lead_num > 0) iseq->param.flags.has_lead = TRUE; + debugs(" - argc: %d\n", iseq->param.lead_num); rest_id = args->rest_arg; if (rest_id == 1) { @@ -1087,8 +1088,9 @@ iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *optargs, NODE *node_args) block_id = args->block_arg; if (args->first_post_arg) { - iseq->arg_post_start = get_dyna_var_idx_at_raw(iseq, args->first_post_arg); - iseq->arg_post_num = args->post_args_num; + iseq->param.post_start = get_dyna_var_idx_at_raw(iseq, args->first_post_arg); + iseq->param.post_num = args->post_args_num; + iseq->param.flags.has_post = TRUE; } if (args->opt_args) { @@ -1112,16 +1114,15 @@ iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *optargs, NODE *node_args) ADD_LABEL(optargs, label); i += 1; - iseq->arg_opts = i; - iseq->arg_opt_table = ALLOC_N(VALUE, i); - MEMCPY(iseq->arg_opt_table, RARRAY_CONST_PTR(labels), VALUE, i); + iseq->param.opt_num = i; + iseq->param.opt_table = ALLOC_N(VALUE, i); + MEMCPY(iseq->param.opt_table, RARRAY_CONST_PTR(labels), VALUE, i); for (j = 0; j < i; j++) { - iseq->arg_opt_table[j] &= ~1; + iseq->param.opt_table[j] &= ~1; } rb_ary_clear(labels); - } - else { - iseq->arg_opts = 0; + + iseq->param.flags.has_opt = TRUE; } if (args->kw_args) { @@ -1130,7 +1131,9 @@ iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *optargs, NODE *node_args) const VALUE complex_mark = rb_str_tmp_new(0); int kw = 0, rkw = 0, di = 0, i; - iseq->arg_keyword_bits = get_dyna_var_idx_at_raw(iseq, args->kw_rest_arg->nd_vid); + iseq->param.flags.has_kw = TRUE; + iseq->param.keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1); + iseq->param.keyword->bits_start = get_dyna_var_idx_at_raw(iseq, args->kw_rest_arg->nd_vid); while (node) { NODE *val_node = node->nd_body->nd_value; @@ -1152,7 +1155,7 @@ iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *optargs, NODE *node_args) dv = complex_mark; } - iseq->arg_keyword_num = ++di; + iseq->param.keyword->num = ++di; rb_ary_push(default_values, dv); } @@ -1160,25 +1163,26 @@ iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *optargs, NODE *node_args) node = node->nd_next; } - iseq->arg_keyword_num = kw; - iseq->arg_keyword_rest = args->kw_rest_arg->nd_cflag != 0 ? get_dyna_var_idx_at_raw(iseq, args->kw_rest_arg->nd_cflag) : -1; - iseq->arg_keyword_required = rkw; - iseq->arg_keyword_table = &iseq->local_table[iseq->arg_keyword_bits - iseq->arg_keyword_num]; - iseq->arg_keyword_default_values = ALLOC_N(VALUE, RARRAY_LEN(default_values)); + iseq->param.keyword->num = kw; + + if (args->kw_rest_arg->nd_cflag != 0) { + iseq->param.keyword->rest_start = get_dyna_var_idx_at_raw(iseq, args->kw_rest_arg->nd_cflag); + iseq->param.flags.has_kwrest = TRUE; + } + iseq->param.keyword->required_num = rkw; + iseq->param.keyword->table = &iseq->local_table[iseq->param.keyword->bits_start - iseq->param.keyword->num]; + iseq->param.keyword->default_values = ALLOC_N(VALUE, RARRAY_LEN(default_values)); for (i = 0; i < RARRAY_LEN(default_values); i++) { VALUE dv = RARRAY_AREF(default_values, i); if (dv == complex_mark) dv = Qundef; - iseq->arg_keyword_default_values[i] = dv; + iseq->param.keyword->default_values[i] = dv; } } else if (args->kw_rest_arg) { - iseq->arg_keyword_bits = -1; - iseq->arg_keyword_rest = get_dyna_var_idx_at_raw(iseq, args->kw_rest_arg->nd_vid); - } - else { - iseq->arg_keyword_bits = -1; - iseq->arg_keyword_rest = -1; + iseq->param.flags.has_kwrest = TRUE; + iseq->param.keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1); + iseq->param.keyword->rest_start = get_dyna_var_idx_at_raw(iseq, args->kw_rest_arg->nd_vid); } if (args->pre_init) { /* m_init */ @@ -1189,76 +1193,67 @@ iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *optargs, NODE *node_args) } if (rest_id) { - iseq->arg_rest = get_dyna_var_idx_at_raw(iseq, rest_id); + iseq->param.rest_start = get_dyna_var_idx_at_raw(iseq, rest_id); + iseq->param.flags.has_rest = TRUE; + assert(iseq->param.rest_start != -1); - if (iseq->arg_rest == -1) { - rb_bug("arg_rest: -1"); - } - - if (iseq->arg_post_start == 0) { - iseq->arg_post_start = iseq->arg_rest + 1; + if (iseq->param.post_start == 0) { /* TODO: why that? */ + iseq->param.post_start = iseq->param.rest_start + 1; } } if (block_id) { - iseq->arg_block = get_dyna_var_idx_at_raw(iseq, block_id); + iseq->param.block_start = get_dyna_var_idx_at_raw(iseq, block_id); + iseq->param.flags.has_block = TRUE; } - if (iseq->arg_opts != 0 || - iseq->arg_post_num != 0 || - iseq->arg_rest != -1 || - iseq->arg_block != -1 || - iseq->arg_keyword_bits != -1 || - iseq->arg_keyword_rest != -1) { - iseq->arg_simple = 0; + if (iseq->param.flags.has_opt || + iseq->param.flags.has_post || + iseq->param.flags.has_rest || + iseq->param.flags.has_block || + iseq->param.flags.has_kw || + iseq->param.flags.has_kwrest) { - /* set arg_size: size of arguments */ - if (iseq->arg_block != -1) { - iseq->arg_size = iseq->arg_block + 1; + if (iseq->param.flags.has_block) { + iseq->param.size = iseq->param.block_start + 1; } - else if (iseq->arg_keyword_rest != -1) { - iseq->arg_size = iseq->arg_keyword_rest + 1; + else if (iseq->param.flags.has_kwrest) { + iseq->param.size = iseq->param.keyword->rest_start + 1; } - else if (iseq->arg_keyword_bits != -1) { - iseq->arg_size = iseq->arg_keyword_bits + 1; + else if (iseq->param.flags.has_kw) { + iseq->param.size = iseq->param.keyword->bits_start + 1; } - else if (iseq->arg_post_num) { - iseq->arg_size = iseq->arg_post_start + iseq->arg_post_num; + else if (iseq->param.flags.has_post) { + iseq->param.size = iseq->param.post_start + iseq->param.post_num; } - else if (iseq->arg_rest != -1) { - iseq->arg_size = iseq->arg_rest + 1; + else if (iseq->param.flags.has_rest) { + iseq->param.size = iseq->param.rest_start + 1; } - else if (iseq->arg_opts) { - iseq->arg_size = iseq->argc + iseq->arg_opts - 1; + else if (iseq->param.flags.has_opt) { + iseq->param.size = iseq->param.lead_num + iseq->param.opt_num - 1; } else { - iseq->arg_size = iseq->argc; + rb_bug("unreachable"); } } else { - iseq->arg_simple = 1; - iseq->arg_size = iseq->argc; + iseq->param.size = iseq->param.lead_num; } if (iseq->type == ISEQ_TYPE_BLOCK) { - if (iseq->arg_opts == 0 && - iseq->arg_post_num == 0 && - iseq->arg_rest == -1 && - iseq->arg_keyword_bits == -1 && - iseq->arg_keyword_rest == -1) { - - /* TODO: why not check block? */ + if (iseq->param.flags.has_opt == FALSE && + iseq->param.flags.has_post == FALSE && + iseq->param.flags.has_rest == FALSE && + iseq->param.flags.has_kw == FALSE && + iseq->param.flags.has_kwrest == FALSE) { - if (iseq->argc == 1 && last_comma == 0) { + if (iseq->param.lead_num == 1 && last_comma == 0) { /* {|a|} */ - iseq->arg_simple |= 0x02; + iseq->param.flags.ambiguous_param0 = TRUE; } } } } - else { - iseq->arg_simple = 1; - } return COMPILE_OK; } @@ -1691,10 +1686,9 @@ iseq_set_optargs_table(rb_iseq_t *iseq) { int i; - if (iseq->arg_opts != 0) { - for (i = 0; i < iseq->arg_opts; i++) { - iseq->arg_opt_table[i] = - label_get_position((LABEL *)iseq->arg_opt_table[i]); + if (iseq->param.flags.has_opt) { + for (i = 0; i < iseq->param.opt_num; i++) { + iseq->param.opt_table[i] = label_get_position((LABEL *)iseq->param.opt_table[i]); } } return COMPILE_OK; @@ -4490,95 +4484,91 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped) rb_iseq_t *liseq = iseq->local_iseq; int lvar_level = get_lvar_level(iseq); - argc = liseq->argc; + argc = liseq->param.lead_num; /* normal arguments */ - for (i = 0; i < liseq->argc; i++) { + for (i = 0; i < liseq->param.lead_num; i++) { int idx = liseq->local_size - i; ADD_INSN2(args, line, getlocal, INT2FIX(idx), INT2FIX(lvar_level)); } - if (!liseq->arg_simple) { - if (liseq->arg_opts) { - /* optional arguments */ - int j; - for (j = 0; j < liseq->arg_opts - 1; j++) { - int idx = liseq->local_size - (i + j); - ADD_INSN2(args, line, getlocal, INT2FIX(idx), INT2FIX(lvar_level)); - } - i += j; - argc = i; - } - - if (liseq->arg_rest != -1) { - /* rest argument */ - int idx = liseq->local_size - liseq->arg_rest; + if (liseq->param.flags.has_opt) { + /* optional arguments */ + int j; + for (j = 0; j < liseq->param.opt_num - 1; j++) { + int idx = liseq->local_size - (i + j); ADD_INSN2(args, line, getlocal, INT2FIX(idx), INT2FIX(lvar_level)); - argc = liseq->arg_rest + 1; - flag |= VM_CALL_ARGS_SPLAT; } + i += j; + argc = i; + } + if (liseq->param.flags.has_rest) { + /* rest argument */ + int idx = liseq->local_size - liseq->param.rest_start; + ADD_INSN2(args, line, getlocal, INT2FIX(idx), INT2FIX(lvar_level)); + argc = liseq->param.rest_start + 1; + flag |= VM_CALL_ARGS_SPLAT; + } + if (liseq->param.flags.has_post) { + /* post arguments */ + int post_len = liseq->param.post_num; + int post_start = liseq->param.post_start; - if (liseq->arg_post_num > 0) { - /* post arguments */ - int post_len = liseq->arg_post_num; - int post_start = liseq->arg_post_start; - - if (liseq->arg_rest != -1) { - int j; - for (j=0; jlocal_size - (post_start + j); - ADD_INSN2(args, line, getlocal, INT2FIX(idx), INT2FIX(lvar_level)); - } - ADD_INSN1(args, line, newarray, INT2FIX(j)); - ADD_INSN (args, line, concatarray); - /* argc is settled at above */ + if (liseq->param.flags.has_rest) { + int j; + for (j=0; jlocal_size - (post_start + j); + ADD_INSN2(args, line, getlocal, INT2FIX(idx), INT2FIX(lvar_level)); } - else { - int j; - for (j=0; jlocal_size - (post_start + j); - ADD_INSN2(args, line, getlocal, INT2FIX(idx), INT2FIX(lvar_level)); - } - argc = post_len + post_start; + ADD_INSN1(args, line, newarray, INT2FIX(j)); + ADD_INSN (args, line, concatarray); + /* argc is settled at above */ + } + else { + int j; + for (j=0; jlocal_size - (post_start + j); + ADD_INSN2(args, line, getlocal, INT2FIX(idx), INT2FIX(lvar_level)); } + argc = post_len + post_start; } + } - if (liseq->arg_keyword_bits >= 0) { /* TODO: support keywords */ - int local_size = liseq->local_size; - argc++; + if (liseq->param.flags.has_kw) { /* TODO: support keywords */ + int local_size = liseq->local_size; + argc++; - ADD_INSN1(args, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE)); + ADD_INSN1(args, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE)); - if (liseq->arg_keyword_rest > 0) { - ADD_INSN2(args, line, getlocal, INT2FIX(liseq->local_size - liseq->arg_keyword_rest), INT2FIX(lvar_level)); - ADD_SEND (args, line, rb_intern("dup"), INT2FIX(0)); - } - else { - ADD_INSN1(args, line, newhash, INT2FIX(0)); - } - for (i = 0; i < liseq->arg_keyword_num; ++i) { - ID id = liseq->arg_keyword_table[i]; - int idx = local_size - get_local_var_idx(liseq, id); - ADD_INSN1(args, line, putobject, ID2SYM(id)); - ADD_INSN2(args, line, getlocal, INT2FIX(idx), INT2FIX(lvar_level)); - } - ADD_SEND(args, line, id_core_hash_merge_ptr, INT2FIX(i * 2 + 1)); - if (liseq->arg_rest != -1) { - ADD_INSN1(args, line, newarray, INT2FIX(1)); - ADD_INSN (args, line, concatarray); - --argc; - } - } - else if (liseq->arg_keyword_rest >= 0) { - ADD_INSN2(args, line, getlocal, INT2FIX(liseq->local_size - liseq->arg_keyword_rest), INT2FIX(lvar_level)); + if (liseq->param.flags.has_kwrest) { + ADD_INSN2(args, line, getlocal, INT2FIX(liseq->local_size - liseq->param.keyword->rest_start), INT2FIX(lvar_level)); ADD_SEND (args, line, rb_intern("dup"), INT2FIX(0)); - if (liseq->arg_rest != -1) { - ADD_INSN1(args, line, newarray, INT2FIX(1)); - ADD_INSN (args, line, concatarray); - } - else { - argc++; - } + } + else { + ADD_INSN1(args, line, newhash, INT2FIX(0)); + } + for (i = 0; i < liseq->param.keyword->num; ++i) { + ID id = liseq->param.keyword->table[i]; + int idx = local_size - get_local_var_idx(liseq, id); + ADD_INSN1(args, line, putobject, ID2SYM(id)); + ADD_INSN2(args, line, getlocal, INT2FIX(idx), INT2FIX(lvar_level)); + } + ADD_SEND(args, line, id_core_hash_merge_ptr, INT2FIX(i * 2 + 1)); + if (liseq->param.flags.has_rest) { + ADD_INSN1(args, line, newarray, INT2FIX(1)); + ADD_INSN (args, line, concatarray); + --argc; + } + } + else if (liseq->param.flags.has_kwrest) { + ADD_INSN2(args, line, getlocal, INT2FIX(liseq->local_size - liseq->param.keyword->rest_start), INT2FIX(lvar_level)); + ADD_SEND (args, line, rb_intern("dup"), INT2FIX(0)); + if (liseq->param.flags.has_rest) { + ADD_INSN1(args, line, newarray, INT2FIX(1)); + ADD_INSN (args, line, concatarray); + } + else { + argc++; } } } @@ -5303,8 +5293,8 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped) * kw = default_value * end */ - int kw_bits_idx = iseq->local_size - iseq->arg_keyword_bits; - int keyword_idx = iseq->arg_keyword_num; + int kw_bits_idx = iseq->local_size - iseq->param.keyword->bits_start; + int keyword_idx = iseq->param.keyword->num; ADD_INSN2(ret, line, checkkeyword, INT2FIX(kw_bits_idx), INT2FIX(keyword_idx)); ADD_INSNL(ret, line, branchif, end_label); @@ -5889,8 +5879,8 @@ rb_iseq_build_from_ary(rb_iseq_t *iseq, VALUE locals, VALUE args, /* args */ if (FIXNUM_P(args)) { - iseq->arg_size = iseq->argc = FIX2INT(args); - iseq->arg_simple = 1; + iseq->param.size = iseq->param.lead_num = FIX2INT(args); + iseq->param.flags.has_lead = TRUE; } else { int i = 0; @@ -5900,36 +5890,31 @@ rb_iseq_build_from_ary(rb_iseq_t *iseq, VALUE locals, VALUE args, VALUE arg_post_start = CHECK_INTEGER(rb_ary_entry(args, i++)); VALUE arg_rest = CHECK_INTEGER(rb_ary_entry(args, i++)); VALUE arg_block = CHECK_INTEGER(rb_ary_entry(args, i++)); - VALUE arg_simple = CHECK_INTEGER(rb_ary_entry(args, i++)); - iseq->argc = FIX2INT(argc); - iseq->arg_rest = FIX2INT(arg_rest); - iseq->arg_post_num = FIX2INT(arg_post_num); - iseq->arg_post_start = FIX2INT(arg_post_start); - iseq->arg_block = FIX2INT(arg_block); - iseq->arg_opts = RARRAY_LENINT(arg_opt_labels); - iseq->arg_opt_table = (VALUE *)ALLOC_N(VALUE, iseq->arg_opts); + iseq->param.lead_num = FIX2INT(argc); + iseq->param.rest_start = FIX2INT(arg_rest); + iseq->param.post_num = FIX2INT(arg_post_num); + iseq->param.post_start = FIX2INT(arg_post_start); + iseq->param.block_start = FIX2INT(arg_block); + iseq->param.opt_num = RARRAY_LENINT(arg_opt_labels); + iseq->param.opt_table = (VALUE *)ALLOC_N(VALUE, iseq->param.opt_num); - if (iseq->arg_block != -1) { - iseq->arg_size = iseq->arg_block + 1; + if (iseq->param.flags.has_block) { + iseq->param.size = iseq->param.block_start + 1; } - else if (iseq->arg_post_num) { - iseq->arg_size = iseq->arg_post_start + iseq->arg_post_num; + else if (iseq->param.flags.has_post) { + iseq->param.size = iseq->param.post_start + iseq->param.post_num; } - else if (iseq->arg_rest != -1) { - iseq->arg_size = iseq->arg_rest + 1; + else if (iseq->param.flags.has_rest) { + iseq->param.size = iseq->param.rest_start + 1; } else { - iseq->arg_size = iseq->argc + (iseq->arg_opts ? iseq->arg_opts - 1 : 0); + iseq->param.size = iseq->param.lead_num + (iseq->param.opt_num - (iseq->param.flags.has_opt == TRUE)); } for (i=0; iarg_opt_table[i] = - (VALUE)register_label(iseq, labels_table, - rb_ary_entry(arg_opt_labels, i)); + iseq->param.opt_table[i] = (VALUE)register_label(iseq, labels_table, rb_ary_entry(arg_opt_labels, i)); } - - iseq->arg_simple = NUM2INT(arg_simple); } /* exception */ diff --git a/iseq.c b/iseq.c index 4af1426a54..6f5ac8b6cd 100644 --- a/iseq.c +++ b/iseq.c @@ -23,7 +23,7 @@ #include "insns_info.inc" #define ISEQ_MAJOR_VERSION 2 -#define ISEQ_MINOR_VERSION 1 +#define ISEQ_MINOR_VERSION 2 VALUE rb_cISeq; @@ -87,7 +87,8 @@ iseq_free(void *ptr) } RUBY_FREE_UNLESS_NULL(iseq->callinfo_entries); RUBY_FREE_UNLESS_NULL(iseq->catch_table); - RUBY_FREE_UNLESS_NULL(iseq->arg_opt_table); + RUBY_FREE_UNLESS_NULL(iseq->param.opt_table); + RUBY_FREE_UNLESS_NULL(iseq->param.keyword); compile_data_free(iseq->compile_data); RUBY_FREE_UNLESS_NULL(iseq->iseq); } @@ -142,7 +143,7 @@ iseq_memsize(const void *ptr) if (iseq->catch_table) { size += iseq_catch_table_bytes(iseq->catch_table->size); } - size += iseq->arg_opts * sizeof(VALUE); + size += iseq->param.opt_num * sizeof(VALUE); size += iseq->is_size * sizeof(union iseq_inline_storage_entry); size += iseq->callinfo_size * sizeof(rb_call_info_t); @@ -262,32 +263,19 @@ prepare_iseq_build(rb_iseq_t *iseq, const rb_compile_option_t *option) { iseq->type = type; - iseq->arg_rest = -1; - iseq->arg_block = -1; - iseq->arg_keyword_bits = -1; - iseq->arg_keyword_rest = -1; RB_OBJ_WRITE(iseq->self, &iseq->klass, 0); set_relation(iseq, parent); name = rb_fstring(name); path = rb_fstring(path); - if (RTEST(absolute_path)) - absolute_path = rb_fstring(absolute_path); - + if (RTEST(absolute_path)) absolute_path = rb_fstring(absolute_path); iseq_location_setup(iseq, path, absolute_path, name, first_lineno); if (iseq != iseq->local_iseq) { RB_OBJ_WRITE(iseq->self, &iseq->location.base_label, iseq->local_iseq->location.label); } - iseq->defined_method_id = 0; RB_OBJ_WRITE(iseq->self, &iseq->mark_ary, 0); - /* - * iseq->special_block_builder = GC_GUARDED_PTR_REF(block_opt); - * iseq->cached_special_block_builder = 0; - * iseq->cached_special_block = 0; - */ - iseq->compile_data = ZALLOC(struct iseq_compile_data); RB_OBJ_WRITE(iseq->self, &iseq->compile_data->err_info, Qnil); RB_OBJ_WRITE(iseq->self, &iseq->compile_data->mark_ary, rb_ary_tmp_new(3)); @@ -1056,14 +1044,8 @@ VALUE iseq_data_to_ary(rb_iseq_t *iseq); * An array containing the names of all arguments and local variables as * symbols. * - * [args] - * The arity if the method or block only has required arguments. - * - * Otherwise an array of: - * - * [required_argc, [optional_arg_labels, ...], - * splat_index, post_splat_argc, post_splat_index, - * block_index, simple] + * [params] + * An Hash object containing parameter information. * * More info about these values can be found in +vm_core.h+. * @@ -1075,6 +1057,8 @@ VALUE iseq_data_to_ary(rb_iseq_t *iseq); * An array of arrays containing the instruction names and operands that * make up the body of the instruction sequence. * + * Note that this format is MRI specific and version dependent. + * */ static VALUE iseq_to_a(VALUE self) @@ -1384,7 +1368,7 @@ catch_type(int type) VALUE rb_iseq_disasm(VALUE self) { - rb_iseq_t *iseqdat = iseq_check(self); + rb_iseq_t *iseqdat = iseq_check(self); /* TODO: rename to iseq */ VALUE *iseq; VALUE str = rb_str_new(0, 0); VALUE child = rb_ary_new(); @@ -1433,13 +1417,16 @@ rb_iseq_disasm(VALUE self) if (tbl) { rb_str_catf(str, "local table (size: %d, argc: %d " - "[opts: %d, rest: %d, post: %d, block: %d, kw: %d@%d, kwrest: %d] s%d)\n", - iseqdat->local_size, iseqdat->argc, - iseqdat->arg_opts, iseqdat->arg_rest, - iseqdat->arg_post_num, iseqdat->arg_block, - iseqdat->arg_keyword_num, iseqdat->local_size - iseqdat->arg_keyword_bits, - iseqdat->arg_keyword_rest, - iseqdat->arg_simple); + "[opts: %d, rest: %d, post: %d, block: %d, kw: %d@%d, kwrest: %d])\n", + iseqdat->local_size, + iseqdat->param.lead_num, + iseqdat->param.opt_num - (iseqdat->param.flags.has_opt == TRUE), + iseqdat->param.flags.has_rest ? iseqdat->param.rest_start : -1, + iseqdat->param.post_num, + iseqdat->param.flags.has_block ? iseqdat->param.block_start : -1, + iseqdat->param.flags.has_kw ? iseqdat->param.keyword->num : -1, + iseqdat->param.flags.has_kw ? iseqdat->param.keyword->required_num : -1, + iseqdat->param.flags.has_kwrest ? iseqdat->param.keyword->rest_start : -1); for (i = 0; i < iseqdat->local_table_size; i++) { long width; @@ -1447,22 +1434,21 @@ rb_iseq_disasm(VALUE self) char argi[0x100] = ""; char opti[0x100] = ""; - if (iseqdat->arg_opts) { - int argc = iseqdat->argc; - int opts = iseqdat->arg_opts; + if (iseqdat->param.flags.has_opt) { + int argc = iseqdat->param.lead_num; + int opts = iseqdat->param.opt_num; if (i >= argc && i < argc + opts - 1) { snprintf(opti, sizeof(opti), "Opt=%"PRIdVALUE, - iseqdat->arg_opt_table[i - argc]); + iseqdat->param.opt_table[i - argc]); } } snprintf(argi, sizeof(argi), "%s%s%s%s%s", /* arg, opts, rest, post block */ - iseqdat->argc > i ? "Arg" : "", + iseqdat->param.lead_num > i ? "Arg" : "", opti, - iseqdat->arg_rest == i ? "Rest" : "", - (iseqdat->arg_post_start <= i && - i < iseqdat->arg_post_start + iseqdat->arg_post_num) ? "Post" : "", - iseqdat->arg_block == i ? "Block" : ""); + (iseqdat->param.flags.has_rest && iseqdat->param.rest_start == i) ? "Rest" : "", + (iseqdat->param.flags.has_post && iseqdat->param.post_start <= i && i < iseqdat->param.post_start + iseqdat->param.post_num) ? "Post" : "", + (iseqdat->param.flags.has_block && iseqdat->param.block_start == i) ? "Block" : ""); rb_str_catf(str, "[%2d] ", iseqdat->local_size - i); width = RSTRING_LEN(str) + 11; @@ -1669,7 +1655,7 @@ iseq_data_to_ary(rb_iseq_t *iseq) VALUE val = rb_ary_new(); VALUE type; /* Symbol */ VALUE locals = rb_ary_new(); - VALUE args = rb_ary_new(); + VALUE params = rb_hash_new(); VALUE body = rb_ary_new(); /* [[:insn1, ...], ...] */ VALUE nbody; VALUE exception = rb_ary_new(); /* [[....]] */ @@ -1729,39 +1715,39 @@ iseq_data_to_ary(rb_iseq_t *iseq) } } - /* args */ + /* params */ { - /* - * [argc, # argc - * [label1, label2, ...] # opts - * rest index, - * post_len - * post_start - * block index, - * simple, - * ] - */ VALUE arg_opt_labels = rb_ary_new(); int j; - for (j=0; jarg_opts; j++) { - rb_ary_push(arg_opt_labels, - register_label(labels_table, iseq->arg_opt_table[j])); + for (j=0; jparam.opt_num; j++) { + rb_ary_push(arg_opt_labels, register_label(labels_table, iseq->param.opt_table[j])); } /* commit */ - if (iseq->arg_simple == 1) { - args = INT2FIX(iseq->argc); - } - else { - rb_ary_push(args, INT2FIX(iseq->argc)); - rb_ary_push(args, arg_opt_labels); - rb_ary_push(args, INT2FIX(iseq->arg_post_num)); - rb_ary_push(args, INT2FIX(iseq->arg_post_start)); - rb_ary_push(args, INT2FIX(iseq->arg_rest)); - rb_ary_push(args, INT2FIX(iseq->arg_block)); - rb_ary_push(args, INT2FIX(iseq->arg_simple)); + if (iseq->param.flags.has_lead) rb_hash_aset(params, ID2SYM(rb_intern("lead_num")), INT2FIX(iseq->param.lead_num)); + if (iseq->param.flags.has_opt) rb_hash_aset(params, ID2SYM(rb_intern("opt")), arg_opt_labels); + if (iseq->param.flags.has_post) rb_hash_aset(params, ID2SYM(rb_intern("post_num")), INT2FIX(iseq->param.post_num)); + if (iseq->param.flags.has_post) rb_hash_aset(params, ID2SYM(rb_intern("post_start")), INT2FIX(iseq->param.post_start)); + if (iseq->param.flags.has_rest) rb_hash_aset(params, ID2SYM(rb_intern("rest_start")), INT2FIX(iseq->param.rest_start)); + if (iseq->param.flags.has_block) rb_hash_aset(params, ID2SYM(rb_intern("block_start")), INT2FIX(iseq->param.block_start)); + if (iseq->param.flags.has_kw) { + VALUE keywords = rb_ary_new(); + int i, j; + for (i=0; iparam.keyword->required_num; i++) { + rb_ary_push(keywords, ID2SYM(iseq->param.keyword->table[i])); + } + for (j=0; iparam.keyword->num; i++, j++) { + VALUE key = rb_ary_new_from_args(1, ID2SYM(iseq->param.keyword->table[i])); + if (iseq->param.keyword->default_values[j] != Qundef) { + rb_ary_push(key, iseq->param.keyword->default_values[j]); + } + rb_ary_push(keywords, key); + } + rb_hash_aset(params, ID2SYM(rb_intern("keyword")), keywords); } + if (iseq->param.flags.has_kwrest) rb_hash_aset(params, ID2SYM(rb_intern("kwrest")), INT2FIX(iseq->param.keyword->rest_start)); + if (iseq->param.flags.ambiguous_param0) rb_hash_aset(params, ID2SYM(rb_intern("ambiguous_param0")), Qtrue); } /* body */ @@ -1897,7 +1883,7 @@ iseq_data_to_ary(rb_iseq_t *iseq) st_free_table(labels_table); - rb_hash_aset(misc, ID2SYM(rb_intern("arg_size")), INT2FIX(iseq->arg_size)); + rb_hash_aset(misc, ID2SYM(rb_intern("arg_size")), INT2FIX(iseq->param.size)); rb_hash_aset(misc, ID2SYM(rb_intern("local_size")), INT2FIX(iseq->local_size)); rb_hash_aset(misc, ID2SYM(rb_intern("stack_max")), INT2FIX(iseq->stack_max)); @@ -1918,7 +1904,7 @@ iseq_data_to_ary(rb_iseq_t *iseq) rb_ary_push(val, iseq->location.first_lineno); rb_ary_push(val, type); rb_ary_push(val, locals); - rb_ary_push(val, args); + rb_ary_push(val, params); rb_ary_push(val, exception); rb_ary_push(val, body); return val; @@ -1959,7 +1945,7 @@ VALUE rb_iseq_parameters(const rb_iseq_t *iseq, int is_proc) { int i, r; - VALUE a, args = rb_ary_new2(iseq->arg_size); + VALUE a, args = rb_ary_new2(iseq->param.size); ID req, opt, rest, block, key, keyrest; #define PARAM_TYPE(type) rb_ary_push(a = rb_ary_new2(2), ID2SYM(type)) #define PARAM_ID(i) iseq->local_table[(i)] @@ -1972,18 +1958,18 @@ rb_iseq_parameters(const rb_iseq_t *iseq, int is_proc) CONST_ID(req, "req"); CONST_ID(opt, "opt"); if (is_proc) { - for (i = 0; i < iseq->argc; i++) { + for (i = 0; i < iseq->param.lead_num; i++) { PARAM_TYPE(opt); rb_ary_push(a, rb_id2str(PARAM_ID(i)) ? ID2SYM(PARAM_ID(i)) : Qnil); rb_ary_push(args, a); } } else { - for (i = 0; i < iseq->argc; i++) { + for (i = 0; i < iseq->param.lead_num; i++) { rb_ary_push(args, PARAM(i, req)); } } - r = iseq->argc + iseq->arg_opts - 1; + r = iseq->param.lead_num + iseq->param.opt_num - 1; for (; i < r; i++) { PARAM_TYPE(opt); if (rb_id2str(PARAM_ID(i))) { @@ -1991,52 +1977,52 @@ rb_iseq_parameters(const rb_iseq_t *iseq, int is_proc) } rb_ary_push(args, a); } - if (iseq->arg_rest != -1) { + if (iseq->param.flags.has_rest) { CONST_ID(rest, "rest"); - rb_ary_push(args, PARAM(iseq->arg_rest, rest)); + rb_ary_push(args, PARAM(iseq->param.rest_start, rest)); } - r = iseq->arg_post_start + iseq->arg_post_num; + r = iseq->param.post_start + iseq->param.post_num; if (is_proc) { - for (i = iseq->arg_post_start; i < r; i++) { + for (i = iseq->param.post_start; i < r; i++) { PARAM_TYPE(opt); rb_ary_push(a, rb_id2str(PARAM_ID(i)) ? ID2SYM(PARAM_ID(i)) : Qnil); rb_ary_push(args, a); } } else { - for (i = iseq->arg_post_start; i < r; i++) { + for (i = iseq->param.post_start; i < r; i++) { rb_ary_push(args, PARAM(i, req)); } } - if (iseq->arg_keyword_bits != -1) { + if (iseq->param.flags.has_kw) { i = 0; - if (iseq->arg_keyword_required) { + if (iseq->param.keyword->required_num > 0) { ID keyreq; CONST_ID(keyreq, "keyreq"); - for (; i < iseq->arg_keyword_required; i++) { + for (; i < iseq->param.keyword->required_num; i++) { PARAM_TYPE(keyreq); - if (rb_id2str(iseq->arg_keyword_table[i])) { - rb_ary_push(a, ID2SYM(iseq->arg_keyword_table[i])); + if (rb_id2str(iseq->param.keyword->table[i])) { + rb_ary_push(a, ID2SYM(iseq->param.keyword->table[i])); } rb_ary_push(args, a); } } CONST_ID(key, "key"); - for (; i < iseq->arg_keyword_num; i++) { + for (; i < iseq->param.keyword->num; i++) { PARAM_TYPE(key); - if (rb_id2str(iseq->arg_keyword_table[i])) { - rb_ary_push(a, ID2SYM(iseq->arg_keyword_table[i])); + if (rb_id2str(iseq->param.keyword->table[i])) { + rb_ary_push(a, ID2SYM(iseq->param.keyword->table[i])); } rb_ary_push(args, a); } } - if (iseq->arg_keyword_rest >= 0) { + if (iseq->param.flags.has_kwrest) { CONST_ID(keyrest, "keyrest"); - rb_ary_push(args, PARAM(iseq->arg_keyword_rest, keyrest)); + rb_ary_push(args, PARAM(iseq->param.keyword->rest_start, keyrest)); } - if (iseq->arg_block != -1) { + if (iseq->param.flags.has_block) { CONST_ID(block, "block"); - rb_ary_push(args, PARAM(iseq->arg_block, block)); + rb_ary_push(args, PARAM(iseq->param.block_start, block)); } return args; } @@ -2136,8 +2122,8 @@ rb_iseq_build_for_ruby2cext( struct iseq_catch_table_entry, iseq->catch_table->size); } - ALLOC_AND_COPY(iseq->arg_opt_table, arg_opt_table, - VALUE, iseq->arg_opts); + ALLOC_AND_COPY(iseq->param.opt_table, arg_opt_table, + VALUE, iseq->param.opt_num); set_relation(iseq, 0); diff --git a/proc.c b/proc.c index d0856ec40d..55985752ae 100644 --- a/proc.c +++ b/proc.c @@ -735,7 +735,7 @@ proc_call(int argc, VALUE *argv, VALUE procval) GetProcPtr(procval, proc); iseq = proc->block.iseq; - if (BUILTIN_TYPE(iseq) == T_NODE || iseq->arg_block != -1) { + if (BUILTIN_TYPE(iseq) == T_NODE || iseq->param.flags.has_block) { if (rb_block_given_p()) { rb_proc_t *passed_proc; RB_GC_GUARD(passed_procval) = rb_block_proc(); @@ -847,11 +847,13 @@ proc_arity(VALUE self) static inline int rb_iseq_min_max_arity(const rb_iseq_t *iseq, int *max) { - *max = iseq->arg_rest == -1 ? - iseq->argc + iseq->arg_post_num + iseq->arg_opts - - (iseq->arg_opts > 0) + (iseq->arg_keyword_num > 0) + (iseq->arg_keyword_rest >= 0) + *max = iseq->param.flags.has_rest == FALSE ? + iseq->param.lead_num + iseq->param.post_num + + iseq->param.opt_num - (iseq->param.flags.has_opt == TRUE) + + (iseq->param.flags.has_kw == TRUE) + + (iseq->param.flags.has_kwrest == TRUE) : UNLIMITED_ARGUMENTS; - return iseq->argc + iseq->arg_post_num + (iseq->arg_keyword_required > 0); + return iseq->param.lead_num + iseq->param.post_num + (iseq->param.flags.has_kw && iseq->param.keyword->required_num > 0); } static int diff --git a/vm.c b/vm.c index f478d26291..3eda7f4ca3 100644 --- a/vm.c +++ b/vm.c @@ -776,7 +776,7 @@ invoke_block_from_c(rb_thread_t *th, const rb_block_t *block, VALUE ret; const rb_iseq_t *iseq = block->iseq; const rb_control_frame_t *cfp; - int i, opt_pc, arg_size = iseq->arg_size; + int i, opt_pc, arg_size = iseq->param.size; int type = block_proc_is_lambda(block->proc) ? VM_FRAME_MAGIC_LAMBDA : VM_FRAME_MAGIC_BLOCK; const rb_method_entry_t *me = th->passed_bmethod_me; th->passed_bmethod_me = 0; diff --git a/vm_args.c b/vm_args.c index fd77bfa4d0..c1f460a972 100644 --- a/vm_args.c +++ b/vm_args.c @@ -381,10 +381,10 @@ static void args_setup_kw_parameters(VALUE* const passed_values, const int passed_keyword_len, const ID * const passed_keywords, const rb_iseq_t * const iseq, VALUE * const locals) { - const ID *acceptable_keywords = iseq->arg_keyword_table; - const int req_key_num = iseq->arg_keyword_required; - const int key_num = iseq->arg_keyword_num; - const VALUE * const default_values = iseq->arg_keyword_default_values; + const ID *acceptable_keywords = iseq->param.keyword->table; + const int req_key_num = iseq->param.keyword->required_num; + const int key_num = iseq->param.keyword->num; + const VALUE * const default_values = iseq->param.keyword->default_values; VALUE missing = 0; int i, di, found = 0; int unspecified_bits = 0; @@ -435,7 +435,7 @@ args_setup_kw_parameters(VALUE* const passed_values, const int passed_keyword_le } } - if (iseq->arg_keyword_rest >= 0) { + if (iseq->param.flags.has_kwrest) { const int rest_hash_index = key_num + 1; locals[rest_hash_index] = make_unused_kw_hash(passed_keywords, passed_keyword_len, passed_values, FALSE); } @@ -522,13 +522,13 @@ static int setup_parameters_complex(rb_thread_t * const th, const rb_iseq_t * const iseq, rb_call_info_t * const ci, VALUE * const locals, const enum arg_setup_type arg_setup_type) { - const int min_argc = iseq->argc + iseq->arg_post_num; - const int max_argc = (iseq->arg_rest == -1) ? min_argc + (iseq->arg_opts - (iseq->arg_opts > 0)) : UNLIMITED_ARGUMENTS; + const int min_argc = iseq->param.lead_num + iseq->param.post_num; + const int max_argc = (iseq->param.flags.has_rest == FALSE) ? min_argc + (iseq->param.opt_num - (iseq->param.flags.has_opt == TRUE)) : UNLIMITED_ARGUMENTS; int opt_pc = 0; int given_argc; struct args_info args_body, *args; VALUE keyword_hash = Qnil; - const int msl = ci->argc + iseq->arg_size; + const int msl = ci->argc + iseq->param.size; th->mark_stack_len = msl; @@ -539,7 +539,7 @@ setup_parameters_complex(rb_thread_t * const th, const rb_iseq_t * const iseq, r args->argv = locals; if (ci->kw_arg) { - if (iseq->arg_keyword_bits >= 0) { + if (iseq->param.flags.has_kw) { int kw_len = ci->kw_arg->keyword_len; /* copy kw_argv */ args->kw_argv = ALLOCA_N(VALUE, kw_len); @@ -571,16 +571,16 @@ setup_parameters_complex(rb_thread_t * const th, const rb_iseq_t * const iseq, r case arg_setup_block: if (given_argc == 1 && (min_argc > 0 || - iseq->arg_opts > 2 || iseq->arg_keyword_bits >= 0 || iseq->arg_keyword_rest >= 0) && /* TODO: can be shrink with flags */ - !(iseq->arg_simple & 0x02) && + iseq->param.opt_num > 2 || iseq->param.flags.has_kw || iseq->param.flags.has_kwrest) && /* TODO: can be shrink with flags */ + !iseq->param.flags.ambiguous_param0 && args_check_block_arg0(args, th, msl)) { given_argc = RARRAY_LEN(args->rest); } break; case arg_setup_lambda: if (given_argc == 1 && - given_argc != iseq->argc && - !(iseq->arg_rest >= 0) && + given_argc != iseq->param.lead_num && + !iseq->param.flags.has_rest && args_check_block_arg0(args, th, msl)) { given_argc = RARRAY_LEN(args->rest); } @@ -605,7 +605,7 @@ setup_parameters_complex(rb_thread_t * const th, const rb_iseq_t * const iseq, r } if (given_argc > min_argc && - (iseq->arg_keyword_bits >= 0 || iseq->arg_keyword_rest >= 0) && + (iseq->param.flags.has_kw || iseq->param.flags.has_kwrest) && args->kw_argv == NULL) { if (args_pop_keyword_hash(args, &keyword_hash, th, msl)) { given_argc--; @@ -623,25 +623,25 @@ setup_parameters_complex(rb_thread_t * const th, const rb_iseq_t * const iseq, r } } - if (iseq->argc > 0) { - args_setup_lead_parameters(args, iseq->argc, locals + 0); + if (iseq->param.flags.has_lead) { + args_setup_lead_parameters(args, iseq->param.lead_num, locals + 0); } - if (iseq->arg_post_num > 0) { - args_setup_post_parameters(args, iseq->arg_post_num, locals + iseq->arg_post_start); + if (iseq->param.flags.has_post) { + args_setup_post_parameters(args, iseq->param.post_num, locals + iseq->param.post_start); } - if (iseq->arg_opts > 0) { - int opt = args_setup_opt_parameters(args, iseq->arg_opts - 1, locals + iseq->argc); - opt_pc = (int)iseq->arg_opt_table[opt]; + if (iseq->param.flags.has_opt) { + int opt = args_setup_opt_parameters(args, iseq->param.opt_num - 1, locals + iseq->param.lead_num); + opt_pc = (int)iseq->param.opt_table[opt]; } - if (iseq->arg_rest >= 0) { - args_setup_rest_parameter(args, locals + iseq->arg_rest); + if (iseq->param.flags.has_rest) { + args_setup_rest_parameter(args, locals + iseq->param.rest_start); } - if (iseq->arg_keyword_bits >= 0) { - VALUE * const klocals = locals + iseq->arg_keyword_bits - iseq->arg_keyword_num; + if (iseq->param.flags.has_kw) { + VALUE * const klocals = locals + iseq->param.keyword->bits_start - iseq->param.keyword->num; if (args->kw_argv != NULL) { args_setup_kw_parameters(args->kw_argv, args->ci->kw_arg->keyword_len, args->ci->kw_arg->keywords, iseq, klocals); @@ -662,18 +662,18 @@ setup_parameters_complex(rb_thread_t * const th, const rb_iseq_t * const iseq, r args_setup_kw_parameters(NULL, 0, NULL, iseq, klocals); } } - else if (iseq->arg_keyword_rest >= 0) { - args_setup_kw_rest_parameter(keyword_hash, locals + iseq->arg_keyword_rest); + else if (iseq->param.flags.has_kwrest) { + args_setup_kw_rest_parameter(keyword_hash, locals + iseq->param.keyword->rest_start); } - if (iseq->arg_block >= 0) { - args_setup_block_parameter(th, ci, locals + iseq->arg_block); + if (iseq->param.flags.has_block) { + args_setup_block_parameter(th, ci, locals + iseq->param.block_start); } #if 0 { int i; - for (i=0; iarg_size; i++) { + for (i=0; iparam.size; i++) { fprintf(stderr, "local[%d] = %p\n", i, (void *)locals[i]); } } diff --git a/vm_core.h b/vm_core.h index f8494d07e6..0daa52f0c3 100644 --- a/vm_core.h +++ b/vm_core.h @@ -240,7 +240,7 @@ struct rb_iseq_struct { rb_call_info_t *callinfo_entries; /** - * argument information + * parameter information * * def m(a1, a2, ..., aM, # mandatory * b1=(...), b2=(...), ..., bN=(...), # optional @@ -251,36 +251,50 @@ struct rb_iseq_struct { * &g) # block * => * - * argc = M // or 0 if no mandatory arg - * arg_opts = N+1 // or 0 if no optional arg - * arg_rest = M+N // or -1 if no rest arg - * arg_opt_table = [ (arg_opts entries) ] - * arg_post_start = M+N+(*1) // or 0 if no post arguments - * arg_post_num = O // or 0 if no post arguments - * arg_keyword_num = K // or 0 if no keyword arg - * arg_block = M+N+(*1)+O+K // or -1 if no block arg - * arg_keyword_bits = M+N+(*1)+O+K+(&1) // or -1 if no keyword arg/rest - * arg_simple = 0 if not simple arguments. - * = 1 if no opt, rest, post, block. - * = 2 if ambiguous block parameter ({|a|}). - * arg_size = M+N+O+(*1)+K+(&1)+(**1) argument size. + * lead_num = M + * opt_num = N+1 + * rest_start = M+N + * post_start = M+N+(*1) + * post_num = O + * keyword_num = K + * block_start = M+N+(*1)+O+K + * keyword_bits = M+N+(*1)+O+K+(&1) + * size = M+N+O+(*1)+K+(&1)+(**1) // parameter size. */ - int argc; - int arg_simple; - int arg_rest; - int arg_block; - int arg_opts; - int arg_post_num; - int arg_post_start; - int arg_size; - VALUE *arg_opt_table; - int arg_keyword_num; - int arg_keyword_bits; - int arg_keyword_rest; - int arg_keyword_required; - ID *arg_keyword_table; - VALUE *arg_keyword_default_values; + struct { + struct { + unsigned int has_lead : 1; + unsigned int has_opt : 1; + unsigned int has_rest : 1; + unsigned int has_post : 1; + unsigned int has_kw : 1; + unsigned int has_kwrest : 1; + unsigned int has_block : 1; + + unsigned int ambiguous_param0 : 1; /* {|a|} */ + } flags; + + int size; + + int lead_num; + int opt_num; + int rest_start; + int post_start; + int post_num; + int block_start; + + VALUE *opt_table; + + struct rb_iseq_param_keyword { + int num; + int required_num; + int bits_start; + int rest_start; + ID *table; + VALUE *default_values; + } *keyword; + } param; /* catch table */ struct iseq_catch_table *catch_table; diff --git a/vm_dump.c b/vm_dump.c index a65542b0f8..034b4192d2 100644 --- a/vm_dump.c +++ b/vm_dump.c @@ -265,7 +265,7 @@ vm_stack_dump_each(rb_thread_t *th, rb_control_frame_t *cfp) name = ""; } else { - argc = iseq->argc; + argc = iseq->param.lead_num; local_size = iseq->local_size; name = RSTRING_PTR(iseq->location.label); } diff --git a/vm_insnhelper.c b/vm_insnhelper.c index 95d232e740..d67fd50db5 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -1008,19 +1008,30 @@ vm_callee_setup_block_arg_arg0_splat(rb_control_frame_t *cfp, const rb_iseq_t *i int i; long len = RARRAY_LEN(ary); - CHECK_VM_STACK_OVERFLOW(cfp, iseq->argc); + CHECK_VM_STACK_OVERFLOW(cfp, iseq->param.lead_num); - for (i=0; iargc; i++) { + for (i=0; iparam.lead_num; i++) { argv[i] = RARRAY_AREF(ary, i); } return i; } +static inline int +simple_iseq_p(const rb_iseq_t *iseq) +{ + return iseq->param.flags.has_opt == FALSE && + iseq->param.flags.has_rest == FALSE && + iseq->param.flags.has_post == FALSE && + iseq->param.flags.has_kw == FALSE && + iseq->param.flags.has_kwrest == FALSE && + iseq->param.flags.has_block == FALSE; +} + static inline void vm_callee_setup_block_arg(rb_thread_t *th, rb_call_info_t *ci, const rb_iseq_t *iseq, VALUE *argv, const enum arg_setup_type arg_setup_type) { - if (LIKELY(iseq->arg_simple & 0x01)) { + if (LIKELY(simple_iseq_p(iseq))) { rb_control_frame_t *cfp = th->cfp; VALUE arg0; @@ -1028,31 +1039,32 @@ vm_callee_setup_block_arg(rb_thread_t *th, rb_call_info_t *ci, const rb_iseq_t * if (arg_setup_type == arg_setup_block && ci->argc == 1 && - iseq->argc > 0 && !(iseq->arg_simple & 0x02) && + iseq->param.flags.has_lead && + !iseq->param.flags.ambiguous_param0 && !NIL_P(arg0 = vm_callee_setup_block_arg_arg0_check(argv))) { ci->argc = vm_callee_setup_block_arg_arg0_splat(cfp, iseq, argv, arg0); } - if (ci->argc != iseq->argc) { + if (ci->argc != iseq->param.lead_num) { if (arg_setup_type == arg_setup_block) { - if (ci->argc < iseq->argc) { + if (ci->argc < iseq->param.lead_num) { int i; - CHECK_VM_STACK_OVERFLOW(cfp, iseq->argc); - for (i=ci->argc; iargc; i++) argv[i] = Qnil; - ci->argc = iseq->argc; /* fill rest parameters */ + CHECK_VM_STACK_OVERFLOW(cfp, iseq->param.lead_num); + for (i=ci->argc; iparam.lead_num; i++) argv[i] = Qnil; + ci->argc = iseq->param.lead_num; /* fill rest parameters */ } - else if (ci->argc > iseq->argc) { - ci->argc = iseq->argc; /* simply truncate arguments */ + else if (ci->argc > iseq->param.lead_num) { + ci->argc = iseq->param.lead_num; /* simply truncate arguments */ } } else if (arg_setup_type == arg_setup_lambda && ci->argc == 1 && !NIL_P(arg0 = vm_callee_setup_block_arg_arg0_check(argv)) && - RARRAY_LEN(arg0) == iseq->argc) { + RARRAY_LEN(arg0) == iseq->param.lead_num) { ci->argc = vm_callee_setup_block_arg_arg0_splat(cfp, iseq, argv, arg0); } else { - argument_error(iseq, ci->argc, iseq->argc, iseq->argc); + argument_error(iseq, ci->argc, iseq->param.lead_num, iseq->param.lead_num); } } @@ -1066,13 +1078,13 @@ vm_callee_setup_block_arg(rb_thread_t *th, rb_call_info_t *ci, const rb_iseq_t * static inline void vm_callee_setup_arg(rb_thread_t *th, rb_call_info_t *ci, const rb_iseq_t *iseq, VALUE *argv) { - if (LIKELY(iseq->arg_simple & 0x01)) { + if (LIKELY(simple_iseq_p(iseq))) { rb_control_frame_t *cfp = th->cfp; CALLER_SETUP_ARG(cfp, ci); /* splat arg */ - if (ci->argc != iseq->argc) { - argument_error(iseq, ci->argc, iseq->argc, iseq->argc); + if (ci->argc != iseq->param.lead_num) { + argument_error(iseq, ci->argc, iseq->param.lead_num, iseq->param.lead_num); } ci->aux.opt_pc = 0; @@ -1110,10 +1122,10 @@ vm_call_iseq_setup_normal(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info int i, local_size; VALUE *argv = cfp->sp - ci->argc; rb_iseq_t *iseq = ci->me->def->body.iseq; - VALUE *sp = argv + iseq->arg_size; + VALUE *sp = argv + iseq->param.size; /* clear local variables (arg_size...local_size) */ - for (i = iseq->arg_size, local_size = iseq->local_size; i < local_size; i++) { + for (i = iseq->param.size, local_size = iseq->local_size; i < local_size; i++) { *sp++ = Qnil; } @@ -1146,12 +1158,12 @@ vm_call_iseq_setup_tailcall(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_in sp++; /* copy arguments */ - for (i=0; i < iseq->arg_size; i++) { + for (i=0; i < iseq->param.size; i++) { *sp++ = src_argv[i]; } /* clear local variables */ - for (i = 0; i < iseq->local_size - iseq->arg_size; i++) { + for (i = 0; i < iseq->local_size - iseq->param.size; i++) { *sp++ = Qnil; } @@ -2031,7 +2043,7 @@ vm_invoke_block(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci if (BUILTIN_TYPE(iseq) != T_NODE) { int opt_pc; - const int arg_size = iseq->arg_size; + const int arg_size = iseq->param.size; int is_lambda = block_proc_is_lambda(block->proc); VALUE * const rsp = GET_SP() - ci->argc; -- cgit v1.2.3