change unsafe immutable hash table iteration
This commit is contained in:
parent
b8341f1559
commit
811ae4f72a
|
@ -2759,6 +2759,116 @@ Scheme_Object *scheme_hash_tree_next_pos(Scheme_Hash_Tree *tree, mzlonglong pos)
|
|||
# define HAMT_TRAVERSE_NEXT(i) ((i)+1)
|
||||
#endif
|
||||
|
||||
XFORM_NONGCING static void hamt_subtree_at_index(Scheme_Hash_Tree *ht, mzlonglong pos,
|
||||
Scheme_Hash_Tree **_subtree, int *_i, int *_popcount)
|
||||
{
|
||||
int popcount, i;
|
||||
Scheme_Hash_Tree *sub;
|
||||
|
||||
while (1) {
|
||||
popcount = hamt_popcount(ht->bitmap);
|
||||
i = HAMT_TRAVERSE_INIT(popcount);
|
||||
while (1) {
|
||||
if (HASHTR_SUBTREEP(ht->els[i])
|
||||
|| HASHTR_COLLISIONP(ht->els[i])) {
|
||||
sub = (Scheme_Hash_Tree *)ht->els[i];
|
||||
if (pos < sub->count) {
|
||||
ht = sub;
|
||||
break; /* to outer loop */
|
||||
} else
|
||||
pos -= sub->count;
|
||||
} else {
|
||||
if (!pos) {
|
||||
*_subtree = ht;
|
||||
*_i = i;
|
||||
if (_popcount) *_popcount = popcount;
|
||||
return;
|
||||
}
|
||||
--pos;
|
||||
}
|
||||
i = HAMT_TRAVERSE_NEXT(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* We have two different implementations of Scheme_Hash_Tree traversal
|
||||
as exposed by `unsafe-immutable-hash-next`, etc.:
|
||||
|
||||
* Consecutive integers from 0 as the index values (the same as
|
||||
`scheme_hash_tree_next`), or
|
||||
|
||||
* Subtree lists (for the spine of a subtree up to the root) plus
|
||||
offset into a subtree.
|
||||
|
||||
The second one is more direct, but requires some allocation. To
|
||||
avoid allocation for small trees, it uses an integer encoding of a
|
||||
path.
|
||||
|
||||
The first implementation is better for small trees, and the second
|
||||
is better for very large trees, but there's not a big difference.
|
||||
Small trees dominate for macro expansion, which is a big use of
|
||||
hash trees, so that gives the first implementation the edge.
|
||||
|
||||
Microbenchmark:
|
||||
|
||||
(let loop ([size 2])
|
||||
(define ht (for/hasheq ([i (in-range size)])
|
||||
(values i i)))
|
||||
(define c (quotient 10000000 size))
|
||||
(printf "~s: " size)
|
||||
(time
|
||||
(for ([j (in-range c)])
|
||||
(for/fold ([v #f]) ([k (in-immutable-hash-keys ht)])
|
||||
k)))
|
||||
(unless (= size (expt 2 20))
|
||||
(loop (* size 2))))
|
||||
|
||||
*/
|
||||
|
||||
#if 1
|
||||
/* ------ Implementation 1 of hash-tree traversal ------ */
|
||||
|
||||
Scheme_Object *scheme_unsafe_hash_tree_start(Scheme_Hash_Tree *ht)
|
||||
{
|
||||
ht = resolve_placeholder(ht);
|
||||
|
||||
if (!ht->count)
|
||||
return scheme_false;
|
||||
else
|
||||
return scheme_make_integer(0);
|
||||
}
|
||||
|
||||
XFORM_NONGCING void scheme_unsafe_hash_tree_subtree(Scheme_Object *obj, Scheme_Object *args,
|
||||
Scheme_Hash_Tree **_subtree, int *_i)
|
||||
{
|
||||
Scheme_Hash_Tree *ht;
|
||||
|
||||
if (SCHEME_NP_CHAPERONEP(obj))
|
||||
obj = SCHEME_CHAPERONE_VAL(obj);
|
||||
ht = (Scheme_Hash_Tree *)obj;
|
||||
ht = resolve_placeholder(ht);
|
||||
|
||||
hamt_subtree_at_index(ht, SCHEME_INT_VAL(args), _subtree, _i, NULL);
|
||||
}
|
||||
|
||||
XFORM_NONGCING Scheme_Object *scheme_unsafe_hash_tree_access(Scheme_Hash_Tree *subtree, int i)
|
||||
{
|
||||
return _mzHAMT_VAL(subtree, i, hamt_popcount(subtree->bitmap));
|
||||
}
|
||||
|
||||
Scheme_Object *scheme_unsafe_hash_tree_next(Scheme_Hash_Tree *ht, Scheme_Object *args)
|
||||
{
|
||||
intptr_t i = SCHEME_INT_VAL(args) + 1;
|
||||
ht = resolve_placeholder(ht);
|
||||
if (i < ht->count)
|
||||
return scheme_make_integer(i);
|
||||
else
|
||||
return scheme_false;
|
||||
}
|
||||
|
||||
#else
|
||||
/* ------ Implementation 2 of hash-tree traversal ------ */
|
||||
|
||||
#define mzHAMT_MAX_INDEX_LEVEL 4 /* For the compressed form of the index */
|
||||
|
||||
Scheme_Object *make_index_frame(Scheme_Hash_Tree *ht, intptr_t i, Scheme_Object *rest)
|
||||
|
@ -2948,38 +3058,21 @@ Scheme_Object *scheme_unsafe_hash_tree_next(Scheme_Hash_Tree *ht, Scheme_Object
|
|||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
XFORM_NONGCING static void hamt_at_index(Scheme_Hash_Tree *ht, mzlonglong pos,
|
||||
Scheme_Object **_key, Scheme_Object **_val, uintptr_t *_code)
|
||||
{
|
||||
int popcount, i;
|
||||
Scheme_Hash_Tree *sub;
|
||||
|
||||
while (1) {
|
||||
popcount = hamt_popcount(ht->bitmap);
|
||||
i = HAMT_TRAVERSE_INIT(popcount);
|
||||
while (1) {
|
||||
if (HASHTR_SUBTREEP(ht->els[i])
|
||||
|| HASHTR_COLLISIONP(ht->els[i])) {
|
||||
sub = (Scheme_Hash_Tree *)ht->els[i];
|
||||
if (pos < sub->count) {
|
||||
ht = sub;
|
||||
break; /* to outer loop */
|
||||
} else
|
||||
pos -= sub->count;
|
||||
} else {
|
||||
if (!pos) {
|
||||
*_key = ht->els[i];
|
||||
if (_val)
|
||||
*_val = _mzHAMT_VAL(ht, i, popcount);
|
||||
if (_code)
|
||||
*_code = _mzHAMT_CODE(ht, i, popcount);
|
||||
return;
|
||||
}
|
||||
--pos;
|
||||
}
|
||||
i = HAMT_TRAVERSE_NEXT(i);
|
||||
}
|
||||
}
|
||||
hamt_subtree_at_index(ht, pos, &sub, &i, &popcount);
|
||||
|
||||
*_key = sub->els[i];
|
||||
if (_val)
|
||||
*_val = _mzHAMT_VAL(sub, i, popcount);
|
||||
if (_code)
|
||||
*_code = _mzHAMT_CODE(sub, i, popcount);
|
||||
}
|
||||
|
||||
int scheme_hash_tree_index(Scheme_Hash_Tree *ht, mzlonglong pos, Scheme_Object **_key, Scheme_Object **_val)
|
||||
|
|
|
@ -10385,7 +10385,7 @@ static Scheme_Object *get_linklet_or_instance_for_import_key(Optimize_Info *info
|
|||
if (!cross || !cross->get_import)
|
||||
return NULL;
|
||||
|
||||
v = scheme_hash_tree_get(cross->linklets, key);
|
||||
v = scheme_eq_hash_tree_get(cross->linklets, key);
|
||||
if (!v) {
|
||||
a[0] = key;
|
||||
v = scheme_apply_multi(cross->get_import, 1, a);
|
||||
|
@ -10455,7 +10455,7 @@ static Scheme_Object *get_import_inline_or_shape(Optimize_Info *info, Scheme_IR_
|
|||
if (!info->cross || (var->instance_pos < 0))
|
||||
return NULL;
|
||||
|
||||
key = scheme_hash_tree_get(info->cross->import_keys, scheme_make_integer(var->instance_pos));
|
||||
key = scheme_eq_hash_tree_get(info->cross->import_keys, scheme_make_integer(var->instance_pos));
|
||||
if (!key)
|
||||
return NULL;
|
||||
|
||||
|
@ -10606,10 +10606,10 @@ Scheme_Object *scheme_optimize_add_import_variable(Optimize_Info *info, Scheme_O
|
|||
if (SCHEME_FALSEP(linklet_key))
|
||||
return NULL;
|
||||
|
||||
pos = scheme_hash_tree_get(info->cross->rev_import_keys, linklet_key);
|
||||
pos = scheme_eq_hash_tree_get(info->cross->rev_import_keys, linklet_key);
|
||||
MZ_ASSERT(pos);
|
||||
|
||||
syms = (Scheme_Hash_Tree *)scheme_hash_tree_get(info->cross->import_syms, pos);
|
||||
syms = (Scheme_Hash_Tree *)scheme_eq_hash_tree_get(info->cross->import_syms, pos);
|
||||
if (!syms) {
|
||||
syms = empty_eq_hash_tree;
|
||||
if (SCHEME_INT_VAL(pos) < SCHEME_VEC_SIZE(info->linklet->importss)) {
|
||||
|
@ -10626,7 +10626,7 @@ Scheme_Object *scheme_optimize_add_import_variable(Optimize_Info *info, Scheme_O
|
|||
info->cross->import_syms = ht;
|
||||
}
|
||||
|
||||
var_pos = scheme_hash_tree_get(syms, symbol);
|
||||
var_pos = scheme_eq_hash_tree_get(syms, symbol);
|
||||
if (!var_pos) {
|
||||
var_pos = scheme_make_integer(syms->count >> 1);
|
||||
syms = scheme_hash_tree_set(syms, symbol, var_pos);
|
||||
|
@ -10646,7 +10646,7 @@ Scheme_Object *scheme_optimize_get_import_key(Optimize_Info *info, Scheme_Object
|
|||
Scheme_Object *next_keys, *key, *pos;
|
||||
Scheme_Hash_Tree *ht;
|
||||
|
||||
next_keys = scheme_hash_tree_get(info->cross->import_next_keys, linklet_key);
|
||||
next_keys = scheme_eq_hash_tree_get(info->cross->import_next_keys, linklet_key);
|
||||
if (!next_keys) {
|
||||
/* chaining is not supported by the compilation client */
|
||||
return NULL;
|
||||
|
@ -10655,7 +10655,7 @@ Scheme_Object *scheme_optimize_get_import_key(Optimize_Info *info, Scheme_Object
|
|||
MZ_ASSERT(instance_pos < SCHEME_VEC_SIZE(next_keys));
|
||||
|
||||
key = SCHEME_VEC_ELS(next_keys)[instance_pos];
|
||||
pos = scheme_hash_tree_get(info->cross->rev_import_keys, key);
|
||||
pos = scheme_eq_hash_tree_get(info->cross->rev_import_keys, key);
|
||||
if (!pos) {
|
||||
/* Add this linklet as an import */
|
||||
pos = scheme_make_integer(info->cross->import_keys->count);
|
||||
|
@ -10720,7 +10720,7 @@ static void record_optimize_shapes(Optimize_Info *info, Scheme_Linklet *linklet,
|
|||
|
||||
/* Add imported variables for each instance */
|
||||
for (i = 0; i < SCHEME_VEC_SIZE(linklet->importss); i++) {
|
||||
ht = (Scheme_Hash_Tree *)scheme_hash_tree_get(info->cross->import_syms, scheme_make_integer(i));
|
||||
ht = (Scheme_Hash_Tree *)scheme_eq_hash_tree_get(info->cross->import_syms, scheme_make_integer(i));
|
||||
if (ht && ((ht->count >> 1) > SCHEME_VEC_SIZE(SCHEME_VEC_ELS(linklet->importss)[i]))) {
|
||||
Scheme_Object *sym;
|
||||
v = scheme_make_vector((ht->count >> 1), NULL);
|
||||
|
@ -10776,7 +10776,7 @@ static void record_optimize_shapes(Optimize_Info *info, Scheme_Linklet *linklet,
|
|||
used = 0;
|
||||
for (i = 0; i < SCHEME_VEC_SIZE(linklet->importss); i++) {
|
||||
if (!SCHEME_INTP(SCHEME_VEC_ELS(linklet->importss)[i])) {
|
||||
v = scheme_hash_tree_get(info->cross->import_keys, scheme_make_integer(i));
|
||||
v = scheme_eq_hash_tree_get(info->cross->import_keys, scheme_make_integer(i));
|
||||
MZ_ASSERT(v);
|
||||
SCHEME_VEC_ELS((*_import_keys))[used++] = v;
|
||||
}
|
||||
|
@ -10791,9 +10791,9 @@ static void record_optimize_shapes(Optimize_Info *info, Scheme_Linklet *linklet,
|
|||
k = 0;
|
||||
for (i = 0; i < SCHEME_VEC_SIZE(linklet->importss); i++) {
|
||||
if (!SCHEME_INTP(SCHEME_VEC_ELS(linklet->importss)[i])) {
|
||||
v = scheme_hash_tree_get(info->cross->import_keys, scheme_make_integer(i));
|
||||
v = scheme_eq_hash_tree_get(info->cross->import_keys, scheme_make_integer(i));
|
||||
if (v)
|
||||
v = scheme_hash_tree_get(info->cross->linklets, v);
|
||||
v = scheme_eq_hash_tree_get(info->cross->linklets, v);
|
||||
in_linklet = ((v && SAME_TYPE(SCHEME_TYPE(v), scheme_linklet_type)) ? (Scheme_Linklet *)v : NULL);
|
||||
in_instance = ((v && SAME_TYPE(SCHEME_TYPE(v), scheme_instance_type)) ? (Scheme_Instance *)v : NULL);
|
||||
MZ_ASSERT(!in_linklet || SAME_TYPE(in_linklet->so.type, scheme_linklet_type));
|
||||
|
|
Loading…
Reference in New Issue
Block a user