Skip to content

Commit 5ccbfd5

Browse files
committed
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 Also add is_function bif for OTP21 Signed-off-by: Paul Guyot <[email protected]>
1 parent 14dea42 commit 5ccbfd5

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
@@ -758,7 +758,7 @@ typedef union
758758
AtomString function_name = globalcontext_atomstring_from_term(mod->global, index_or_function); \
759759
struct Nif *nif = (struct Nif *) nifs_get(module_name, function_name, fun_arity); \
760760
if (!IS_NULL_PTR(nif)) { \
761-
term return_value = nif->nif_ptr(ctx, arity, ctx->x); \
761+
term return_value = nif->nif_ptr(ctx, fun_arity, ctx->x); \
762762
if (UNLIKELY(term_is_invalid_term(return_value))) { \
763763
HANDLE_ERROR(); \
764764
} \
@@ -770,7 +770,7 @@ typedef union
770770
if (IS_NULL_PTR(fun_module)) { \
771771
HANDLE_ERROR(); \
772772
} \
773-
label = module_search_exported_function(fun_module, function_name, arity); \
773+
label = module_search_exported_function(fun_module, function_name, fun_arity); \
774774
if (UNLIKELY(label == 0)) { \
775775
HANDLE_ERROR(); \
776776
} \

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)