summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosé Valim <jose.valim@dashbit.co>2021-03-22 17:35:46 +0100
committerSverker Eriksson <sverker@erlang.org>2021-04-09 14:17:35 +0200
commit8609f5cd9d6820f058693294e9d4433ce2922243 (patch)
treec9be93f61fe341c4c8ed7928159f503ed9c3a1e4
parent4e1660e7ff93334ef8ce3ae740e0886e4483bf30 (diff)
downloaderlang-8609f5cd9d6820f058693294e9d4433ce2922243.tar.gz
Do not allocate large map when value is the same
This is the same as 6007bf0f8 but applied to large maps.
-rw-r--r--erts/emulator/beam/erl_map.c26
-rw-r--r--erts/emulator/beam/erl_map.h2
-rw-r--r--lib/stdlib/test/maps_SUITE.erl8
3 files changed, 28 insertions, 8 deletions
diff --git a/erts/emulator/beam/erl_map.c b/erts/emulator/beam/erl_map.c
index 9b1762e299..ce17cd9163 100644
--- a/erts/emulator/beam/erl_map.c
+++ b/erts/emulator/beam/erl_map.c
@@ -2370,17 +2370,29 @@ Eterm erts_hashmap_insert(Process *p, Uint32 hx, Eterm key, Eterm value,
Uint size, upsz;
Eterm *hp, res = THE_NON_VALUE;
DECLARE_ESTACK(stack);
- if (erts_hashmap_insert_down(hx, key, map, &size, &upsz, &stack, is_update)) {
- hp = HAlloc(p, size);
- res = erts_hashmap_insert_up(hp, key, value, &upsz, &stack);
+ if (erts_hashmap_insert_down(hx, key, value, map, &size, &upsz, &stack,
+ is_update)) {
+ if (size) {
+ /* We are putting a new value (under a new or existing key) */
+ hp = HAlloc(p, size);
+ res = erts_hashmap_insert_up(hp, key, value, &upsz, &stack);
+ }
+ else {
+ /* We are putting the same key-value */
+ res = map;
+ }
+ }
+ else {
+ /* We are updating and the key does not exist */
+ ASSERT(is_update);
}
- DESTROY_ESTACK(stack);
+ DESTROY_ESTACK(stack);
return res;
}
-int erts_hashmap_insert_down(Uint32 hx, Eterm key, Eterm node, Uint *sz,
+int erts_hashmap_insert_down(Uint32 hx, Eterm key, Eterm value, Eterm node, Uint *sz,
Uint *update_size, ErtsEStack *sp, int is_update) {
Eterm *ptr;
Eterm hdr, ckey;
@@ -2398,6 +2410,10 @@ int erts_hashmap_insert_down(Uint32 hx, Eterm key, Eterm node, Uint *sz,
ptr = list_val(node);
ckey = CAR(ptr);
if (EQ(ckey, key)) {
+ if (CDR(ptr) == value) {
+ *sz = 0; /* same value, same map, no heap needed */
+ return 1;
+ }
*update_size = 0;
goto unroll;
}
diff --git a/erts/emulator/beam/erl_map.h b/erts/emulator/beam/erl_map.h
index 718d400e22..d587273ec7 100644
--- a/erts/emulator/beam/erl_map.h
+++ b/erts/emulator/beam/erl_map.h
@@ -85,7 +85,7 @@ int erts_maps_take(Process *p, Eterm key, Eterm map, Eterm *res, Eterm *value
Eterm erts_hashmap_insert(Process *p, Uint32 hx, Eterm key, Eterm value,
Eterm node, int is_update);
-int erts_hashmap_insert_down(Uint32 hx, Eterm key, Eterm node, Uint *sz,
+int erts_hashmap_insert_down(Uint32 hx, Eterm key, Eterm value, Eterm node, Uint *sz,
Uint *upsz, struct ErtsEStack_ *sp, int is_update);
Eterm erts_hashmap_insert_up(Eterm *hp, Eterm key, Eterm value,
Uint *upsz, struct ErtsEStack_ *sp);
diff --git a/lib/stdlib/test/maps_SUITE.erl b/lib/stdlib/test/maps_SUITE.erl
index 4159ea6c3b..4860e39b70 100644
--- a/lib/stdlib/test/maps_SUITE.erl
+++ b/lib/stdlib/test/maps_SUITE.erl
@@ -495,8 +495,12 @@ iter_kv(I) ->
t_put_opt(Config) when is_list(Config) ->
Value = id(#{complex => map}),
- Map = id(#{a => Value}),
- true = erts_debug:same(maps:put(a, Value, Map), Map),
+ Small = id(#{a => Value}),
+ true = erts_debug:same(maps:put(a, Value, Small), Small),
+
+ LargeBase = maps:from_list([{I,I}||I<-lists:seq(1,200)]),
+ Large = LargeBase#{a => Value},
+ true = erts_debug:same(maps:put(a, Value, Large), Large),
ok.
t_merge_opt(Config) when is_list(Config) ->