aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/beam
diff options
context:
space:
mode:
authorBjörn-Egil Dahlberg <[email protected]>2015-03-03 12:46:05 +0100
committerBjörn-Egil Dahlberg <[email protected]>2015-03-12 19:15:31 +0100
commit9794b73998690178538a1dfc193565dcd477b4fe (patch)
tree64a98ff673023c77410fd671639d2bbed7d9176c /erts/emulator/beam
parentba117527441b58886a06c0feff40677b9fa48983 (diff)
downloadotp-9794b73998690178538a1dfc193565dcd477b4fe.tar.gz
otp-9794b73998690178538a1dfc193565dcd477b4fe.tar.bz2
otp-9794b73998690178538a1dfc193565dcd477b4fe.zip
erts: Fix update_map_assoc instruction
Did not build a hashmap once the small limit was exceeded.
Diffstat (limited to 'erts/emulator/beam')
-rw-r--r--erts/emulator/beam/beam_emu.c13
-rw-r--r--erts/emulator/beam/erl_map.c31
-rw-r--r--erts/emulator/beam/erl_map.h1
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