diff options
Diffstat (limited to 'erts/emulator/test/hipe_SUITE.erl')
-rw-r--r-- | erts/emulator/test/hipe_SUITE.erl | 188 |
1 files changed, 188 insertions, 0 deletions
diff --git a/erts/emulator/test/hipe_SUITE.erl b/erts/emulator/test/hipe_SUITE.erl new file mode 100644 index 0000000000..e62d4260f6 --- /dev/null +++ b/erts/emulator/test/hipe_SUITE.erl @@ -0,0 +1,188 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2016-2017. All Rights Reserved. +%% +%% 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. +%% +%% %CopyrightEnd% +%% + +-module(hipe_SUITE). +-export([all/0 + ,t_copy_literals/1 + ,t_purge/1 + ,t_trycatch/1 + ]). + +all() -> + case erlang:system_info(hipe_architecture) of + undefined -> {skip, "HiPE is disabled"}; + _ -> [t_copy_literals + ,t_purge + ,t_trycatch + ] + end. + +t_copy_literals(doc) -> + "Check that BEAM literals referenced from HiPE stack are copied by" + " check_process_code"; +t_copy_literals(Config) when is_list(Config) -> + %% Compile the the ref_cell and literals modules. + Data = proplists:get_value(data_dir, Config), + Priv = proplists:get_value(priv_dir, Config), + RefFile = filename:join(Data, "ref_cell"), + {ok,ref_cell} = c:c(RefFile, [{outdir,Priv},native]), + true = code:is_module_native(ref_cell), + LitFile = filename:join(Data, "literals"), + {ok,literals} = c:c(LitFile, [{outdir,Priv}]), + + %% store references to literals on HiPE stacks + PA = ref_cell:start_link(), + ref_cell:call(PA, {put_res_of, fun literals:a/0}), + PB = ref_cell:start_link_deep(), + ref_cell:call(PB, {put_res_of, fun literals:b/0}), + + %% purge the literals + _ = (catch erlang:purge_module(literals)), + true = erlang:delete_module(literals), + true = erlang:purge_module(literals), + + %% Give the literal collector some time to work... + receive after 2000 -> ok end, + + %% check that the ex-literals are ok + [a,b,c] = ref_cell:call(PA, get), + {a,b,c} = ref_cell:call(PB, get), + + %% cleanup + ref_cell:call(PA, done), + ref_cell:call(PB, done), + _ = (catch erlang:purge_module(ref_cell)), + true = erlang:delete_module(ref_cell), + true = erlang:purge_module(ref_cell), + ok. + +t_purge(doc) -> "Checks that native code is properly found and purged"; +t_purge(Config) when is_list(Config) -> + Data = proplists:get_value(data_dir, Config), + Priv = proplists:get_value(priv_dir, Config), + SrcFile = filename:join(Data, "ref_cell"), + BeamFile = filename:join(Priv, "ref_cell"), + {ok,ref_cell} = c:c(SrcFile, [{outdir,Priv},native]), + true = code:is_module_native(ref_cell), + + PA = ref_cell:start_link(), + + %% Unload, PA should still be running + true = erlang:delete_module(ref_cell), + %% Can't use ref_cel:call/2, it's in old code! + call(PA, {put_res_of, fun()-> hej end}), + hej = call(PA, get), + + %% Load same module again + code:load_abs(BeamFile), + true = code:is_module_native(ref_cell), + PB = ref_cell:start_link(), + + %% Purge old code, PA should be killed, PB should survive + unlink(PA), + ARef = monitor(process, PA), + true = erlang:purge_module(ref_cell), + receive {'DOWN', ARef, process, PA, killed} -> ok + after 1 -> ct:fail("PA was not killed") + end, + + %% Unload, PB should still be running + true = erlang:delete_module(ref_cell), + call(PB, {put_res_of, fun()-> svejs end}), + svejs = call(PB, get), + + unlink(PB), + BRef = monitor(process, PB), + true = erlang:purge_module(ref_cell), + receive {'DOWN', BRef, process, PB, killed} -> ok + after 1 -> ct:fail("PB was not killed") + end, + + ok. + +call(Pid, Call) -> + Pid ! {Call, self()}, + receive {Pid, Res} -> Res end. + +t_trycatch(Config) -> + DataDir = proplists:get_value(data_dir, Config), + Files = ["trycatch_1.erl","trycatch_2.erl","trycatch_3.erl"], + Sources0 = [filename:join(DataDir, Src) || Src <- Files], + Sources = trycatch_combine(Sources0), + t_trycatch_1(Sources). + +t_trycatch_1([S|Ss]) -> + io:format("~p", [S]), + compile_and_load(S), + call_trycatch(try_catch), + call_trycatch(plain_catch), + io:nl(), + t_trycatch_1(Ss); +t_trycatch_1([]) -> + ok. + +trycatch_combine([N|Ns]) -> + Combined = trycatch_combine(Ns), + lists:append([[[{N,[]}|C],[{N,[native]},C]] || C <- Combined]); +trycatch_combine([]) -> + [[]]. + +call_trycatch(Func) -> + case do_call_trycatch(error, Func, {error,whatever}) of + {error,whatever,[{trycatch_3,three,1,_}|_]} -> + ok + end, + case do_call_trycatch(error, Func, fc) of + {error,function_clause,[{trycatch_3,three,[fc],_}|_]} -> + ok; + {error,function_clause,[{trycatch_3,three,1,_}|_]} -> + ok + end, + case do_call_trycatch(throw, Func, {throw,{a,b}}) of + {throw,{a,b},[{trycatch_3,three,1,_}|_]} -> + ok + end, + case do_call_trycatch(exit, Func, {exit,{a,b,c}}) of + {exit,{a,b,c},[{trycatch_3,three,1,_}|_]} -> + ok + end, + ok. + +do_call_trycatch(_Class, try_catch, Argument) -> + trycatch_1:one_try_catch(Argument); +do_call_trycatch(error, plain_catch, Argument) -> + {{'EXIT',{Reason,Stk}},Stk} = trycatch_1:one_plain_catch(Argument), + {error,Reason,Stk}; +do_call_trycatch(throw, plain_catch, Argument) -> + {Reason,Stk} = trycatch_1:one_plain_catch(Argument), + {throw,Reason,Stk}; +do_call_trycatch(exit, plain_catch, Argument) -> + {{'EXIT',Reason},Stk} = trycatch_1:one_plain_catch(Argument), + {exit,Reason,Stk}. + +compile_and_load(Sources) -> + _ = [begin + {ok,Mod,Bin} = compile:file(Src, [binary,report|Opts]), + code:purge(Mod), + code:delete(Mod), + code:purge(Mod), + {module,Mod} = code:load_binary(Mod, atom_to_list(Mod), Bin) + end || {Src,Opts} <- Sources], + ok. |