File 2270-Replace-binary-bin_to_list-CIF-implementation-with-b.patch of Package erlang

From 2627297ad239697c7df297b8fde35f9827fa962f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?John=20H=C3=B6gberg?= <john@erlang.org>
Date: Mon, 26 Feb 2018 16:27:39 +0100
Subject: [PATCH] Replace binary:bin_to_list CIF implementation with
 binary_to_list

binary:bin_to_list had a poor implementation that resulted in
excessive garbage collection. binary_to_list is almost identical and
has a generally better implementation, so I've replaced
binary:bin_to_list's CIF with a thin wrapper around binary_to_list.

Granted, binary_to_list has a deprecated indexing scheme, but we're
unlikely to ever remote it entirely and it's somewhat easy to move
it to the 'binary' module later on.
---
 erts/emulator/beam/atom.names         |   1 -
 erts/emulator/beam/bif.tab            |   3 -
 erts/emulator/beam/erl_bif_binary.c   | 191 ----------------------------------
 lib/stdlib/src/binary.erl             |  28 +++--
 5 files changed, 22 insertions(+), 201 deletions(-)

diff --git a/erts/emulator/beam/atom.names b/erts/emulator/beam/atom.names
index b6ec3e7ed2..42a368cdd8 100644
--- a/erts/emulator/beam/atom.names
+++ b/erts/emulator/beam/atom.names
@@ -124,7 +124,6 @@ atom big
 atom bif_return_trap
 atom bif_timer_server
 atom binary
-atom binary_bin_to_list_trap
 atom binary_copy_trap
 atom binary_find_trap
 atom binary_longest_prefix_trap
diff --git a/erts/emulator/beam/bif.tab b/erts/emulator/beam/bif.tab
index b5725e4185..0d1166f6ed 100644
--- a/erts/emulator/beam/bif.tab
+++ b/erts/emulator/beam/bif.tab
@@ -551,9 +551,6 @@ bif binary:last/1
 bif binary:at/2
 bif binary:part/2 binary_binary_part_2
 bif binary:part/3 binary_binary_part_3
-bif binary:bin_to_list/1
-bif binary:bin_to_list/2
-bif binary:bin_to_list/3
 bif binary:list_to_bin/1
 bif binary:copy/1
 bif binary:copy/2
diff --git a/erts/emulator/beam/erl_bif_binary.c b/erts/emulator/beam/erl_bif_binary.c
index 41c2ae08d3..33bc189182 100644
--- a/erts/emulator/beam/erl_bif_binary.c
+++ b/erts/emulator/beam/erl_bif_binary.c
@@ -61,8 +61,6 @@ static Export binary_longest_prefix_trap_export;
 static BIF_RETTYPE binary_longest_prefix_trap(BIF_ALIST_3);
 static Export binary_longest_suffix_trap_export;
 static BIF_RETTYPE binary_longest_suffix_trap(BIF_ALIST_3);
-static Export binary_bin_to_list_trap_export;
-static BIF_RETTYPE binary_bin_to_list_trap(BIF_ALIST_3);
 static Export binary_copy_trap_export;
 static BIF_RETTYPE binary_copy_trap(BIF_ALIST_2);
 static Uint max_loop_limit;
@@ -86,10 +84,6 @@ void erts_init_bif_binary(void)
 			  am_erlang, am_binary_longest_suffix_trap, 3,
 			  &binary_longest_suffix_trap);
 
-    erts_init_trap_export(&binary_bin_to_list_trap_export,
-			  am_erlang, am_binary_bin_to_list_trap, 3,
-			  &binary_bin_to_list_trap);
-
     erts_init_trap_export(&binary_copy_trap_export,
 			  am_erlang, am_binary_copy_trap, 2,
 			  &binary_copy_trap);
@@ -2440,191 +2434,6 @@ BIF_RETTYPE binary_at_2(BIF_ALIST_2)
     BIF_ERROR(BIF_P,BADARG);
 }
 
