Skip to content

Commit 4e5374b

Browse files
committed
Merge pull request #2338 from pguyot/w25/jit_bitstring_extract_float-add-missing-nogc-alloc
JIT: add missing memory_ensure_free in jit_bitstring_extract_float These changes are made under both the "Apache 2.0" and the "GNU Lesser General Public License 2.1 or later" license terms (dual license). SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later
2 parents 1e3f501 + f5fe9a3 commit 4e5374b

7 files changed

Lines changed: 86 additions & 24 deletions

File tree

libs/jit/src/jit.erl

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1334,7 +1334,7 @@ first_pass(<<?OP_BS_GET_FLOAT2, Rest0/binary>>, MMod, MSt0, State0) ->
13341334
?ASSERT_ALL_NATIVE_FREE(MSt0),
13351335
{Fail, Rest1} = decode_label(Rest0),
13361336
{MSt1, Src, Rest2} = decode_typed_compact_term(Rest1, MMod, MSt0, State0),
1337-
{_Live, Rest3} = decode_literal(Rest2),
1337+
{Live, Rest3} = decode_literal(Rest2),
13381338
{MSt2, Size, Rest4} = decode_typed_compact_term(Rest3, MMod, MSt1, State0),
13391339
{Unit, Rest5} = decode_literal(Rest4),
13401340
{FlagsValue, Rest6} = decode_literal(Rest5),
@@ -1348,24 +1348,19 @@ first_pass(<<?OP_BS_GET_FLOAT2, Rest0/binary>>, MMod, MSt0, State0) ->
13481348
MSt5 = MMod:mul(MSt4, SizeReg, Unit),
13491349
{MSt5, SizeReg}
13501350
end,
1351-
{MSt7, BSBinaryReg} = MMod:get_array_element(MSt6, MatchStateRegPtr, 1),
1352-
{MSt8, BSOffsetReg} = MMod:get_array_element(MSt7, MatchStateRegPtr, 2),
1353-
{MSt9, Result} = MMod:call_primitive(MSt8, ?PRIM_BITSTRING_EXTRACT_FLOAT, [
1354-
ctx, {free, BSBinaryReg}, BSOffsetReg, NumBits, {free, FlagsValue}
1351+
{MSt7, Result} = MMod:call_primitive(MSt6, ?PRIM_BITSTRING_EXTRACT_FLOAT, [
1352+
ctx, jit_state, {free, MatchStateRegPtr}, {free, NumBits}, {free, FlagsValue}, Live
13551353
]),
1356-
MSt10 = cond_jump_to_label({Result, '==', ?FALSE_ATOM}, Fail, MMod, MSt9),
1357-
MSt11 = MMod:add(MSt10, BSOffsetReg, NumBits),
1358-
MSt12 = MMod:free_native_registers(MSt11, [NumBits]),
1359-
MSt13 = MMod:move_to_array_element(MSt12, BSOffsetReg, MatchStateRegPtr, 2),
1360-
MSt14 = MMod:free_native_registers(MSt13, [BSOffsetReg, MatchStateRegPtr]),
1361-
{MSt15, Dest, Rest7} = decode_dest(Rest6, MMod, MSt14),
1354+
MSt8 = handle_error_if({Result, '==', 0}, MMod, MSt7),
1355+
MSt9 = cond_jump_to_label({Result, '==', ?FALSE_ATOM}, Fail, MMod, MSt8),
1356+
{MSt10, Dest, Rest7} = decode_dest(Rest6, MMod, MSt9),
13621357
?TRACE("OP_BS_GET_FLOAT2 ~p,~p,~p,~p,~p,~p,~p\n", [
1363-
Fail, Src, _Live, Size, Unit, FlagsValue, Dest
1358+
Fail, Src, Live, Size, Unit, FlagsValue, Dest
13641359
]),
1365-
MSt16 = MMod:move_to_vm_register(MSt15, Result, Dest),
1366-
MSt17 = MMod:free_native_registers(MSt16, [Result]),
1367-
?ASSERT_ALL_NATIVE_FREE(MSt17),
1368-
first_pass(Rest7, MMod, MSt17, State0);
1360+
MSt11 = MMod:move_to_vm_register(MSt10, Result, Dest),
1361+
MSt12 = MMod:free_native_registers(MSt11, [Result]),
1362+
?ASSERT_ALL_NATIVE_FREE(MSt12),
1363+
first_pass(Rest7, MMod, MSt12, State0);
13691364
% 119
13701365
first_pass(<<?OP_BS_GET_BINARY2, Rest0/binary>>, MMod, MSt0, State0) ->
13711366
?ASSERT_ALL_NATIVE_FREE(MSt0),

src/libAtomVM/jit.c

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1522,27 +1522,34 @@ static term jit_bitstring_extract_integer(
15221522
}
15231523
}
15241524

1525-
static term jit_bitstring_extract_float(Context *ctx, term *bin_ptr, size_t offset, int n, int bs_flags)
1525+
static term jit_bitstring_extract_float(Context *ctx, JITState *jit_state, term *match_state_ptr, int n, int bs_flags, int live)
15261526
{
1527-
TRACE("jit_bitstring_extract_float: bin_ptr=%p offset=%d n=%d bs_flags=%d\n", (void *) bin_ptr, (int) offset, n, bs_flags);
1527+
TRACE("jit_bitstring_extract_float: match_state_ptr=%p n=%d bs_flags=%d live=%d\n", (void *) match_state_ptr, n, bs_flags, live);
1528+
avm_int_t offset = (avm_int_t) match_state_ptr[2];
15281529
avm_float_t value;
15291530
bool status;
15301531
switch (n) {
15311532
case 16:
1532-
status = bitstring_extract_f16((term) (((uintptr_t) bin_ptr) | TERM_PRIMARY_BOXED), offset, n, bs_flags, &value);
1533+
status = bitstring_extract_f16(match_state_ptr[1], offset, n, bs_flags, &value);
15331534
break;
15341535
case 32:
1535-
status = bitstring_extract_f32((term) (((uintptr_t) bin_ptr) | TERM_PRIMARY_BOXED), offset, n, bs_flags, &value);
1536+
status = bitstring_extract_f32(match_state_ptr[1], offset, n, bs_flags, &value);
15361537
break;
15371538
case 64:
1538-
status = bitstring_extract_f64((term) (((uintptr_t) bin_ptr) | TERM_PRIMARY_BOXED), offset, n, bs_flags, &value);
1539+
status = bitstring_extract_f64(match_state_ptr[1], offset, n, bs_flags, &value);
15391540
break;
15401541
default:
15411542
status = false;
15421543
}
15431544
if (UNLIKELY(!status)) {
15441545
return FALSE_ATOM;
15451546
}
1547+
match_state_ptr[2] = (term) (offset + n);
1548+
TRIM_LIVE_REGS(live);
1549+
if (UNLIKELY(memory_ensure_free_with_roots(ctx, FLOAT_SIZE, live, ctx->x, MEMORY_CAN_SHRINK) != MEMORY_GC_OK)) {
1550+
set_error(ctx, jit_state, 0, OUT_OF_MEMORY_ATOM);
1551+
return term_invalid_term();
1552+
}
15461553
return term_from_float(value, &ctx->heap);
15471554
}
15481555

src/libAtomVM/jit.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ struct ModuleNativeInterface
234234
void *(*malloc)(Context *ctx, JITState *jit_state, size_t sz);
235235
void (*free)(void *ptr);
236236
term (*put_map_assoc)(Context *ctx, JITState *jit_state, term src, size_t new_entries, size_t num_elements, term *kv);
237-
term (*bitstring_extract_float)(Context *ctx, term *bin_ptr, size_t offset, int n, int bs_flags);
237+
term (*bitstring_extract_float)(Context *ctx, JITState *jit_state, term *match_state_ptr, int n, int bs_flags, int live);
238238
int (*module_get_fun_arity)(Module *fun_module, uint32_t fun_index);
239239
bool (*bitstring_match_module_str)(Context *ctx, JITState *jit_state, term bin, size_t offset, int str_id, size_t len);
240240
term (*bitstring_get_utf8)(term src);

src/libAtomVM/opcodesswitch.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4399,7 +4399,6 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb)
43994399
term src;
44004400
DECODE_COMPACT_TERM(src, pc);
44014401
uint32_t live;
4402-
UNUSED(live);
44034402
DECODE_LITERAL(live, pc);
44044403
term size;
44054404
DECODE_COMPACT_TERM(size, pc);
@@ -4442,7 +4441,8 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb)
44424441
} else {
44434442
term_set_match_state_offset(src, bs_offset + increment);
44444443

4445-
if (UNLIKELY(memory_ensure_free_opt(ctx, FLOAT_SIZE, MEMORY_NO_GC) != MEMORY_GC_OK)) {
4444+
TRIM_LIVE_REGS(live);
4445+
if (UNLIKELY(memory_ensure_free_with_roots(ctx, FLOAT_SIZE, live, x_regs, MEMORY_CAN_SHRINK) != MEMORY_GC_OK)) {
44464446
RAISE_ERROR(OUT_OF_MEMORY_ATOM);
44474447
}
44484448
term t = term_from_float(value, &ctx->heap);

tests/erlang_tests/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -570,6 +570,7 @@ compile_erlang(bs_context_byte_size)
570570
compile_erlang(bs_get_binary_fixed_size)
571571
compile_erlang(bs_get_integer_fixed_size)
572572
compile_erlang(bs_get_float_dynamic_size)
573+
compile_erlang(bs_get_float_gc)
573574
compile_erlang(test_is_not_equal)
574575
compile_assembler(test_is_not_equal_asm)
575576
compile_erlang(test_make_fun2)
@@ -1139,6 +1140,7 @@ set(erlang_test_beams
11391140
bs_get_binary_fixed_size.beam
11401141
bs_get_integer_fixed_size.beam
11411142
bs_get_float_dynamic_size.beam
1143+
bs_get_float_gc.beam
11421144
test_is_not_equal.beam
11431145
test_is_not_equal_asm.beam
11441146
test_make_fun2.beam
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
%
2+
% This file is part of AtomVM.
3+
%
4+
% Copyright 2026 Paul Guyot <pguyot@kallisys.net>
5+
%
6+
% Licensed under the Apache License, Version 2.0 (the "License");
7+
% you may not use this file except in compliance with the License.
8+
% You may obtain a copy of the License at
9+
%
10+
% http://www.apache.org/licenses/LICENSE-2.0
11+
%
12+
% Unless required by applicable law or agreed to in writing, software
13+
% distributed under the License is distributed on an "AS IS" BASIS,
14+
% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
% See the License for the specific language governing permissions and
16+
% limitations under the License.
17+
%
18+
% SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later
19+
%
20+
21+
-module(bs_get_float_gc).
22+
23+
%% Force the compiler to use bs_get_float2 opcode instead of the
24+
%% newer bs_match opcode. The no_bs_match option was removed in OTP 29.
25+
-if(?OTP_RELEASE =< 28).
26+
-compile([no_bs_match]).
27+
-endif.
28+
29+
-export([start/0, id/1]).
30+
31+
start() ->
32+
Bin = id(<<3.14:64/float, 2.5:32/float>>),
33+
Acc = loop(2000, Bin, []),
34+
2000 = length(Acc),
35+
ok = check(Acc),
36+
0.
37+
38+
loop(0, _Bin, Acc) ->
39+
Acc;
40+
loop(N, Bin, Acc) ->
41+
<<F64:64/float, F32:32/float>> = Bin,
42+
_ = id(make_list(32, [])),
43+
loop(N - 1, Bin, [{F64, F32} | Acc]).
44+
45+
make_list(0, Acc) ->
46+
Acc;
47+
make_list(N, Acc) ->
48+
make_list(N - 1, [N | Acc]).
49+
50+
check([]) ->
51+
ok;
52+
check([{F64, F32} | Tail]) ->
53+
true = (F64 > 3.139) andalso (F64 < 3.141),
54+
true = (F32 > 2.49) andalso (F32 < 2.51),
55+
check(Tail).
56+
57+
id(X) -> X.

tests/test.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,7 @@ struct Test tests[] = {
536536
TEST_CASE(bs_get_binary_fixed_size),
537537
TEST_CASE(bs_get_integer_fixed_size),
538538
TEST_CASE(bs_get_float_dynamic_size),
539+
TEST_CASE(bs_get_float_gc),
539540
TEST_CASE(test_is_not_equal),
540541
TEST_CASE(test_make_fun2),
541542
TEST_CASE(test_allocate_zero),

0 commit comments

Comments
 (0)