Skip to content

Commit

Permalink
erts: Fix db_match map copy bug
Browse files Browse the repository at this point in the history
  • Loading branch information
garazdawi committed Oct 2, 2023
1 parent e7eaff0 commit d67709f
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 18 deletions.
39 changes: 21 additions & 18 deletions erts/emulator/beam/erl_db_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -3991,35 +3991,38 @@ dmc_map(DMCContext *context, DMCHeap *heap, DMC_STACK_TYPE(UWord) *text,
return ret;
}

if (constant_values) {
/* We may have to convert all values to individual matchPushC
instructions, if we do that then more stack will be needed
than estimated, so we artificially bumb the needed stack here
so that dmc_tuple thinks that dmc_array has used the needed stack. */
context->stack_used += nelems;
}

if ((ret = dmc_tuple(context, heap, text, m->keys, &constant_keys)) != retOk) {
return ret;
}

if (constant_values) {
context->stack_used -= nelems;
}

if (constant_values && constant_keys) {
*constant = 1;
return retOk;
}

/* If all values were constants, then nothing was emitted by the
first dmc_array, so we reset the pc and emit all values as
constants and then re-emit the keys. */
if (constant_values) {
DMC_STACK_NUM(*text) = textpos;
context->stack_used = stackpos;
ASSERT(!constant_keys);
for (int i = nelems; i--;) {
do_emit_constant(context, text, values[i]);
}
dmc_tuple(context, heap, text, m->keys, &constant_keys);
/* If all values were constants, then nothing was emitted by the
first dmc_array, so we insert the constants at the start of the
stack. */
dmc_rearrange_constants(context, text, textpos, values, nelems);
} else if (constant_keys) {
Eterm *p = tuple_val(m->keys);
Uint nelems = arityval(*p);
ASSERT(!constant_values);
p++;
for (int i = nelems; i--;)
do_emit_constant(context, text, p[i]);
DMC_PUSH2(*text, matchMkTuple, nelems);
context->stack_used -= nelems - 1;
/* If all keys were constant we just want to emit the key tuple.
Since do_emit_constant expects tuples to be wrapped in 1 arity
tuples we need give do_emit_constant {keys} */
Eterm wrapTuple[2] = {make_arityval(1), m->keys};
do_emit_constant(context, text, make_tuple(wrapTuple));
}

DMC_PUSH2(*text, matchMkFlatMap, nelems);
Expand Down
23 changes: 23 additions & 0 deletions lib/stdlib/test/ets_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -1914,6 +1914,29 @@ t_select_pam_stack_overflow_bug(Config) ->
ets:delete(T),
ok.

t_select_flatmap_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) ->
Expand Down

0 comments on commit d67709f

Please sign in to comment.