aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjörn-Egil Dahlberg <[email protected]>2014-03-06 18:00:52 +0100
committerBjörn-Egil Dahlberg <[email protected]>2014-03-17 17:47:35 +0100
commit5d75a3b453b64ae1b10c8980ec5c146d7b2d5d1a (patch)
tree0a5601a0b059d1cb9f289f31169c77c574feddd9
parent90a948d7cf7f188b5461c2a7bb25a656ec681966 (diff)
downloadotp-5d75a3b453b64ae1b10c8980ec5c146d7b2d5d1a.tar.gz
otp-5d75a3b453b64ae1b10c8980ec5c146d7b2d5d1a.tar.bz2
otp-5d75a3b453b64ae1b10c8980ec5c146d7b2d5d1a.zip
compiler: Constant fold Maps that are safe
For updates of Map literals which may cause an error will be determined in runtime, i.e. instructions are emitted for those updates. The changes in cerl now requires compiler-5.0 to compile because of is_map/1 guard.
-rw-r--r--lib/compiler/src/cerl.erl32
-rw-r--r--lib/compiler/src/sys_core_fold.erl4
2 files changed, 33 insertions, 3 deletions
diff --git a/lib/compiler/src/cerl.erl b/lib/compiler/src/cerl.erl
index 9024999d7f..61b47ed468 100644
--- a/lib/compiler/src/cerl.erl
+++ b/lib/compiler/src/cerl.erl
@@ -1588,7 +1588,7 @@ ann_c_map(As,Es) ->
ann_c_map(As, #c_literal{val=#{}}, Es).
ann_c_map(As,#c_literal{val=Mval}=M,Es) when is_map(Mval), map_size(Mval) =:= 0 ->
- Pairs = [[K,V]||#c_map_pair{key=K,val=V}<-Es],
+ Pairs = [[Ck,Cv]||#c_map_pair{key=Ck,val=Cv}<-Es],
IsLit = lists:foldl(fun(Pair,Res) ->
Res andalso is_lit_list(Pair)
end, true, Pairs),
@@ -1599,8 +1599,36 @@ ann_c_map(As,#c_literal{val=Mval}=M,Es) when is_map(Mval), map_size(Mval) =:= 0
true ->
#c_literal{anno=As, val=maps:from_list(lists:map(Fun, Pairs))}
end;
+ann_c_map(As,#c_literal{val=M},Es) when is_map(M) ->
+ fold_map_pairs(As,Es,M);
ann_c_map(As,M,Es) ->
- #c_map{var=M, es = Es, anno = As }.
+ #c_map{var=M, es=Es, anno=As }.
+
+fold_map_pairs(As,[],M) -> #c_literal{anno=As,val=M};
+%% M#{ K => V}
+fold_map_pairs(As,[#c_map_pair{op=#c_literal{val=assoc},key=Ck,val=Cv}=E|Es],M) ->
+ case is_lit_list([Ck,Cv]) of
+ true ->
+ [K,V] = lit_list_vals([Ck,Cv]),
+ fold_map_pairs(As,Es,maps:put(K,V,M));
+ false ->
+ #c_map{var=#c_literal{val=M,anno=As}, es=[E|Es], anno=As }
+ end;
+%% M#{ K := V}
+fold_map_pairs(As,[#c_map_pair{op=#c_literal{val=exact},key=Ck,val=Cv}=E|Es],M) ->
+ case is_lit_list([Ck,Cv]) of
+ true ->
+ [K,V] = lit_list_vals([Ck,Cv]),
+ case maps:is_key(K,M) of
+ true -> fold_map_pairs(As,Es,maps:put(K,V,M));
+ false ->
+ #c_map{var=#c_literal{val=M,anno=As}, es=[E|Es], anno=As }
+ end;
+ false ->
+ #c_map{var=#c_literal{val=M,anno=As}, es=[E|Es], anno=As }
+ end;
+fold_map_pairs(As,Es,M) ->
+ #c_map{var=#c_literal{val=M,anno=As}, es=Es, anno=As }.
update_c_map(Old,M,Es) ->
diff --git a/lib/compiler/src/sys_core_fold.erl b/lib/compiler/src/sys_core_fold.erl
index 90cc3b9051..bf1be6d773 100644
--- a/lib/compiler/src/sys_core_fold.erl
+++ b/lib/compiler/src/sys_core_fold.erl
@@ -72,7 +72,7 @@
-import(lists, [map/2,foldl/3,foldr/3,mapfoldl/3,all/2,any/2,
reverse/1,reverse/2,member/2,nth/2,flatten/1,unzip/1]).
--import(cerl, [ann_c_cons/3,ann_c_tuple/2,ann_c_map/3]).
+-import(cerl, [ann_c_cons/3,ann_c_map/3,ann_c_tuple/2]).
-include("core_parse.hrl").
@@ -1378,6 +1378,7 @@ eval_is_record(Call, _, _, _, _) -> Call.
is_not_integer(#c_literal{val=Val}) when not is_integer(Val) -> true;
is_not_integer(#c_tuple{}) -> true;
is_not_integer(#c_cons{}) -> true;
+is_not_integer(#c_map{}) -> true;
is_not_integer(_) -> false.
%% is_not_tuple(Core) -> true | false.
@@ -1385,6 +1386,7 @@ is_not_integer(_) -> false.
is_not_tuple(#c_literal{val=Val}) when not is_tuple(Val) -> true;
is_not_tuple(#c_cons{}) -> true;
+is_not_tuple(#c_map{}) -> true;
is_not_tuple(_) -> false.
%% eval_setelement(Call, Pos, Tuple, NewVal) -> Core.