Skip to content

Commit

Permalink
erlang_service_ct: inrepret module instead of compiling
Browse files Browse the repository at this point in the history
Summary: This changes the `erlang_service_ct` to interpret modules in a very similar way to what `escript` does in `interpreted` mode, instead of compiling the modules just to call a single function. This should likely speed things up - interpreting those small `all()` and `groups()` functions should be significantly faster than compiling the whole module.

Reviewed By: robertoaloi

Differential Revision: D69254637

fbshipit-source-id: a5f9a9765179d08bf5ded5ccb6b37451fc7e6116
  • Loading branch information
michalmuskala authored and facebook-github-bot committed Feb 11, 2025
1 parent 66d166a commit cf8accc
Showing 1 changed file with 39 additions and 20 deletions.
59 changes: 39 additions & 20 deletions erlang_service/src/erlang_service_ct.erl
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,44 @@

-export([run/2]).

run(_Id, [Module, Filename, CompileOptions, ShouldRequestGroups, AstBinary]) ->
run(_Id, [Module, _Filename, _CompileOptions, ShouldRequestGroups, AstBinary]) ->
{ok, Forms0, _} = binary_to_term(AstBinary),
Forms1 = elp_parse:map_anno(fun(_) -> 0 end, Forms0),
{ok, Module, Binary}
= case compile:noenv_forms(Forms1, CompileOptions) of
{ok, M, B, _} -> {ok, M, B};
{ok, M, B} -> {ok, M, B}
end,
code:load_binary(Module, Filename, Binary),
{All, Groups} =
try
case ShouldRequestGroups of
true ->
{Module:all(), Module:groups()};
false ->
{Module:all(), []}
end
after
code:purge(Module),
code:delete(Module)
end,
Anno0 = erl_anno:new(0),
Forms1 = elp_parse:map_anno(fun(_) -> Anno0 end, Forms0),
{All, Groups} = interpret(Forms1, Module, ShouldRequestGroups, Anno0),
{ok, [{<<"ALL">>, term_to_binary(All)}, {<<"GRP">>, term_to_binary(Groups)}]}.

interpret(Forms, Mod, ShouldRequestGroups, Anno) ->
Dict = parse_to_map(Forms),
All = {call, Anno, {atom, Anno, all}, []},
Value =
case ShouldRequestGroups of
true -> {tuple, Anno, [All, {call, Anno, {atom, Anno, groups}, []}]};
false -> {tuple, Anno, [All, {nil, Anno}]}
end,
Handler = {value, fun(Name, Args) -> code_handler(Name, Args, Dict, Mod) end},
{value, Result, _} = erl_eval:expr(Value, erl_eval:new_bindings(), Handler),
Result.

parse_to_map(Forms) ->
Local = #{{local, Name, Arity} => Clauses || {function, _, Name, Arity, Clauses} <- Forms},
Remote = #{{remote, NA} => Mod || {attribute, _, import, {Mod, NAs}} <- Forms, NA <- NAs},
maps:merge(Local, Remote).

code_handler(Name, Args, Dict, Mod) ->
Arity = length(Args),
case Dict of
#{{local, Name, Arity} := Clauses} ->
Handler = {value, fun(N, As) -> code_handler(N, As, Dict, Mod) end},
case erl_eval:match_clause(Clauses, Args, erl_eval:new_bindings(), Handler) of
{Body, Bindings} ->
{value, Val, _} = erl_eval:exprs(Body, Bindings, Handler),
Val;
nomatch ->
erlang:error({function_clause, [{Mod,Name,Args}]})
end;
#{{remote, {Name, Arity}} := Mod} ->
apply(Mod, Name, Args);
_ ->
erlang:error({undef, {Name, Arity}})
end.

0 comments on commit cf8accc

Please sign in to comment.