File 7921-Add-fast-lanes-for-2-and-2-on-nil-arguments.patch of Package erlang

From 8eeb95d479c61ad30aa70aef3f686f9107845b27 Mon Sep 17 00:00:00 2001
From: Michael Davis <mcarsondavis@gmail.com>
Date: Mon, 26 Aug 2024 16:39:42 -0400
Subject: [PATCH] Add fast-lanes for '++'/2 and '--'/2 on nil arguments

Currently appending an empty list to another list causes the left-hand
side list to be fully copied. We can skip the append operation when the
right-hand side is nil since it shouldn't change the left-hand side
list. In this fast-lane we scan the list to determine if it is improper
so that cases like `[1, 2 | 3] ++ []` behave the same as cases like
`[1, 2 | 3] ++ [4]`: return a badarg error.

This patch adds similar fast-lanes for '--'/2: we can return the first
argument when either the first or second arguments are nil.
---
 erts/emulator/beam/erl_bif_lists.c | 56 +++++++++++++++++++++++++++++-
 1 file changed, 55 insertions(+), 1 deletion(-)

diff --git a/erts/emulator/beam/erl_bif_lists.c b/erts/emulator/beam/erl_bif_lists.c
index 5dcd53d613..10afb3adaa 100644
--- a/erts/emulator/beam/erl_bif_lists.c
+++ b/erts/emulator/beam/erl_bif_lists.c
@@ -56,6 +56,36 @@ static int append_ctx_bin_dtor(Binary *context_bin) {
     return 1;
 }
 
+static int append_empty_rhs(Process *p, ErtsAppendContext *context) {
+    static const Sint ELEMENTS_PER_RED = 32;
+    Sint budget, count;
+
+    budget = ELEMENTS_PER_RED * ERTS_BIF_REDS_LEFT(p);
+
+#ifdef DEBUG
+    budget = budget / 10 + 1;
+#endif
+
+    for (count = 0; count < budget && is_list(context->iterator); count++) {
+        context->iterator = CDR(list_val(context->iterator));
+    }
+
+    BUMP_REDS(p, count / ELEMENTS_PER_RED);
+
+    if (is_list(context->iterator)) {
+        return 0;
+    } else if (is_nil(context->iterator)) {
+#ifdef DEBUG
+        context->result_cdr = &context->rhs_original;
+#endif
+        context->result = context->lhs_original;
+
+        return 1;
+    }
+
+    return -1;
+}
+
 static Eterm append_create_trap_state(Process *p,
                                       ErtsAppendContext *from_context) {
     ErtsAppendContext *to_context;
@@ -203,6 +233,11 @@ static BIF_RETTYPE lists_append_onheap(Process *p, ErtsAppendContext *context) {
 }
 
 static int append_continue(Process *p, ErtsAppendContext *context) {
+    /* Fast-lane when the rhs is nil: return lhs. */
+    if (is_nil(context->rhs_original)) {
+        return append_empty_rhs(p, context);
+    }
+
     /* We build the result on the unused part of the heap if possible to save
      * us the trouble of having to figure out the list size. We fall back to
      * lists_append_alloc when we run out of space. */
@@ -906,7 +941,12 @@ static int subtract_continue(Process *p, ErtsSubtractContext *context) {
                 return res;
             }
 
-            if (context->lhs_remaining <= SUBTRACT_LHS_THRESHOLD) {
+            /* If the lhs list is empty then there's nothing to do.
+             * Returning early will be taken care of in the `SUBTRACT_STAGE_LEN_RHS`
+             * stage after the rhs list has been scanned. */
+            if (context->lhs_remaining > 0 &&
+                context->lhs_remaining <= SUBTRACT_LHS_THRESHOLD &&
+                is_list(context->rhs_original)) {
                 return subtract_enter_naive_lhs(p, context);
             }
 
@@ -926,6 +966,20 @@ static int subtract_continue(Process *p, ErtsSubtractContext *context) {
                 return res;
             }
 
+            /* If the lhs list is empty then the subtraction must return nil. */
+            if (context->lhs_remaining == 0) {
+                ASSERT(is_nil(context->lhs_original));
+                context->result = NIL;
+                return 1;
+            }
+            /* If the rhs list is empty then the subtraction should return the
+             * lhs list unchanged. */
+            if (context->rhs_remaining == 0) {
+                ASSERT(is_nil(context->rhs_original));
+                context->result = context->lhs_original;
+                return 1;
+            }
+
             /* We've walked through both lists fully now so we no longer need
              * to check for errors past this point. */
 
-- 
2.43.0

openSUSE Build Service is sponsored by