Skip to content

Commit

Permalink
Merge branch 'maint'
Browse files Browse the repository at this point in the history
* maint:
  compiler: Fix bug in `nif_start` insertion
  • Loading branch information
bjorng committed Jun 21, 2023
2 parents d030220 + abdac13 commit 6a95736
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 7 deletions.
7 changes: 6 additions & 1 deletion lib/compiler/src/v3_core.erl
Original file line number Diff line number Diff line change
Expand Up @@ -4097,7 +4097,12 @@ insert_nif_start([VF={V,F=#c_fun{body=Body}}|Funs]) ->
#c_case{} ->
NifStart = #c_primop{name=#c_literal{val=nif_start},args=[]},
[{V,F#c_fun{body=#c_seq{arg=NifStart,body=Body}}}
|insert_nif_start(Funs)]
|insert_nif_start(Funs)];
#c_letrec{defs=Defs,body=LetrecBody0}=LR0 ->
NifStart = #c_primop{name=#c_literal{val=nif_start},args=[]},
LetrecBody = #c_seq{arg=NifStart,body=LetrecBody0},
LR = LR0#c_letrec{defs=insert_nif_start(Defs), body=LetrecBody},
[{V,F#c_fun{body=LR}}|insert_nif_start(Funs)]
end;
insert_nif_start([]) ->
[].
Expand Down
33 changes: 28 additions & 5 deletions lib/compiler/test/core_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ nif(Conf) ->
nif_compile_to_cerl(Conf, [{d,'WITH_ATTRIBUTE'},{d,'WITH_LOAD_NIF'}]),
false = nif_first_instruction_is_nif_start(init, 1, Funs),
true = nif_first_instruction_is_nif_start(start, 1, Funs),
false = nif_first_instruction_is_nif_start(bug0, 1, Funs),
false = nif_first_instruction_is_nif_start(module_info, 0, Funs),
false = nif_first_instruction_is_nif_start(module_info, 1, Funs),
ok.
Expand All @@ -186,6 +187,7 @@ no_nif(Conf) ->
Funs = nif_compile_to_cerl(Conf, [{d,'WITH_LOAD_NIF'}]),
true = nif_first_instruction_is_nif_start(init, 1, Funs),
true = nif_first_instruction_is_nif_start(start, 1, Funs),
true = nif_first_instruction_is_nif_start(bug0, 1, Funs),
true = nif_first_instruction_is_nif_start(module_info, 0, Funs),
true = nif_first_instruction_is_nif_start(module_info, 1, Funs),
ok.
Expand All @@ -195,6 +197,7 @@ no_load_nif(Conf) ->
Funs = nif_compile_to_cerl(Conf, []),
false = nif_first_instruction_is_nif_start(init, 1, Funs),
false = nif_first_instruction_is_nif_start(start, 1, Funs),
false = nif_first_instruction_is_nif_start(bug0, 1, Funs),
false = nif_first_instruction_is_nif_start(module_info, 0, Funs),
false = nif_first_instruction_is_nif_start(module_info, 1, Funs),
ok.
Expand All @@ -207,11 +210,7 @@ nif_compile_to_cerl(Conf, Flags) ->

nif_first_instruction_is_nif_start(F, A, [{{F,A},Body}|_]) ->
try
Primop = cerl:seq_arg(Body),
Name = cerl:primop_name(Primop),
0 = cerl:primop_arity(Primop),
nif_start = cerl:atom_val(Name),
true
assert_body_starts_with_nif_start(Body)
catch
error:_ ->
false
Expand All @@ -220,3 +219,27 @@ nif_first_instruction_is_nif_start(F, A, [_|Rest]) ->
nif_first_instruction_is_nif_start(F, A, Rest);
nif_first_instruction_is_nif_start(_, _, []) ->
not_found.

%% Return true if the body starts with nif_start or not at all if
%% not. Descend into letrecs.
assert_body_starts_with_nif_start(Body0) ->
Body = case cerl:is_c_letrec(Body0) of
true ->
%% For the compiler generated functions in the
%% defs-part of the letrec, we just check that
%% they start with a nif-start, regardless of
%% their names.
lists:foreach(fun({_, F}) ->
assert_body_starts_with_nif_start(
cerl:fun_body(F))
end, cerl:letrec_defs(Body0)),
%% Return the body of the letrec for checking.
cerl:letrec_body(Body0);
false ->
Body0
end,
Primop = cerl:seq_arg(Body),
Name = cerl:primop_name(Primop),
0 = cerl:primop_arity(Primop),
nif_start = cerl:atom_val(Name),
true.
7 changes: 6 additions & 1 deletion lib/compiler/test/core_SUITE_data/nif.erl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
-module(nif).

-export([init/1, start/1]).
-export([init/1, start/1, bug0/1]).

-ifdef(WITH_ATTRIBUTE).
-nifs([start/1]).
Expand All @@ -15,3 +15,8 @@ init(_File) ->
-endif.

start(_) -> erlang:nif_error(not_loaded).

%% This used to crash the compiler in the v3_core pass as
%% insert_nif_start/1 did not support letrecs.
bug0(<<HL:32/signed-integer-big-unit:1, _:HL/binary, _/binary>>) ->
<<>>.

0 comments on commit 6a95736

Please sign in to comment.