diff options
Diffstat (limited to 'erts/emulator')
-rw-r--r-- | erts/emulator/beam/beam_emu.c | 13 | ||||
-rw-r--r-- | erts/emulator/beam/erl_map.c | 31 | ||||
-rw-r--r-- | erts/emulator/beam/erl_map.h | 1 |
3 files changed, 44 insertions, 1 deletions
diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c index 1166b32a3b..c753e57ddc 100644 --- a/erts/emulator/beam/beam_emu.c +++ b/erts/emulator/beam/beam_emu.c @@ -6781,8 +6781,19 @@ update_map_assoc(Process* p, Eterm* reg, Eterm map, BeamInstr* I) n = kp - p->htop - 1; /* Actual number of keys/values */ *p->htop = make_arityval(n); + p->htop = hp; mp->size = n; - p->htop = hp; + + /* The expensive case, need to build a hashmap */ + if (n > MAP_SMALL_MAP_LIMIT) { + res = erts_hashmap_from_ks_and_vs(p,map_get_keys(mp),map_get_values(mp),n); + if (p->mbuf) { + Uint live = Arg(3); + reg[live] = res; + erts_garbage_collect(p, 0, reg, live+1); + res = reg[live]; + } + } return res; } diff --git a/erts/emulator/beam/erl_map.c b/erts/emulator/beam/erl_map.c index 1703f86b0e..e26b97d75c 100644 --- a/erts/emulator/beam/erl_map.c +++ b/erts/emulator/beam/erl_map.c @@ -452,6 +452,37 @@ Eterm erts_hashmap_from_array(Process *p, Eterm *leafs, Uint n) { return res; } + +Eterm erts_hashmap_from_ks_and_vs(Process *p, Eterm *ks, Eterm *vs, Uint n) { + Uint32 sw, hx; + Uint i; + hxnode_t *hxns; + Eterm *hp, res; + + ASSERT(n > 0); + + hp = HAlloc(p, (2 * n)); + + /* create tmp hx values and leaf ptrs */ + hxns = (hxnode_t *)erts_alloc(ERTS_ALC_T_TMP, n * sizeof(hxnode_t)); + + for(i = 0; i < n; i++) { + hx = hashmap_make_hash(ks[i]); + swizzle32(sw,hx); + hxns[i].hx = sw; + hxns[i].val = CONS(hp, ks[i], vs[i]); hp += 2; + hxns[i].skip = 1; /* will be reassigned in from_array */ + hxns[i].i = i; + } + + res = hashmap_from_unsorted_array(p, hxns, n); + + erts_free(ERTS_ALC_T_TMP, (void *) hxns); + ERTS_VERIFY_UNUSED_TEMP_ALLOC(p); + + return res; +} + static Eterm hashmap_from_unsorted_array(Process *p, hxnode_t *hxns, Uint n) { Uint jx = 0, ix = 0, lx, cx; Eterm res; diff --git a/erts/emulator/beam/erl_map.h b/erts/emulator/beam/erl_map.h index 3544189936..6a7b29fe86 100644 --- a/erts/emulator/beam/erl_map.h +++ b/erts/emulator/beam/erl_map.h @@ -103,6 +103,7 @@ void hashmap_iterator_init(struct ErtsWStack_* s, Eterm node); Eterm* hashmap_iterator_next(struct ErtsWStack_* s); int hashmap_key_hash_cmp(Eterm* ap, Eterm* bp); Eterm erts_hashmap_from_array(Process *p, Eterm *leafs, Uint n); +Eterm erts_hashmap_from_ks_and_vs(Process *p, Eterm *ks, Eterm *vs, Uint n); const Eterm *erts_hashmap_get(Uint32 hx, Eterm key, Eterm map); #if HALFWORD_HEAP |