-#define BIN_TO_LIST_OK 0
-#define BIN_TO_LIST_TRAP 1
-/* No badarg, checked before call */
-
-#define BIN_TO_LIST_LOOP_FACTOR 10
-
-static int do_bin_to_list(Process *p, byte *bytes, Uint bit_offs,
-			  Uint start, Sint *lenp, Eterm *termp)
-{
-    Uint reds = get_reds(p, BIN_TO_LIST_LOOP_FACTOR); /* reds can never be 0 */
-    Uint len = *lenp;
-    Uint loops;
-    Eterm *hp;
-    Eterm term = *termp;
-    Uint n;
-
-    ASSERT(reds > 0);
-
-    loops = MIN(reds,len);
-
-    BUMP_REDS(p, loops / BIN_TO_LIST_LOOP_FACTOR);
-
-    hp = HAlloc(p,2*loops);
-    while (loops--) {
-	--len;
-	if (bit_offs) {
-	    n = ((((Uint) bytes[start+len]) << bit_offs) |
-		 (((Uint) bytes[start+len+1]) >> (8-bit_offs))) & 0xFF;
-	} else {
-	    n = bytes[start+len];
-	}
-
-	term = CONS(hp,make_small(n),term);
-	hp +=2;
-    }
-    *termp = term;
-    *lenp = len;
-    if (len) {
-	BUMP_ALL_REDS(p);
-	return BIN_TO_LIST_TRAP;
-    }
-    return BIN_TO_LIST_OK;
-}
-
-
-static BIF_RETTYPE do_trap_bin_to_list(Process *p, Eterm binary,
-				       Uint start, Sint len, Eterm sofar)
-{
-    Eterm *hp;
-    Eterm blob;
-
-    hp = HAlloc(p,3);
-    hp[0] = make_pos_bignum_header(2);
-    hp[1] = start;
-    hp[2] = (Uint) len;
-    blob = make_big(hp);
-    BIF_TRAP3(&binary_bin_to_list_trap_export, p, binary, blob, sofar);
-}
-
-static BIF_RETTYPE binary_bin_to_list_trap(BIF_ALIST_3)
-{
-    Eterm *ptr;
-    Uint start;
-    Sint len;
-    byte *bytes;
-    Uint bit_offs;
-    Uint bit_size;
-    Eterm res = BIF_ARG_3;
-
-    ptr  = big_val(BIF_ARG_2);
-    start = ptr[1];
-    len = (Sint) ptr[2];
-
-    ERTS_GET_BINARY_BYTES(BIF_ARG_1,bytes,bit_offs,bit_size);
-    if (do_bin_to_list(BIF_P, bytes, bit_offs, start, &len, &res) ==
-	BIN_TO_LIST_OK) {
-	BIF_RET(res);
-    }
-    return do_trap_bin_to_list(BIF_P,BIF_ARG_1,start,len,res);
-}
-
-static BIF_RETTYPE binary_bin_to_list_common(Process *p,
-					     Eterm bin,
-					     Eterm epos,
-					     Eterm elen)
-{
-    Uint pos;
-    Sint len;
-    size_t sz;
-    byte *bytes;
-    Uint bit_offs;
-    Uint bit_size;
-    Eterm res = NIL;
-
-    if (is_not_binary(bin)) {
-	goto badarg;
-    }
-    if (!term_to_Uint(epos, &pos)) {
-	goto badarg;
-    }
-    if (!term_to_Sint(elen, &len)) {
-	goto badarg;
-    }
-    if (len < 0) {
-	Uint lentmp = -(Uint)len;
-	/* overflow */
-	if ((Sint)lentmp < 0) {
-	    goto badarg;
-	}
-	len = lentmp;
-	if (len > pos) {
-	    goto badarg;
-	}
-	pos -= len;
-    }
-    /* overflow */
-    if ((pos + len) < pos || (len > 0 && (pos + len) == pos)) {
-	goto badarg;
-    }
-    sz = binary_size(bin);
-
-    if (pos+len > sz) {
-	goto badarg;
-    }
-    ERTS_GET_BINARY_BYTES(bin,bytes,bit_offs,bit_size);
-    if (bit_size != 0) {
-	goto badarg;
-    }
-    if(do_bin_to_list(p, bytes, bit_offs, pos, &len, &res) ==
-       BIN_TO_LIST_OK) {
-	BIF_RET(res);
-    }
-    return do_trap_bin_to_list(p,bin,pos,len,res);
-
- badarg:
-    BIF_ERROR(p,BADARG);
-}
-
-BIF_RETTYPE binary_bin_to_list_3(BIF_ALIST_3)
-{
-    return binary_bin_to_list_common(BIF_P,BIF_ARG_1,BIF_ARG_2,BIF_ARG_3);
-}
-
-BIF_RETTYPE binary_bin_to_list_2(BIF_ALIST_2)
-{
-    Eterm *tp;
-
-    if (is_not_tuple(BIF_ARG_2)) {
-	goto badarg;
-    }
-    tp = tuple_val(BIF_ARG_2);
-    if (arityval(*tp) != 2) {
-	goto badarg;
-    }
-    return binary_bin_to_list_common(BIF_P,BIF_ARG_1,tp[1],tp[2]);
- badarg:
-    BIF_ERROR(BIF_P,BADARG);
-}
-
-BIF_RETTYPE binary_bin_to_list_1(BIF_ALIST_1)
-{
-    Uint pos = 0;
-    Sint len;
-    byte *bytes;
-    Uint bit_offs;
-    Uint bit_size;
-    Eterm res = NIL;
-
-    if (is_not_binary(BIF_ARG_1)) {
-	goto badarg;
-    }
-    len = binary_size(BIF_ARG_1);
-    ERTS_GET_BINARY_BYTES(BIF_ARG_1,bytes,bit_offs,bit_size);
-    if (bit_size != 0) {
-	goto badarg;
-    }
-    if(do_bin_to_list(BIF_P, bytes, bit_offs, pos, &len, &res) ==
-       BIN_TO_LIST_OK) {
-	BIF_RET(res);
-    }
-    return do_trap_bin_to_list(BIF_P,BIF_ARG_1,pos,len,res);
- badarg:
-    BIF_ERROR(BIF_P,BADARG);
-}
-
 HIPE_WRAPPER_BIF_DISABLE_GC(binary_list_to_bin, 1)
 
 BIF_RETTYPE binary_list_to_bin_1(BIF_ALIST_1)
