diff options
author | Jeremy Evans <[email protected]> | 2023-11-06 12:08:03 -0800 |
---|---|---|
committer | Jeremy Evans <[email protected]> | 2023-12-07 11:27:55 -0800 |
commit | c70c1d2a9592bcea916500eb16ae58f6de4b9a3f (patch) | |
tree | 4a37dead56b26bf8f79270eac8652378b0a310e4 /compile.c | |
parent | 40a2afd08fe1b921f1052b29031abfa1869e0557 (diff) |
Eliminate array allocation for f(1, *a, &lvar) and f(1, *a, &@iv)
Due to how the compiler works, while f(*a, &lvar) and f(*a, &@iv)
do not allocate an array, but f(1, *a, &lvar) and f(1, *a, &@iv)
do. It's probably possible to fix this in the compiler, but
seems easiest to fix this in the peephole optimizer.
Eliminating this array allocation is as safe as the current
elimination of the array allocation for f(*a, &lvar) and
f(*a, &@iv).
Diffstat (limited to 'compile.c')
-rw-r--r-- | compile.c | 24 |
1 files changed, 24 insertions, 0 deletions
@@ -3854,6 +3854,30 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal if ((flag & VM_CALL_ARGS_SPLAT) && !(flag & (VM_CALL_KW_SPLAT|VM_CALL_ARGS_BLOCKARG))) { OPERAND_AT(iobj, 0) = Qfalse; } + } else if (IS_NEXT_INSN_ID(niobj, getlocal) || IS_NEXT_INSN_ID(niobj, getinstancevariable)) { + niobj = niobj->next; + + if (IS_NEXT_INSN_ID(niobj, send)) { + niobj = niobj->next; + unsigned int flag = vm_ci_flag((const struct rb_callinfo *)OPERAND_AT(niobj, 0)); + + if ((flag & VM_CALL_ARGS_SPLAT)) { + /* + * Eliminate array allocation for f(1, *a, &lvar) and f(1, *a, &@iv) + * + * splatarray true + * getlocal / getinstancevariable + * send ARGS_SPLAT|ARGS_BLOCKARG and not KW_SPLAT + * => + * splatarray false + * getlocal / getinstancevariable + * send + */ + if ((flag & VM_CALL_ARGS_BLOCKARG) && !(flag & VM_CALL_KW_SPLAT)) { + OPERAND_AT(iobj, 0) = Qfalse; + } + } + } } } |