File 3739-sys_core_fold-Rewrite-maps-get-2-and-friends-to-guar.patch of Package erlang
From 19eaa12154ff20b531ed96d5249998c762b1a139 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?John=20H=C3=B6gberg?= <john@erlang.org>
Date: Thu, 28 Nov 2019 14:49:49 +0100
Subject: [PATCH 9/9] sys_core_fold: Rewrite maps:get/2 and friends to guard
BIFs
---
erts/emulator/test/map_SUITE.erl | 16 +++++++----
lib/compiler/src/sys_core_fold.erl | 56 ++++++++++++++++++++++++++------------
lib/stdlib/test/maps_SUITE.erl | 7 +++--
3 files changed, 54 insertions(+), 25 deletions(-)
diff --git a/erts/emulator/test/map_SUITE.erl b/erts/emulator/test/map_SUITE.erl
index 4b638b9082..dbf6fa58ed 100644
--- a/erts/emulator/test/map_SUITE.erl
+++ b/erts/emulator/test/map_SUITE.erl
@@ -1872,15 +1872,18 @@ t_bif_map_get(Config) when is_list(Config) ->
"v3" = maps:get(<<"k2">>, M1),
%% error cases
+ %%
+ %% Note that the stack trace is ignored because the compiler may have
+ %% rewritten maps:get/2 to map_get.
do_badmap(fun(T) ->
- {'EXIT',{{badmap,T},[{maps,get,_,_}|_]}} =
+ {'EXIT',{{badmap,T},_}} =
(catch maps:get(a, T))
end),
- {'EXIT',{{badkey,{1,1}},[{maps,get,_,_}|_]}} =
+ {'EXIT',{{badkey,{1,1}},_}} =
(catch maps:get({1,1}, #{{1,1.0} => "tuple"})),
- {'EXIT',{{badkey,a},[{maps,get,_,_}|_]}} = (catch maps:get(a, #{})),
- {'EXIT',{{badkey,a},[{maps,get,_,_}|_]}} =
+ {'EXIT',{{badkey,a},_}} = (catch maps:get(a, #{})),
+ {'EXIT',{{badkey,a},_}} =
(catch maps:get(a, #{b=>1, c=>2})),
ok.
@@ -1942,8 +1945,11 @@ t_bif_map_is_key(Config) when is_list(Config) ->
false = maps:is_key(1.0, maps:put(1, "number", M1)),
%% error case
+ %%
+ %% Note that the stack trace is ignored because the compiler may have
+ %% rewritten maps:is_key/2 to is_map_key.
do_badmap(fun(T) ->
- {'EXIT',{{badmap,T},[{maps,is_key,_,_}|_]}} =
+ {'EXIT',{{badmap,T},_}} =
(catch maps:is_key(a, T))
end),
ok.
diff --git a/lib/compiler/src/sys_core_fold.erl b/lib/compiler/src/sys_core_fold.erl
index a16a030f9d..93136f74cd 100644
--- a/lib/compiler/src/sys_core_fold.erl
+++ b/lib/compiler/src/sys_core_fold.erl
@@ -876,25 +876,45 @@ fold_apply(Apply, _, _) -> Apply.
%% Handling remote calls. The module/name fields have been processed.
-call(#c_call{args=As}=Call, #c_literal{val=M}=M0, #c_literal{val=N}=N0, Sub) ->
- case get(no_inline_list_funcs) of
- true ->
- call_1(Call, M0, N0, As, Sub);
- false ->
- case sys_core_fold_lists:call(Call, M, N, As) of
- none ->
- call_1(Call, M0, N0, As, Sub);
- Core ->
- expr(Core, Sub)
- end
-
- end;
-call(#c_call{args=As}=Call, M, N, Sub) ->
- call_1(Call, M, N, As, Sub).
-
-call_1(Call, M, N, As0, Sub) ->
+call(#c_call{args=As0}=Call0, #c_literal{val=M}=M0, #c_literal{val=N}=N0, Sub) ->
As1 = expr_list(As0, value, Sub),
- fold_call(Call#c_call{args=As1}, M, N, As1, Sub).
+ case simplify_call(Call0, M, N, As1) of
+ #c_literal{}=Lit ->
+ Lit;
+ #c_call{args=As}=Call ->
+ case get(no_inline_list_funcs) of
+ true ->
+ fold_call(Call, M0, N0, As, Sub);
+ false ->
+ case sys_core_fold_lists:call(Call, M, N, As) of
+ none -> fold_call(Call, M0, N0, As, Sub);
+ Core -> expr(Core, Sub)
+ end
+ end
+ end;
+call(#c_call{args=As0}=Call, M, N, Sub) ->
+ As = expr_list(As0, value, Sub),
+ fold_call(Call#c_call{args=As}, M, N, As, Sub).
+
+%% Rewrite certain known functions to BIFs, improving performance
+%% slightly at the cost of making tracing and stack traces incorrect.
+simplify_call(Call, maps, get, [Key, Map]) ->
+ rewrite_call(Call, erlang, map_get, [Key, Map]);
+simplify_call(Call, maps, is_key, [Key, Map]) ->
+ rewrite_call(Call, erlang, is_map_key, [Key, Map]);
+simplify_call(_Call, maps, new, []) ->
+ #c_literal{val=#{}};
+simplify_call(Call, maps, size, [Map]) ->
+ rewrite_call(Call, erlang, map_size, [Map]);
+simplify_call(Call, _, _, Args) ->
+ Call#c_call{args=Args}.
+
+%% rewrite_call(Call0, Mod, Func, Args, Sub) -> Call
+%% Rewrites a call to the given MFA.
+rewrite_call(Call, Mod, Func, Args) ->
+ ModLit = #c_literal{val=Mod},
+ FuncLit = #c_literal{val=Func},
+ Call#c_call{module=ModLit,name=FuncLit,args=Args}.
%% fold_call(Call, Mod, Name, Args, Sub) -> Expr.
%% Try to safely evaluate the call. Just try to evaluate arguments,
diff --git a/lib/stdlib/test/maps_SUITE.erl b/lib/stdlib/test/maps_SUITE.erl
index 9853068478..0ad6989cbb 100644
--- a/lib/stdlib/test/maps_SUITE.erl
+++ b/lib/stdlib/test/maps_SUITE.erl
@@ -237,8 +237,11 @@ t_size_1(Config) when is_list(Config) ->
600 = maps:size(maps:from_list([{{"k",I},I}||I<-lists:seq(1,600)])),
%% error case
- ?badmap(a,size,[a]) = (catch maps:size(id(a))),
- ?badmap(<<>>,size,[<<>>]) = (catch maps:size(id(<<>>))),
+ %%
+ %% Note that the stack trace is ignored because the compiler may have
+ %% rewritten maps:size/2 to map_size.
+ {'EXIT', {{badmap,a}, _}} = (catch maps:size(id(a))),
+ {'EXIT', {{badmap,<<>>}, _}} = (catch maps:size(id(<<>>))),
ok.
id(I) -> I.
--
2.16.4