From 653d191a58e52def76bb68d5570c5844c4d1dbed Mon Sep 17 00:00:00 2001 From: Davide Bettio Date: Fri, 14 Feb 2025 22:58:28 +0100 Subject: [PATCH] Fix handling of BIFs as funs Fix funs such as `fun erlang:'not'/1`: only NIFs were supported before of this change. Signed-off-by: Davide Bettio --- CHANGELOG.md | 1 + src/libAtomVM/opcodesswitch.h | 5 ++-- tests/erlang_tests/CMakeLists.txt | 4 +++ tests/erlang_tests/fun_call_bif.erl | 46 +++++++++++++++++++++++++++++ tests/test.c | 1 + 5 files changed, 54 insertions(+), 3 deletions(-) create mode 100644 tests/erlang_tests/fun_call_bif.erl diff --git a/CHANGELOG.md b/CHANGELOG.md index fbfb24058..220785f48 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,7 @@ integers bug when handling errors from BIFs used as NIFs (when called with `CALL_EXT` and similar opcodes)` - Fix matching of binaries on unaligned boundaries for code compiled with older versions of OTP - Add missing out of memory handling in binary_to_atom +- Fixed call to funs such as fun erlang:'not'/1, that make use of BIFs ## [0.6.5] - 2024-10-15 diff --git a/src/libAtomVM/opcodesswitch.h b/src/libAtomVM/opcodesswitch.h index acd4eca2f..980508c53 100644 --- a/src/libAtomVM/opcodesswitch.h +++ b/src/libAtomVM/opcodesswitch.h @@ -1161,9 +1161,8 @@ static void destroy_extended_registers(Context *ctx, unsigned int live) fun_arity = term_to_int(boxed_value[3]); \ AtomString module_name = globalcontext_atomstring_from_term(glb, module); \ AtomString function_name = globalcontext_atomstring_from_term(glb, index_or_function); \ - struct Nif *nif = (struct Nif *) nifs_get(module_name, function_name, fun_arity); \ - if (!IS_NULL_PTR(nif)) { \ - term return_value = nif->nif_ptr(ctx, fun_arity, x_regs); \ + term return_value; \ + if (maybe_call_native(ctx, module_name, function_name, fun_arity, &return_value)) { \ PROCESS_MAYBE_TRAP_RETURN_VALUE(return_value); \ x_regs[0] = return_value; \ if (ctx->heap.root->next) { \ diff --git a/tests/erlang_tests/CMakeLists.txt b/tests/erlang_tests/CMakeLists.txt index 9623736a2..058863a50 100644 --- a/tests/erlang_tests/CMakeLists.txt +++ b/tests/erlang_tests/CMakeLists.txt @@ -197,6 +197,8 @@ compile_erlang(test_funs11) compile_erlang(test_make_fun3) +compile_erlang(fun_call_bif) + compile_erlang(complex_struct_size0) compile_erlang(complex_struct_size1) compile_erlang(complex_struct_size2) @@ -669,6 +671,8 @@ add_custom_target(erlang_test_modules DEPENDS test_make_fun3.beam + fun_call_bif.beam + complex_struct_size0.beam complex_struct_size1.beam complex_struct_size2.beam diff --git a/tests/erlang_tests/fun_call_bif.erl b/tests/erlang_tests/fun_call_bif.erl new file mode 100644 index 000000000..d85fd82d3 --- /dev/null +++ b/tests/erlang_tests/fun_call_bif.erl @@ -0,0 +1,46 @@ +% +% This file is part of AtomVM. +% +% Copyright 2025 Paul Guyot +% Copyright 2025 Davide Bettio +% +% Licensed under the Apache License, Version 2.0 (the "License"); +% you may not use this file except in compliance with the License. +% You may obtain a copy of the License at +% +% http://www.apache.org/licenses/LICENSE-2.0 +% +% Unless required by applicable law or agreed to in writing, software +% distributed under the License is distributed on an "AS IS" BASIS, +% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +% See the License for the specific language governing permissions and +% limitations under the License. +% +% SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later +% + +-module(fun_call_bif). + +-export([ + start/0, + g/2, + h/4 +]). + +start() -> + Fun1 = fun erlang:'not'/1, + A = ?MODULE:h(Fun1, true, false, 1) - 1, + R1 = erlang:list_to_existing_atom("start"), + Fun2 = fun erlang:list_to_existing_atom/1, + B = ?MODULE:g(Fun2, atom_to_list(R1)), + A + B. + +g(Fun, R1) -> + start = Fun(R1), + 0. + +h(Fun, In, Exp, V) -> + case Fun(In) of + Exp -> V; + _ -> 0 + end. diff --git a/tests/test.c b/tests/test.c index 0536d5740..4f554e5ac 100644 --- a/tests/test.c +++ b/tests/test.c @@ -234,6 +234,7 @@ struct Test tests[] = { TEST_CASE_EXPECTED(test_funs10, 6817), TEST_CASE_EXPECTED(test_funs11, 817), TEST_CASE(test_make_fun3), + TEST_CASE(fun_call_bif), TEST_CASE(nested_list_size0), TEST_CASE_EXPECTED(nested_list_size1, 2),