From 05169ff8fa0713f3ea969bc27b9d8f58b439863c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Tue, 10 Mar 2015 12:57:59 +0100 Subject: erts: Teach hashmaps to match spec compiler --- erts/emulator/beam/erl_db_util.c | 222 +++++++++++++++++++++++++++++++++------ 1 file changed, 189 insertions(+), 33 deletions(-) (limited to 'erts/emulator/beam/erl_db_util.c') diff --git a/erts/emulator/beam/erl_db_util.c b/erts/emulator/beam/erl_db_util.c index 748be93fe3..8b5ab16642 100644 --- a/erts/emulator/beam/erl_db_util.c +++ b/erts/emulator/beam/erl_db_util.c @@ -231,7 +231,8 @@ typedef enum { matchConsA, /* Car is below Cdr */ matchConsB, /* Cdr is below Car (unusual) */ matchMkTuple, - matchMkMap, + matchMkFlatMap, + matchMkHashMap, matchCall0, matchCall1, matchCall2, @@ -1424,6 +1425,63 @@ restart: } break; } + if (is_hashmap(t)) { + DECLARE_WSTACK(wstack); + Eterm *kv; + num_iters = hashmap_size(t); + if (!structure_checked) { + DMC_PUSH(text, matchMap); + DMC_PUSH(text, num_iters); + } + structure_checked = 0; + + hashmap_iterator_init(&wstack, t); + + while ((kv=hashmap_iterator_next(&wstack)) != NULL) { + Eterm key = CAR(kv); + Eterm value = CDR(kv); + if (db_is_variable(key) >= 0) { + if (context.err_info) { + add_dmc_err(context.err_info, + "Variable found in map key.", + -1, 0UL, dmcError); + } + DESTROY_WSTACK(wstack); + goto error; + } else if (key == am_Underscore) { + if (context.err_info) { + add_dmc_err(context.err_info, + "Underscore found in map key.", + -1, 0UL, dmcError); + } + DESTROY_WSTACK(wstack); + goto error; + } + DMC_PUSH(text, matchKey); + DMC_PUSH(text, dmc_private_copy(&context, key)); + { + int old_stack = ++(context.stack_used); + res = dmc_one_term(&context, &heap, &stack, &text, + value); + ASSERT(res != retFail); + if (res == retRestart) { + DESTROY_WSTACK(wstack); + goto restart; + } + if (old_stack != context.stack_used) { + ASSERT(old_stack + 1 == context.stack_used); + DMC_PUSH(text, matchSwap); + } + if (context.stack_used > context.stack_need) { + context.stack_need = context.stack_used; + } + DMC_PUSH(text, matchPop); + --(context.stack_used); + } + } + DESTROY_WSTACK(wstack); + break; + } if (!is_tuple(t)) { goto simple_term; } @@ -1946,23 +2004,37 @@ restart: ++ep; break; case matchMap: - if (!is_map_rel(*ep, base)) { + if (!is_map_rel(*ep, base) && !is_hashmap_rel(*ep,base)) { FAIL(); } n = *pc++; - if (map_get_size(map_val_rel(*ep, base)) < n) { - FAIL(); - } + if (is_map_rel(*ep,base)) { + if (map_get_size(map_val_rel(*ep, base)) < n) { + FAIL(); + } + } else { + ASSERT(is_hashmap_rel(*ep,base)); + if (hashmap_size_rel(*ep, base) < n) { + FAIL(); + } + } ep = map_val_rel(*ep, base); break; case matchPushM: - if (!is_map_rel(*ep, base)) { + if (!is_map_rel(*ep, base) && !is_hashmap_rel(*ep, base)) { FAIL(); } n = *pc++; - if (map_get_size(map_val_rel(*ep, base)) < n) { - FAIL(); - } + if (is_map_rel(*ep,base)) { + if (map_get_size(map_val_rel(*ep, base)) < n) { + FAIL(); + } + } else { + ASSERT(is_hashmap_rel(*ep,base)); + if (hashmap_size_rel(*ep, base) < n) { + FAIL(); + } + } *sp++ = map_val_rel(*ep++, base); break; case matchKey: @@ -2079,7 +2151,7 @@ restart: } *esp++ = t; break; - case matchMkMap: + case matchMkFlatMap: n = *pc++; ehp = HAllocX(build_proc, 1 + MAP_HEADER_SIZE + n, HEAP_XTRA); t = *ehp++ = *--esp; @@ -2096,6 +2168,21 @@ restart: } *esp++ = t; break; + case matchMkHashMap: + n = *pc++; + esp -= 2*n; + ehp = HAllocX(build_proc, 2*n, HEAP_XTRA); + { + ErtsHeapFactory factory; + Uint ix; + factory.p = build_proc; + for (ix = 0; ix < 2*n; ix++){ + ehp[ix] = esp[ix]; + } + t = erts_hashmap_from_array(&factory, ehp, n, 0); + } + *esp++ = t; + break; case matchCall0: bif = (Eterm (*)(Process*, ...)) *pc++; t = (*bif)(build_proc, bif_args); @@ -3366,7 +3453,6 @@ static DMCRet dmc_one_term(DMCContext *context, Uint sz, sz2, sz3; Uint i, j; - switch (c & _TAG_PRIMARY_MASK) { case TAG_PRIMARY_IMMED1: if ((n = db_is_variable(c)) >= 0) { /* variable */ @@ -3460,6 +3546,13 @@ static DMCRet dmc_one_term(DMCContext *context, DMC_PUSH(*text, n); DMC_PUSH(*stack, c); break; + case (_TAG_HEADER_HASHMAP >> _TAG_PRIMARY_SIZE): + n = hashmap_size(c); + DMC_PUSH(*text, matchPushM); + ++(context->stack_used); + DMC_PUSH(*text, n); + DMC_PUSH(*stack, c); + break; case (_TAG_HEADER_REF >> _TAG_PRIMARY_SIZE): { Eterm* ref_val = internal_ref_val(c); @@ -3745,30 +3838,87 @@ static DMCRet dmc_map(DMCContext *context, DMCHeap *heap, DMC_STACK_TYPE(UWord) *text, Eterm t, int *constant) { - map_t *m = (map_t *)map_val(t); - Eterm *values = map_get_values(m); - int nelems = map_get_size(m); + int nelems; int constant_values; DMCRet ret; + if (is_map(t)) { + map_t *m = (map_t *)map_val(t); + Eterm *values = map_get_values(m); - ret = dmc_array(context, heap, text, values, nelems, &constant_values); - if (ret != retOk) { - return ret; - } - if (constant_values) { - *constant = 1; + nelems = map_get_size(m); + ret = dmc_array(context, heap, text, values, nelems, &constant_values); + + if (ret != retOk) { + return ret; + } + if (constant_values) { + *constant = 1; + return retOk; + } + DMC_PUSH(*text, matchPushC); + DMC_PUSH(*text, dmc_private_copy(context, m->keys)); + if (++context->stack_used > context->stack_need) { + context->stack_need = context->stack_used; + } + DMC_PUSH(*text, matchMkFlatMap); + DMC_PUSH(*text, nelems); + context->stack_used -= nelems; + *constant = 0; + return retOk; + } else { + DECLARE_WSTACK(wstack); + Eterm *kv; + int c; + + ASSERT(is_hashmap(t)); + + hashmap_iterator_init(&wstack, t); + constant_values = 1; + nelems = hashmap_size(t); + + while ((kv=hashmap_iterator_prev(&wstack)) != NULL) { + if ((ret = dmc_expr(context, heap, text, CDR(kv), &c)) != retOk) { + DESTROY_WSTACK(wstack); + return ret; + } + if (!c) + constant_values = 0; + } + + if (constant_values) { + *constant = 1; + DESTROY_WSTACK(wstack); + return retOk; + } + + *constant = 0; + + hashmap_iterator_init(&wstack, t); + + 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; + } + 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)); + } + } + DMC_PUSH(*text, matchMkHashMap); + DMC_PUSH(*text, nelems); + context->stack_used -= nelems; + DESTROY_WSTACK(wstack); return retOk; } - DMC_PUSH(*text, matchPushC); - DMC_PUSH(*text, dmc_private_copy(context, m->keys)); - if (++context->stack_used > context->stack_need) { - context->stack_need = context->stack_used; - } - DMC_PUSH(*text, matchMkMap); - DMC_PUSH(*text, nelems); - context->stack_used -= nelems; - *constant = 0; - return retOk; } static DMCRet dmc_whole_expression(DMCContext *context, @@ -4765,7 +4915,7 @@ static DMCRet dmc_expr(DMCContext *context, return ret; break; case TAG_PRIMARY_BOXED: - if (is_map(t)) { + if (is_map(t) || is_hashmap(t)) { return dmc_map(context, heap, text, t, constant); } if (!is_tuple(t)) { @@ -5462,11 +5612,17 @@ void db_match_dis(Binary *bp) ++t; erts_printf("MkTuple\t%beu\n", n); break; - case matchMkMap: + case matchMkFlatMap: + ++t; + n = *t; + ++t; + erts_printf("MkFlatMap\t%beu\n", n); + break; + case matchMkHashMap: ++t; n = *t; ++t; - erts_printf("MkMapA\t%beu\n", n); + erts_printf("MkHashMap\t%beu\n", n); break; case matchOr: ++t; -- cgit v1.2.3 From 27e57aa05354b743b735a41716c0e3af18f2843e Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Tue, 10 Mar 2015 19:03:19 +0100 Subject: erts: Refactor maps naming convention flatmap: Small map hashmap: Large map map: flatmap or hashmap --- erts/emulator/beam/erl_db_util.c | 50 ++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 25 deletions(-) (limited to 'erts/emulator/beam/erl_db_util.c') diff --git a/erts/emulator/beam/erl_db_util.c b/erts/emulator/beam/erl_db_util.c index 8b5ab16642..cca3f381a1 100644 --- a/erts/emulator/beam/erl_db_util.c +++ b/erts/emulator/beam/erl_db_util.c @@ -1377,15 +1377,15 @@ restart: for (;;) { switch (t & _TAG_PRIMARY_MASK) { case TAG_PRIMARY_BOXED: - if (is_map(t)) { - num_iters = map_get_size(map_val(t)); + if (is_flatmap(t)) { + num_iters = flatmap_get_size(flatmap_val(t)); if (!structure_checked) { DMC_PUSH(text, matchMap); DMC_PUSH(text, num_iters); } structure_checked = 0; for (i = 0; i < num_iters; ++i) { - Eterm key = map_get_keys(map_val(t))[i]; + Eterm key = flatmap_get_keys(flatmap_val(t))[i]; if (db_is_variable(key) >= 0) { if (context.err_info) { add_dmc_err(context.err_info, @@ -1405,7 +1405,7 @@ restart: DMC_PUSH(text, dmc_private_copy(&context, key)); { int old_stack = ++(context.stack_used); - Eterm value = map_get_values(map_val(t))[i]; + Eterm value = flatmap_get_values(flatmap_val(t))[i]; res = dmc_one_term(&context, &heap, &stack, &text, value); ASSERT(res != retFail); @@ -2004,12 +2004,12 @@ restart: ++ep; break; case matchMap: - if (!is_map_rel(*ep, base) && !is_hashmap_rel(*ep,base)) { + if (!is_flatmap_rel(*ep, base) && !is_hashmap_rel(*ep,base)) { FAIL(); } n = *pc++; - if (is_map_rel(*ep,base)) { - if (map_get_size(map_val_rel(*ep, base)) < n) { + if (is_flatmap_rel(*ep,base)) { + if (flatmap_get_size(flatmap_val_rel(*ep, base)) < n) { FAIL(); } } else { @@ -2018,15 +2018,15 @@ restart: FAIL(); } } - ep = map_val_rel(*ep, base); + ep = flatmap_val_rel(*ep, base); break; case matchPushM: - if (!is_map_rel(*ep, base) && !is_hashmap_rel(*ep, base)) { + if (!is_flatmap_rel(*ep, base) && !is_hashmap_rel(*ep, base)) { FAIL(); } n = *pc++; - if (is_map_rel(*ep,base)) { - if (map_get_size(map_val_rel(*ep, base)) < n) { + if (is_flatmap_rel(*ep,base)) { + if (flatmap_get_size(flatmap_val_rel(*ep, base)) < n) { FAIL(); } } else { @@ -2035,11 +2035,11 @@ restart: FAIL(); } } - *sp++ = map_val_rel(*ep++, base); + *sp++ = flatmap_val_rel(*ep++, base); break; case matchKey: t = (Eterm) *pc++; - tp = erts_maps_get_rel(t, make_map_rel(ep, base), base); + tp = erts_maps_get_rel(t, make_flatmap_rel(ep, base), base); if (!tp) { FAIL(); } @@ -2156,12 +2156,12 @@ restart: ehp = HAllocX(build_proc, 1 + MAP_HEADER_SIZE + n, HEAP_XTRA); t = *ehp++ = *--esp; { - map_t *m = (map_t *)ehp; + flatmap_t *m = (flatmap_t *)ehp; m->thing_word = MAP_HEADER; m->size = n; m->keys = t; } - t = make_map(ehp); + t = make_flatmap(ehp); ehp += MAP_HEADER_SIZE; while (n--) { *ehp++ = *--esp; @@ -3373,10 +3373,10 @@ int db_has_variable(Eterm node) { while(arity--) { ESTACK_PUSH(s,*(++tuple)); } - } else if (is_map(node)) { - Eterm *values = map_get_values(map_val(node)); - int size = map_get_size(map_val(node)); - ESTACK_PUSH(s, ((map_t *) map_val(node))->keys); + } else if (is_flatmap(node)) { + Eterm *values = flatmap_get_values(flatmap_val(node)); + Uint size = flatmap_get_size(flatmap_val(node)); + ESTACK_PUSH(s, ((flatmap_t *) flatmap_val(node))->keys); while (size--) { ESTACK_PUSH(s, *(values++)); } @@ -3540,7 +3540,7 @@ static DMCRet dmc_one_term(DMCContext *context, DMC_PUSH(*stack, c); break; case (_TAG_HEADER_MAP >> _TAG_PRIMARY_SIZE): - n = map_get_size(map_val(c)); + n = flatmap_get_size(flatmap_val(c)); DMC_PUSH(*text, matchPushM); ++(context->stack_used); DMC_PUSH(*text, n); @@ -3841,11 +3841,11 @@ dmc_map(DMCContext *context, DMCHeap *heap, DMC_STACK_TYPE(UWord) *text, int nelems; int constant_values; DMCRet ret; - if (is_map(t)) { - map_t *m = (map_t *)map_val(t); - Eterm *values = map_get_values(m); + if (is_flatmap(t)) { + flatmap_t *m = (flatmap_t *)flatmap_val(t); + Eterm *values = flatmap_get_values(m); - nelems = map_get_size(m); + nelems = flatmap_get_size(m); ret = dmc_array(context, heap, text, values, nelems, &constant_values); if (ret != retOk) { @@ -4915,7 +4915,7 @@ static DMCRet dmc_expr(DMCContext *context, return ret; break; case TAG_PRIMARY_BOXED: - if (is_map(t) || is_hashmap(t)) { + if (is_flatmap(t) || is_hashmap(t)) { return dmc_map(context, heap, text, t, constant); } if (!is_tuple(t)) { -- cgit v1.2.3 From 2fadbefc264d33da526ec61cffc9847f724d8d92 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Tue, 10 Mar 2015 19:57:07 +0100 Subject: erts: Reintroduce is_map macro as shorthand for is_flatmap || is_hashmap --- erts/emulator/beam/erl_db_util.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'erts/emulator/beam/erl_db_util.c') diff --git a/erts/emulator/beam/erl_db_util.c b/erts/emulator/beam/erl_db_util.c index cca3f381a1..efbefb7492 100644 --- a/erts/emulator/beam/erl_db_util.c +++ b/erts/emulator/beam/erl_db_util.c @@ -2004,7 +2004,7 @@ restart: ++ep; break; case matchMap: - if (!is_flatmap_rel(*ep, base) && !is_hashmap_rel(*ep,base)) { + if (!is_map_rel(*ep, base)) { FAIL(); } n = *pc++; @@ -2021,7 +2021,7 @@ restart: ep = flatmap_val_rel(*ep, base); break; case matchPushM: - if (!is_flatmap_rel(*ep, base) && !is_hashmap_rel(*ep, base)) { + if (!is_map_rel(*ep, base)) { FAIL(); } n = *pc++; @@ -4915,7 +4915,7 @@ static DMCRet dmc_expr(DMCContext *context, return ret; break; case TAG_PRIMARY_BOXED: - if (is_flatmap(t) || is_hashmap(t)) { + if (is_map(t)) { return dmc_map(context, heap, text, t, constant); } if (!is_tuple(t)) { -- cgit v1.2.3 From 81551dd13167b9c4458c4fee7ce08e152f9f5273 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Wed, 11 Mar 2015 20:39:08 +0100 Subject: erts: Make hashmap iterator more flexible to allow mixing of 'next' and 'prev' operations. --- erts/emulator/beam/erl_db_util.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'erts/emulator/beam/erl_db_util.c') diff --git a/erts/emulator/beam/erl_db_util.c b/erts/emulator/beam/erl_db_util.c index efbefb7492..e522876d03 100644 --- a/erts/emulator/beam/erl_db_util.c +++ b/erts/emulator/beam/erl_db_util.c @@ -1435,7 +1435,7 @@ restart: } structure_checked = 0; - hashmap_iterator_init(&wstack, t); + hashmap_iterator_init(&wstack, t, 0); while ((kv=hashmap_iterator_next(&wstack)) != NULL) { Eterm key = CAR(kv); @@ -3872,7 +3872,7 @@ dmc_map(DMCContext *context, DMCHeap *heap, DMC_STACK_TYPE(UWord) *text, ASSERT(is_hashmap(t)); - hashmap_iterator_init(&wstack, t); + hashmap_iterator_init(&wstack, t, 1); constant_values = 1; nelems = hashmap_size(t); @@ -3893,7 +3893,7 @@ dmc_map(DMCContext *context, DMCHeap *heap, DMC_STACK_TYPE(UWord) *text, *constant = 0; - hashmap_iterator_init(&wstack, t); + hashmap_iterator_init(&wstack, t, 1); while ((kv=hashmap_iterator_prev(&wstack)) != NULL) { /* push key */ -- cgit v1.2.3