diff --git a/lib/stdlib/src/binary.erl b/lib/stdlib/src/binary.erl
index 6a64133b45..7d0e42489e 100644
--- a/lib/stdlib/src/binary.erl
+++ b/lib/stdlib/src/binary.erl
@@ -47,23 +47,39 @@ at(_, _) ->
 -spec bin_to_list(Subject) -> [byte()] when
       Subject :: binary().
 
-bin_to_list(_) ->
-    erlang:nif_error(undef).
+bin_to_list(Subject) ->
+    binary_to_list(Subject).
 
 -spec bin_to_list(Subject, PosLen) -> [byte()] when
       Subject :: binary(),
       PosLen :: part().
 
-bin_to_list(_, _) ->
-    erlang:nif_error(undef).
+bin_to_list(Subject, {Pos, Len}) ->
+    bin_to_list(Subject, Pos, Len);
+bin_to_list(_Subject, _BadArg) ->
+    erlang:error(badarg).
 
 -spec bin_to_list(Subject, Pos, Len) -> [byte()] when
       Subject :: binary(),
       Pos :: non_neg_integer(),
       Len :: integer().
 
-bin_to_list(_, _, _) ->
-    erlang:nif_error(undef).
+bin_to_list(Subject, Pos, Len) when not is_binary(Subject);
+                                    not is_integer(Pos);
+                                    not is_integer(Len) ->
+    %% binary_to_list/3 allows bitstrings as long as the slice fits, and we
+    %% want to badarg when Pos/Len aren't integers instead of raising badarith
+    %% when adjusting args for binary_to_list/3.
+    erlang:error(badarg);
+bin_to_list(Subject, Pos, 0) when Pos >= 0, Pos =< byte_size(Subject) ->
+    %% binary_to_list/3 doesn't handle this case.
+    [];
+bin_to_list(_Subject, _Pos, 0) ->
+    erlang:error(badarg);
+bin_to_list(Subject, Pos, Len) when Len < 0 ->
+    bin_to_list(Subject, Pos + Len, -Len);
+bin_to_list(Subject, Pos, Len) when Len > 0 ->
+    binary_to_list(Subject, Pos + 1, Pos + Len).
 
 -spec compile_pattern(Pattern) -> cp() when
       Pattern :: binary() | [binary()].
-- 
2.16.2

openSUSE Build Service is sponsored by