Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:Ledest:erlang:23
erlang
6931-sys_core_fold-Inline-maps-get-3.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File 6931-sys_core_fold-Inline-maps-get-3.patch of Package erlang
From 9dc9a47dfe14c103be2aefa760f068eb58733069 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20H=C3=B6gberg?= <john@erlang.org> Date: Thu, 9 Mar 2023 16:26:49 +0100 Subject: [PATCH] sys_core_fold: Inline maps:get/3 --- lib/compiler/src/sys_core_fold.erl | 33 +++++++++++++++++-- lib/stdlib/test/maps_SUITE.erl | 3 +- system/doc/efficiency_guide/maps.xml | 49 ++++++++++++++++------------ 3 files changed, 61 insertions(+), 24 deletions(-) diff --git a/lib/compiler/src/sys_core_fold.erl b/lib/compiler/src/sys_core_fold.erl index d97954572b..99867a508b 100644 --- a/lib/compiler/src/sys_core_fold.erl +++ b/lib/compiler/src/sys_core_fold.erl @@ -800,8 +800,6 @@ fold_apply(Apply, _, _) -> Apply. call(#c_call{args=As0}=Call0, #c_literal{val=M}=M0, #c_literal{val=N}=N0, Sub) -> As1 = expr_list(As0, value, 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 -> @@ -811,7 +809,11 @@ call(#c_call{args=As0}=Call0, #c_literal{val=M}=M0, #c_literal{val=N}=N0, Sub) - none -> fold_call(Call, M0, N0, As, Sub); Core -> expr(Core, Sub) end - end + end; + #c_case{}=Case -> + Case; + #c_literal{}=Lit -> + Lit end; call(#c_call{args=As0}=Call, M, N, Sub) -> As = expr_list(As0, value, Sub), @@ -821,6 +823,31 @@ call(#c_call{args=As0}=Call, M, N, Sub) -> %% 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(#c_call{anno=Anno0}, maps, get, [Key, Map, Default]) -> + Anno = [compiler_generated | Anno0], + + Value = make_var(Anno), + Fail = make_var(Anno), + Raise = #c_primop{name=#c_literal{val=match_fail}, + args=[#c_tuple{es=[#c_literal{val=badmap}, + Fail]}]}, + + Cs = [#c_clause{anno=Anno, + pats=[#c_map{es=[#c_map_pair{op=#c_literal{val=exact}, + key=Key, + val=Value}], + is_pat=true}], + guard=#c_literal{val=true}, + body=Value}, + #c_clause{anno=Anno, + pats=[#c_map{es=[],is_pat=true}], + guard=#c_literal{val=true}, + body=Default}, + #c_clause{anno=Anno, + pats=[Fail], + guard=#c_literal{val=true}, + body=Raise}], + #c_case{anno=Anno,arg=Map,clauses=Cs}; simplify_call(Call, maps, is_key, [Key, Map]) -> rewrite_call(Call, erlang, is_map_key, [Key, Map]); simplify_call(_Call, maps, new, []) -> diff --git a/lib/stdlib/test/maps_SUITE.erl b/lib/stdlib/test/maps_SUITE.erl index 937315e242..0f20398803 100644 --- a/lib/stdlib/test/maps_SUITE.erl +++ b/lib/stdlib/test/maps_SUITE.erl @@ -358,7 +358,8 @@ t_get_3(Config) when is_list(Config) -> DefaultValue = maps:get(key3, Map, DefaultValue), %% error case - ?badmap(a,get,[[a,b],a,def]) = (catch maps:get([a,b],id(a),def)), + {'EXIT', {{badmap,a}, _}} = (catch maps:get([a,b],id(a),def)), + ok. t_without_2(_Config) -> diff --git a/system/doc/efficiency_guide/maps.xml b/system/doc/efficiency_guide/maps.xml index 140bdd549a..1cbfa6786d 100644 --- a/system/doc/efficiency_guide/maps.xml +++ b/system/doc/efficiency_guide/maps.xml @@ -107,10 +107,7 @@ there are default values, sharing of keys between different instances of the map will be less effective, and it is not possible to match multiple elements having default values in one - go. The <c>maps:get/3</c> function is <seeguide - marker="#maps_get_3">implemented in Erlang</seeguide>, making it - less efficient than <c>maps:get/2</c> or the map matching - syntax.</p></item> + go.</p></item> <item><p>To avoid having to deal with a map that may lack some keys, <seemfa marker="stdlib:maps#merge/2">maps:merge/2</seemfa> @@ -487,32 +484,43 @@ new() -> <section> <marker id="maps_get_3"/> <title>maps:get/3</title> - <p><seemfa marker="stdlib:maps#get/3">maps:get/3</seemfa> - is implemented in Erlang essentially like this:</p> + <p>As an optimization, the compiler will rewrite a call to <seemfa + marker="stdlib:maps#get/3">maps:get/3</seemfa> to Erlang code similar to + the following:</p> <code type="erl"><![CDATA[ -get(Key, Map, Default) -> - case Map of - #{Key := Value} -> Value; - #{} -> Default - end.]]></code> + Result = case Map of + #{Key := Value} -> Value; + #{} -> Default + end]]></code> - <p>Therefore, a call <c>maps:get/3</c> is more expensive than a - call to <c>maps:get/2</c>.</p> + <p>This is reasonably efficient, but if a small map is used as an + alternative to using a record it is often better not to rely on default + values as it prevents sharing of keys, which may in the end use more + memory than what you save from not storing default values in the + map.</p> - <p>If a <seeguide marker="#terminology">small map</seeguide> - is used as alternative to using a record, - instead of calling <c>maps:get/3</c> multiple times to handle - default values, consider putting the default values in a map and - merging that map with the other map:</p> + <p>If default values are nevertheless required, instead of calling + <c>maps:get/3</c> multiple times, consider putting the default values + in a map and merging that map with the other map:</p> <code type="erl"><![CDATA[ DefaultMap = #{Key1 => Value2, Key2 => Value2, ..., KeyN => ValueN}, MapWithDefaultsApplied = maps:merge(DefaultMap, OtherMap)]]></code> - <p>Whether that is faster than calling <c>maps:get/3</c> - multiple times depends on the size of the map and the number of - default values.</p> + <p>This helps share keys between the default map and the one you applied + defaults to, as long as the default map contains <em>all</em> the keys + that will ever be used and not just the ones with default values. + Whether this is faster than calling <c>maps:get/3</c> multiple times + depends on the size of the map and the number of default values.</p> + + <change> + <p> + Before OTP 26.0 <c>maps:get/3</c> was implemented by calling + the function instead of rewriting it as an Erlang expression. It is + now slightly faster but can no longer be traced. + </p> + </change> </section> <section> -- 2.35.3
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor