summaryrefslogtreecommitdiff
path: root/compile.c
diff options
context:
space:
mode:
authorko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2017-10-24 11:13:49 +0000
committerko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2017-10-24 11:13:49 +0000
commit5ee9513a7104078d9d2f51aecc354ae67f1ba002 (patch)
tree52e299b3ec089f27e306012ee11d4e70d82ff848 /compile.c
parentd0d32ba1e8e30443cadc0580e3f1e534af547f07 (diff)
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.c75
1 files changed, 67 insertions, 8 deletions
diff --git a/compile.c b/compile.c
index 3d59b6383f..767da7a3da 100644
--- a/compile.c
+++ b/compile.c
@@ -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;