Skip to content

Commit

Permalink
erts: Fix db_match hashmap copy bug
Browse files Browse the repository at this point in the history
  • Loading branch information
garazdawi committed Oct 2, 2023
1 parent d67709f commit 5fccca1
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 11 deletions.
69 changes: 58 additions & 11 deletions erts/emulator/beam/erl_db_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -4031,10 +4031,12 @@ dmc_map(DMCContext *context, DMCHeap *heap, DMC_STACK_TYPE(UWord) *text,
return retOk;
} else {
DECLARE_WSTACK(wstack);
DMC_STACK_TYPE(UWord) instr_save;
Eterm *kv;
int c;
int textpos = DMC_STACK_NUM(*text);
int stackpos = context->stack_used;
int preventive_bumps = 0;

ASSERT(is_hashmap(t));

Expand All @@ -4048,52 +4050,97 @@ dmc_map(DMCContext *context, DMCHeap *heap, DMC_STACK_TYPE(UWord) *text,
DESTROY_WSTACK(wstack);
return ret;
}
if (!c)

if (!c) {
constant_values = 0;
break;
}

++context->stack_used;
++preventive_bumps;

if ((ret = dmc_expr(context, heap, text, CDR(kv), &c)) != retOk) {
DESTROY_WSTACK(wstack);
return ret;
}
if (!c)

if (!c) {
constant_values = 0;
break;
}

++context->stack_used;
++preventive_bumps;

}

context->stack_used -= preventive_bumps;

if (constant_values) {
ASSERT(DMC_STACK_NUM(*text) == textpos);
*constant = 1;
DESTROY_WSTACK(wstack);
return retOk;
}

/* reset the program to the original position and re-emit everything */
DMC_STACK_NUM(*text) = textpos;
context->stack_used = stackpos;

*constant = 0;
DMC_INIT_STACK(instr_save);
while (DMC_STACK_NUM(*text) > textpos) {
DMC_PUSH(instr_save, DMC_POP(*text));
}

hashmap_iterator_init(&wstack, t, 1);

while ((kv=hashmap_iterator_prev(&wstack)) != NULL) {
do_emit_constant(context, text, CAR(kv));
if (--preventive_bumps == 0) {
while(!DMC_EMPTY(instr_save)) {
DMC_PUSH(*text, DMC_POP(instr_save));
}
break;
}
do_emit_constant(context, text, CDR(kv));
if (--preventive_bumps == 0) {
while(!DMC_EMPTY(instr_save)) {
DMC_PUSH(*text, DMC_POP(instr_save));
}
kv=hashmap_iterator_prev(&wstack);
if ((ret = dmc_expr(context, heap, text, CDR(kv), &c)) != retOk) {
DESTROY_WSTACK(wstack);
return ret;
}
if (c) {
do_emit_constant(context, text, CDR(kv));
}
break;
}
}

while ((kv=hashmap_iterator_prev(&wstack)) != NULL) {

/* push key */
if ((ret = dmc_expr(context, heap, text, CAR(kv), &c)) != retOk) {
DESTROY_WSTACK(wstack);
return ret;
}
DESTROY_WSTACK(wstack);
return ret;
}

if (c) {
do_emit_constant(context, text, CAR(kv));
}

/* push value */
if ((ret = dmc_expr(context, heap, text, CDR(kv), &c)) != retOk) {
DESTROY_WSTACK(wstack);
return ret;
}

if (c) {
do_emit_constant(context, text, CDR(kv));
}
}
ASSERT(preventive_bumps <= 0);
DMC_PUSH2(*text, matchMkHashMap, nelems);
context->stack_used -= 2*nelems - 1; /* n keys & values => 1 map */
DMC_FREE(instr_save);
DESTROY_WSTACK(wstack);
return retOk;
}
Expand Down
25 changes: 25 additions & 0 deletions lib/stdlib/test/ets_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -1938,6 +1938,31 @@ t_select_flatmap_term_copy_bug(_Config) ->
ets:delete(T),
ok.

t_select_hashmap_term_copy_bug(_Config) ->

T = ets:new(a,[]),
ets:insert(T, {list_to_binary(lists:duplicate(36,$a)),
list_to_binary(lists:duplicate(36,$b)),
list_to_binary(lists:duplicate(36,$c))}),
V1 = ets:select(T, [{{'$1','$2','$3'},[],[#{ '$1' => a }]}]),
erlang:garbage_collect(),
V1 = ets:select(T, [{{'$1','$2','$3'},[],[#{ '$1' => a }]}]),
erlang:garbage_collect(),
V2 = ets:select(T, [{{'$1','$2','$3'},[],[#{ a => '$1' }]}]),
erlang:garbage_collect(),
V2 = ets:select(T, [{{'$1','$2','$3'},[],[#{ a => '$1' }]}]),
erlang:garbage_collect(),
V3 = ets:select(T, [{{'$1','$2','$3'},[],[#{ '$1' => '$1' }]}]),
erlang:garbage_collect(),
V3 = ets:select(T, [{{'$1','$2','$3'},[],[#{ '$1' => '$1' }]}]),
erlang:garbage_collect(),
V3 = ets:select(T, [{{'$1','$2','$3'},[],[#{ a => a }]}]),
erlang:garbage_collect(),
V3 = ets:select(T, [{{'$1','$2','$3'},[],[#{ a => a }]}]),
erlang:garbage_collect(),
ets:delete(T),
ok.

%% Test that partly bound keys gives faster matches.
partly_bound(Config) when is_list(Config) ->
case os:type() of
Expand Down

0 comments on commit 5fccca1

Please sign in to comment.