summaryrefslogtreecommitdiff
path: root/iseq.c
diff options
context:
space:
mode:
authorko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2014-11-02 18:02:55 +0000
committerko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2014-11-02 18:02:55 +0000
commitfbebd502f9f374d1eef31c63c10c7d8adcd63280 (patch)
tree69dc3dbcdd12509100d01fce6e5d95343b3337c9 /iseq.c
parent055a465ac4222f314917c1d682fbd9d0d73535af (diff)
* rewrite method/block parameter fitting logic to optimize
keyword arguments/parameters and a splat argument. [Feature #10440] (Details are described in this ticket) Most of complex part is moved to vm_args.c. Now, ISeq#to_a does not catch up new instruction format. * vm_core.h: change iseq data structures. * introduce rb_call_info_kw_arg_t to represent keyword arguments. * add rb_call_info_t::kw_arg. * rename rb_iseq_t::arg_post_len to rb_iseq_t::arg_post_num. * rename rb_iseq_t::arg_keywords to arg_keyword_num. * rename rb_iseq_t::arg_keyword to rb_iseq_t::arg_keyword_bits. to represent keyword bitmap parameter index. This bitmap parameter shows that which keyword parameters are given or not given (0 for given). It is refered by `checkkeyword' instruction described bellow. * rename rb_iseq_t::arg_keyword_check to rb_iseq_t::arg_keyword_rest to represent keyword rest parameter index. * add rb_iseq_t::arg_keyword_default_values to represent default keyword values. * rename VM_CALL_ARGS_SKIP_SETUP to VM_CALL_ARGS_SIMPLE to represent (ci->flag & (SPLAT|BLOCKARG)) && ci->blockiseq == NULL && ci->kw_arg == NULL. * vm_insnhelper.c, vm_args.c: rewrite with refactoring. * rewrite splat argument code. * rewrite keyword arguments/parameters code. * merge method and block parameter fitting code into one code base. * vm.c, vm_eval.c: catch up these changes. * compile.c (new_callinfo): callinfo requires kw_arg parameter. * compile.c (compile_array_): check the last argument Hash object or not. If Hash object and all keys are Symbol literals, they are compiled to keyword arguments. * insns.def (checkkeyword): add new instruction. This instruction check the availability of corresponding keyword. For example, a method "def foo k1: 'v1'; end" is cimpiled to the following instructions. 0000 checkkeyword 2, 0 # check k1 is given. 0003 branchif 9 # if given, jump to address #9 0005 putstring "v1" 0007 setlocal_OP__WC__0 3 # k1 = 'v1' 0009 trace 8 0011 putnil 0012 trace 16 0014 leave * insns.def (opt_send_simple): removed and add new instruction "opt_send_without_block". * parse.y (new_args_tail_gen): reorder variables. Before this patch, a method "def foo(k1: 1, kr1:, k2: 2, **krest, &b)" has parameter variables "k1, kr1, k2, &b, internal_id, krest", but this patch reorders to "kr1, k1, k2, internal_id, krest, &b". (locate a block variable at last) * parse.y (vtable_pop): added. This function remove latest `n' variables from vtable. * iseq.c: catch up iseq data changes. * proc.c: ditto. * class.c (keyword_error): export as rb_keyword_error(). * common.mk: depend vm_args.c for vm.o. * hash.c (rb_hash_has_key): export. * internal.h: ditto. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@48239 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'iseq.c')
-rw-r--r--iseq.c40
1 files changed, 25 insertions, 15 deletions
diff --git a/iseq.c b/iseq.c
index 2bfdf7c9ed..4af1426a54 100644
--- a/iseq.c
+++ b/iseq.c
@@ -67,6 +67,7 @@ iseq_free(void *ptr)
RUBY_FREE_ENTER("iseq");
if (ptr) {
+ int i;
iseq = ptr;
if (!iseq->orig) {
/* It's possible that strings are freed */
@@ -79,10 +80,14 @@ iseq_free(void *ptr)
RUBY_FREE_UNLESS_NULL(iseq->line_info_table);
RUBY_FREE_UNLESS_NULL(iseq->local_table);
RUBY_FREE_UNLESS_NULL(iseq->is_entries);
+ for (i=0; i<iseq->callinfo_size; i++) {
+ /* TODO: revisit callinfo data structure */
+ rb_call_info_kw_arg_t *kw_arg = iseq->callinfo_entries[i].kw_arg;
+ RUBY_FREE_UNLESS_NULL(kw_arg);
+ }
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->arg_keyword_table);
compile_data_free(iseq->compile_data);
RUBY_FREE_UNLESS_NULL(iseq->iseq);
}
@@ -259,7 +264,8 @@ prepare_iseq_build(rb_iseq_t *iseq,
iseq->type = type;
iseq->arg_rest = -1;
iseq->arg_block = -1;
- iseq->arg_keyword = -1;
+ iseq->arg_keyword_bits = -1;
+ iseq->arg_keyword_rest = -1;
RB_OBJ_WRITE(iseq->self, &iseq->klass, 0);
set_relation(iseq, parent);
@@ -1239,6 +1245,9 @@ rb_insn_operand_intern(const rb_iseq_t *iseq,
rb_ary_push(ary, rb_sprintf("argc:%d", ci->orig_argc));
+ if (ci->kw_arg) {
+ rb_ary_push(ary, rb_sprintf("kw:%d", ci->kw_arg->keyword_len));
+ }
if (ci->blockiseq) {
if (child) {
rb_ary_push(child, ci->blockiseq->self);
@@ -1255,7 +1264,7 @@ rb_insn_operand_intern(const rb_iseq_t *iseq,
if (ci->flag & VM_CALL_TAILCALL) rb_ary_push(flags, rb_str_new2("TAILCALL"));
if (ci->flag & VM_CALL_SUPER) rb_ary_push(flags, rb_str_new2("SUPER"));
if (ci->flag & VM_CALL_OPT_SEND) rb_ary_push(flags, rb_str_new2("SNED")); /* maybe not reachable */
- if (ci->flag & VM_CALL_ARGS_SKIP_SETUP) rb_ary_push(flags, rb_str_new2("ARGS_SKIP")); /* maybe not reachable */
+ if (ci->flag & VM_CALL_ARGS_SIMPLE) rb_ary_push(flags, rb_str_new2("ARGS_SIMPLE")); /* maybe not reachable */
rb_ary_push(ary, rb_ary_join(flags, rb_str_new2("|")));
}
ret = rb_sprintf("<callinfo!%"PRIsVALUE">", rb_ary_join(ary, rb_str_new2(", ")));
@@ -1424,11 +1433,12 @@ 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, keyword: %d@%d] s%d)\n",
+ "[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_len, iseqdat->arg_block,
- iseqdat->arg_keywords, iseqdat->local_size-iseqdat->arg_keyword,
+ 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);
for (i = 0; i < iseqdat->local_table_size; i++) {
@@ -1451,7 +1461,7 @@ rb_iseq_disasm(VALUE self)
opti,
iseqdat->arg_rest == i ? "Rest" : "",
(iseqdat->arg_post_start <= i &&
- i < iseqdat->arg_post_start + iseqdat->arg_post_len) ? "Post" : "",
+ i < iseqdat->arg_post_start + iseqdat->arg_post_num) ? "Post" : "",
iseqdat->arg_block == i ? "Block" : "");
rb_str_catf(str, "[%2d] ", iseqdat->local_size - i);
@@ -1746,7 +1756,7 @@ iseq_data_to_ary(rb_iseq_t *iseq)
else {
rb_ary_push(args, INT2FIX(iseq->argc));
rb_ary_push(args, arg_opt_labels);
- rb_ary_push(args, INT2FIX(iseq->arg_post_len));
+ 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));
@@ -1985,7 +1995,7 @@ rb_iseq_parameters(const rb_iseq_t *iseq, int is_proc)
CONST_ID(rest, "rest");
rb_ary_push(args, PARAM(iseq->arg_rest, rest));
}
- r = iseq->arg_post_start + iseq->arg_post_len;
+ r = iseq->arg_post_start + iseq->arg_post_num;
if (is_proc) {
for (i = iseq->arg_post_start; i < r; i++) {
PARAM_TYPE(opt);
@@ -1998,7 +2008,7 @@ rb_iseq_parameters(const rb_iseq_t *iseq, int is_proc)
rb_ary_push(args, PARAM(i, req));
}
}
- if (iseq->arg_keyword != -1) {
+ if (iseq->arg_keyword_bits != -1) {
i = 0;
if (iseq->arg_keyword_required) {
ID keyreq;
@@ -2012,17 +2022,17 @@ rb_iseq_parameters(const rb_iseq_t *iseq, int is_proc)
}
}
CONST_ID(key, "key");
- for (; i < iseq->arg_keywords; i++) {
+ for (; i < iseq->arg_keyword_num; i++) {
PARAM_TYPE(key);
if (rb_id2str(iseq->arg_keyword_table[i])) {
rb_ary_push(a, ID2SYM(iseq->arg_keyword_table[i]));
}
rb_ary_push(args, a);
}
- if (!iseq->arg_keyword_check) {
- CONST_ID(keyrest, "keyrest");
- rb_ary_push(args, PARAM(iseq->arg_keyword, keyrest));
- }
+ }
+ if (iseq->arg_keyword_rest >= 0) {
+ CONST_ID(keyrest, "keyrest");
+ rb_ary_push(args, PARAM(iseq->arg_keyword_rest, keyrest));
}
if (iseq->arg_block != -1) {
CONST_ID(block, "block");