Skip to content

Commit

Permalink
Make sub-binaries of sub-binaries sub-binaries
Browse files Browse the repository at this point in the history
Fix a bug where sub-binaries of sub-binaries were reallocated, thus wasting
memory.

Signed-off-by: Paul Guyot <[email protected]>
  • Loading branch information
pguyot committed Oct 28, 2023
1 parent 92eed62 commit dcc47d3
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 3 deletions.
3 changes: 3 additions & 0 deletions src/libAtomVM/term.h
Original file line number Diff line number Diff line change
Expand Up @@ -1040,6 +1040,9 @@ static inline term term_maybe_create_sub_binary(term binary, size_t offset, size
{
if (term_is_refc_binary(binary) && len >= SUB_BINARY_MIN) {
return term_alloc_sub_binary(binary, offset, len, heap);
} else if (term_is_sub_binary(binary) && len >= SUB_BINARY_MIN) {
const term *boxed_value = term_to_const_term_ptr(binary);
return term_alloc_sub_binary(boxed_value[3], boxed_value[2] + offset, len, heap);
} else {
const char *data = term_binary_data(binary);
return term_from_literal_binary(data + offset, len, heap, glb);
Expand Down
23 changes: 20 additions & 3 deletions tests/erlang_tests/test_sub_binaries.erl
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ start() ->

test_common() ->
ok = run_test(fun() -> test_count_binary() end),
ok = run_test(fun() -> test_sub_sub_binary() end),
ok.

test_atom() ->
Expand All @@ -72,6 +73,14 @@ test_atom() ->
ok = run_test(fun() -> test_bit_syntax_get_binary() end),
ok.

test_sub_sub_binary() ->
Bin = create_binary(get_largest_heap_binary_size()),

SubBin = binary:part(Bin, 1, 7),
<<2, 3, 4, 5, 6, 7, 8>> = SubBin,
<<4, 5, 6, 7, 8>> = binary:part(SubBin, 2, 5),
ok.

test_heap_sub_binary() ->
MemoryBinarySize = erlang:memory(binary),
HeapSize0 = get_heap_size(),
Expand All @@ -80,7 +89,7 @@ test_heap_sub_binary() ->
HeapSize1 = get_heap_size(),
?VERIFY(HeapSize0 < HeapSize1),

SubBin = binary:part(Bin, 1, 7),
SubBin = binary:part(Bin, 1, 47),
HeapSize2 = get_heap_size(),
?VERIFY(HeapSize1 < HeapSize2),
?VERIFY((HeapSize2 - HeapSize1) >= 8),
Expand All @@ -104,11 +113,19 @@ test_const_sub_binary() ->

LargeSubBin = binary:part(?LITERAL_BIN, 1, BinarySize - 1),
HeapSize2 = get_heap_size(),
?VERIFY(HeapSize2 < HeapSize1 + erlang:byte_size(LargeSubBin)),
?VERIFY((HeapSize2 - HeapSize1) >= 8),
?VERIFY((HeapSize2 - HeapSize1) < BinarySize div 4),
?VERIFY(MemoryBinarySize == erlang:memory(binary)),

SubSubBin = binary:part(LargeSubBin, 0, BinarySize - 2),
HeapSize3 = get_heap_size(),
?VERIFY((HeapSize3 - HeapSize2) >= 8),
?VERIFY((HeapSize3 - HeapSize2) < BinarySize div 4),
?VERIFY(MemoryBinarySize == erlang:memory(binary)),

id(SmallSubBin),
id(LargeSubBin),
id(SubSubBin),
ok.

test_non_const_sub_binary() ->
Expand All @@ -126,7 +143,7 @@ test_non_const_sub_binary() ->

LargeSubBin = binary:part(Bin, 1, BinarySize - 1),
HeapSize3 = get_heap_size(),
?VERIFY(HeapSize3 < HeapSize2 + erlang:byte_size(LargeSubBin)),
?VERIFY((HeapSize3 - HeapSize2) < BinarySize div 4),
?VERIFY(MemoryBinarySize + 1024 == erlang:memory(binary)),

id(String),
Expand Down

0 comments on commit dcc47d3

Please sign in to comment.