diff options
author | ko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2017-10-24 11:13:49 +0000 |
---|---|---|
committer | ko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2017-10-24 11:13:49 +0000 |
commit | 5ee9513a7104078d9d2f51aecc354ae67f1ba002 (patch) | |
tree | 52e299b3ec089f27e306012ee11d4e70d82ff848 /compile.c | |
parent | d0d32ba1e8e30443cadc0580e3f1e534af547f07 (diff) | |
download | ruby-5ee9513a7104078d9d2f51aecc354ae67f1ba002.tar.gz |
Lazy Proc allocation for block parameters
[Feature #14045]
* insns.def (getblockparam, setblockparam): add special access
instructions for block parameters.
getblockparam checks VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM and
if it is not set this instruction creates a Proc object from
a given blcok and set VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM.
setblockparam is similar to setlocal, but set
VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM.
* compile.c: use get/setblockparm instead get/setlocal instructions.
Note that they are used for method local block parameters (def m(&b)),
not for block local method parameters (iter{|&b|).
* proc.c (get_local_variable_ptr): creates Proc object for
Binding#local_variable_get/set.
* safe.c (safe_setter): we need to create Proc objects for postponed
block parameters when $SAFE is changed.
* vm_args.c (args_setup_block_parameter): used only for block local blcok
parameters.
* vm_args.c (vm_caller_setup_arg_block): if called with
VM_CALL_ARGS_BLOCKARG_BLOCKPARAM flag then passed block values should be
a block handler.
* test/ruby/test_optimization.rb: add tests.
* benchmark/bm_vm1_blockparam*: added.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@60397 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'compile.c')
-rw-r--r-- | compile.c | 75 |
1 files changed, 67 insertions, 8 deletions
@@ -300,15 +300,11 @@ struct iseq_compile_data_ensure_node_stack { } \ } while (0) -#define ADD_GETLOCAL(seq, line, idx, level) \ - do { \ - ADD_INSN2((seq), (line), getlocal, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level)); \ - } while (0) +static void iseq_add_getlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, int line, int idx, int level); +static void iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, int line, int idx, int level); -#define ADD_SETLOCAL(seq, line, idx, level) \ - do { \ - ADD_INSN2((seq), (line), setlocal, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level)); \ - } while (0) +#define ADD_GETLOCAL(seq, line, idx, level) iseq_add_getlocal(iseq, (seq), (line), (idx), (level)) +#define ADD_SETLOCAL(seq, line, idx, level) iseq_add_setlocal(iseq, (seq), (line), (idx), (level)) /* add label */ #define ADD_LABEL(seq, label) \ @@ -976,6 +972,18 @@ LIST_SIZE_ZERO(LINK_ANCHOR *const anchor) } } +static int +LIST_SIZE_ONE(const LINK_ANCHOR *const anchor) +{ + if (anchor->anchor.next != NULL && + anchor->anchor.next->next == NULL) { + return 1; + } + else { + return 0; + } +} + /* * anc1: e1, e2, e3 * anc2: e4, e5 @@ -1298,6 +1306,47 @@ get_dyna_var_idx(const rb_iseq_t *iseq, ID id, int *level, int *ls) return idx; } +static int +iseq_local_block_param_p(const rb_iseq_t *iseq, unsigned int idx, unsigned int level) +{ + while (level > 0) { + iseq = iseq->body->parent_iseq; + level--; + } + if (iseq->body->local_iseq == iseq && /* local variables */ + iseq->body->param.flags.has_block && + iseq->body->local_table_size - iseq->body->param.block_start == idx) { + return TRUE; + } + else { + return FALSE; + } +} + +static void +iseq_add_getlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, int line, int idx, int level) +{ + if (iseq_local_block_param_p(iseq, idx, level)) { + ADD_INSN2(seq, line, getblockparam, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level)); + } + else { + ADD_INSN2(seq, line, getlocal, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level)); + } +} + +static void +iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, int line, int idx, int level) +{ + if (iseq_local_block_param_p(iseq, idx, level)) { + ADD_INSN2(seq, line, setblockparam, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level)); + } + else { + ADD_INSN2(seq, line, setlocal, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level)); + } +} + + + static void iseq_calc_param_size(rb_iseq_t *iseq) { @@ -4173,6 +4222,16 @@ setup_args(rb_iseq_t *iseq, LINK_ANCHOR *const args, NODE *argn, } if (*flag & VM_CALL_ARGS_BLOCKARG) { + if (LIST_SIZE_ONE(arg_block)) { + LINK_ELEMENT *elem = FIRST_ELEMENT(arg_block); + if (elem->type == ISEQ_ELEMENT_INSN) { + INSN *iobj = (INSN *)elem; + if (iobj->insn_id == BIN(getblockparam)) { + iobj->insn_id = BIN(getlocal); + *flag |= VM_CALL_ARGS_BLOCKARG_BLOCKPARAM; + } + } + } ADD_SEQ(args, arg_block); } return argc; |