aboutsummaryrefslogtreecommitdiffstats
path: root/compile.c
diff options
context:
space:
mode:
authorJeremy Evans <code@jeremyevans.net>2023-11-06 12:08:03 -0800
committerJeremy Evans <code@jeremyevans.net>2023-12-07 11:27:55 -0800
commitc70c1d2a9592bcea916500eb16ae58f6de4b9a3f (patch)
tree4a37dead56b26bf8f79270eac8652378b0a310e4 /compile.c
parent40a2afd08fe1b921f1052b29031abfa1869e0557 (diff)
downloadruby-c70c1d2a9592bcea916500eb16ae58f6de4b9a3f.tar.gz
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.c24
1 files changed, 24 insertions, 0 deletions
diff --git a/compile.c b/compile.c
index fe0bd5e6d2..1f3b0920de 100644
--- a/compile.c
+++ b/compile.c
@@ -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;
+ }
+ }
+ }
}
}