diff options
author | ko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2014-11-02 18:02:55 +0000 |
---|---|---|
committer | ko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2014-11-02 18:02:55 +0000 |
commit | fbebd502f9f374d1eef31c63c10c7d8adcd63280 (patch) | |
tree | 69dc3dbcdd12509100d01fce6e5d95343b3337c9 /iseq.c | |
parent | 055a465ac4222f314917c1d682fbd9d0d73535af (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.c | 40 |
1 files changed, 25 insertions, 15 deletions
@@ -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"); |