Skip to content

Commit 1549382

Browse files
committed
Merge pull request atomvm#525 from pguyot/w17/fix-fun-external-and-apply
Fix call and encoding/decoding of function references Fix a bug where call of function references would fail Fix a warning related to encoding of function references Implement decoding of function references 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 9090844 + 5ccbfd5 commit 1549382

File tree

6 files changed

+56
-5
lines changed

6 files changed

+56
-5
lines changed

src/libAtomVM/bif.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,13 @@ term bif_erlang_is_boolean_1(Context *ctx, term arg1)
116116
return (arg1 == TRUE_ATOM || arg1 == FALSE_ATOM) ? TRUE_ATOM : FALSE_ATOM;
117117
}
118118

119+
term bif_erlang_is_function_1(Context *ctx, term arg1)
120+
{
121+
UNUSED(ctx);
122+
123+
return term_is_function(arg1) ? TRUE_ATOM : FALSE_ATOM;
124+
}
125+
119126
term bif_erlang_is_integer_1(Context *ctx, term arg1)
120127
{
121128
UNUSED(ctx);

src/libAtomVM/bif.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ term bif_erlang_length_1(Context *ctx, int live, term arg1);
5050
term bif_erlang_is_atom_1(Context *ctx, term arg1);
5151
term bif_erlang_is_binary_1(Context *ctx, term arg1);
5252
term bif_erlang_is_boolean_1(Context *ctx, term arg1);
53+
term bif_erlang_is_function_1(Context *ctx, term arg1);
5354
term bif_erlang_is_integer_1(Context *ctx, term arg1);
5455
term bif_erlang_is_list_1(Context *ctx, term arg1);
5556
term bif_erlang_is_number_1(Context *ctx, term arg1);

src/libAtomVM/bifs.gperf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ erlang:get/1, bif_erlang_get_1, false
4040
erlang:is_atom/1, bif_erlang_is_atom_1, false
4141
erlang:is_binary/1, bif_erlang_is_binary_1, false
4242
erlang:is_boolean/1, bif_erlang_is_boolean_1, false
43+
erlang:is_function/1, bif_erlang_is_function_1, false
4344
erlang:is_integer/1, bif_erlang_is_integer_1, false
4445
erlang:is_list/1, bif_erlang_is_list_1, false
4546
erlang:is_number/1, bif_erlang_is_number_1, false

src/libAtomVM/externalterm.c

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -373,7 +373,17 @@ static int serialize_term(Context *ctx, uint8_t *buf, term t)
373373
k += serialize_term(ctx, IS_NULL_PTR(buf) ? NULL : buf + k, value);
374374
}
375375
return k;
376-
376+
} else if (term_is_function(t)) {
377+
if (!IS_NULL_PTR(buf)) {
378+
buf[0] = EXPORT_EXT;
379+
}
380+
size_t k = 1;
381+
const term *boxed_value = term_to_const_term_ptr(t);
382+
for (size_t i = 1; i <= 3; ++i) {
383+
term mfa = boxed_value[i];
384+
k += serialize_term(ctx, IS_NULL_PTR(buf) ? NULL : buf + k, mfa);
385+
}
386+
return k;
377387
} else {
378388
fprintf(stderr, "Unknown external term type: %" TERM_U_FMT "\n", t);
379389
AVM_ABORT();
@@ -780,6 +790,7 @@ static int calculate_heap_usage(const uint8_t *external_term_buf, size_t remaini
780790
}
781791
int heap_usage = 1;
782792
int buf_pos = 1;
793+
remaining -= 1;
783794
for (int i = 0; i < 3; i++) {
784795
int element_size = 0;
785796
int u = calculate_heap_usage(external_term_buf + buf_pos, remaining, &element_size, copy, ctx);
@@ -796,7 +807,7 @@ static int calculate_heap_usage(const uint8_t *external_term_buf, size_t remaini
796807
}
797808

798809
*eterm_size = buf_pos;
799-
return FUNCTION_REFERENCE_SIZE;
810+
return heap_usage;
800811
}
801812

802813
case MAP_EXT: {

src/libAtomVM/opcodesswitch.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -762,7 +762,7 @@ typedef union
762762
AtomString function_name = globalcontext_atomstring_from_term(mod->global, index_or_function); \
763763
struct Nif *nif = (struct Nif *) nifs_get(module_name, function_name, fun_arity); \
764764
if (!IS_NULL_PTR(nif)) { \
765-
term return_value = nif->nif_ptr(ctx, arity, ctx->x); \
765+
term return_value = nif->nif_ptr(ctx, fun_arity, ctx->x); \
766766
if (UNLIKELY(term_is_invalid_term(return_value))) { \
767767
HANDLE_ERROR(); \
768768
} \
@@ -774,7 +774,7 @@ typedef union
774774
if (IS_NULL_PTR(fun_module)) { \
775775
HANDLE_ERROR(); \
776776
} \
777-
label = module_search_exported_function(fun_module, function_name, arity); \
777+
label = module_search_exported_function(fun_module, function_name, fun_arity); \
778778
if (UNLIKELY(label == 0)) { \
779779
HANDLE_ERROR(); \
780780
} \

tests/erlang_tests/test_binary_to_term.erl

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020

2121
-module(test_binary_to_term).
2222

23-
-export([start/0]).
23+
-export([start/0, apply/2, apply/3]).
2424

2525
start() ->
2626
test_reverse(foo, <<131, 100, 0, 3, 102, 111, 111>>),
@@ -61,6 +61,7 @@ start() ->
6161
57, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 48,
6262
49, 50, 51, 52, 53>>
6363
),
64+
ok = test_external_function(),
6465

6566
{32768, 6} = erlang:binary_to_term(<<131, 98, 0, 0, 128, 0, 127>>, [used]),
6667
test_catentate_and_split([foo, bar, 128, {foo, bar}, [a, b, c, {d}]]),
@@ -138,6 +139,36 @@ mutate_bin(Bin, I) ->
138139
I2 = Ith bxor 16#FF,
139140
<<Prefix/binary, I2:8/integer-unsigned, Rest/binary>>.
140141

142+
test_external_function() ->
143+
Bin = term_to_binary([fun ?MODULE:apply/2, fun ?MODULE:apply/3]),
144+
Bin =
145+
<<131, 108, 0, 0, 0, 2, 113, 100, 0, 19, 116, 101, 115, 116, 95, 98, 105, 110, 97, 114, 121,
146+
95, 116, 111, 95, 116, 101, 114, 109, 100, 0, 5, 97, 112, 112, 108, 121, 97, 2, 113,
147+
100, 0, 19, 116, 101, 115, 116, 95, 98, 105, 110, 97, 114, 121, 95, 116, 111, 95, 116,
148+
101, 114, 109, 100, 0, 5, 97, 112, 112, 108, 121, 97, 3, 106>>,
149+
[Fun2, Fun3] = binary_to_term(Bin),
150+
true = is_function(Fun2),
151+
true = is_function(Fun3),
152+
42 = Fun2(fun() -> 42 end, []),
153+
42 = Fun3(?MODULE, apply, [fun() -> 42 end, []]),
154+
42 = Fun3(?MODULE, apply, [Fun2, [fun() -> 42 end, []]]),
155+
ok.
156+
157+
% We don't have access to erlang module in tests.
158+
apply(F, []) ->
159+
F();
160+
apply(F, [X]) ->
161+
F(X);
162+
apply(F, [X, Y]) ->
163+
F(X, Y).
164+
165+
apply(M, F, []) ->
166+
M:F();
167+
apply(M, F, [X]) ->
168+
M:F(X);
169+
apply(M, F, [X, Y]) ->
170+
M:F(X, Y).
171+
141172
expect_badarg(Fun) ->
142173
try
143174
Fun(),

0 commit comments

Comments
 (0)