Subclass cleanup must use exact key match to not call VM during GC sweep

This commit is contained in:
K. Lange 2022-07-09 18:50:31 +09:00
parent ff23dbbc14
commit 6fa951a0bb
3 changed files with 49 additions and 1 deletions

View File

@ -140,6 +140,19 @@ extern int krk_tableGet_fast(KrkTable * table, KrkString * str, KrkValue * value
*/
extern int krk_tableDelete(KrkTable * table, KrkValue key);
/**
* @brief Remove a key from a hash table, with identity lookup.
* @memberof KrkTable
*
* Scans the table 'table' for the key 'key' and, if found, removes
* the entry, replacing it with a tombstone value.
*
* @param table Table to delete from.
* @param key Key to delete.
* @return 1 if the value was found and deleted, 0 if it was not present.
*/
extern int krk_tableDeleteExact(KrkTable * table, KrkValue key);
/**
* @brief Internal table scan function.
* @memberof KrkTable

View File

@ -237,7 +237,7 @@ static void freeObject(KrkObj * object) {
krk_freeTable(&_class->methods);
krk_freeTable(&_class->subclasses);
if (_class->base) {
krk_tableDelete(&_class->base->subclasses, OBJECT_VAL(object));
krk_tableDeleteExact(&_class->base->subclasses, OBJECT_VAL(object));
}
FREE(KrkClass, object);
break;

View File

@ -82,6 +82,29 @@ KrkTableEntry * krk_findEntry(KrkTableEntry * entries, size_t capacity, KrkValue
}
}
KrkTableEntry * krk_findEntryExact(KrkTableEntry * entries, size_t capacity, KrkValue key) {
uint32_t index;
if (krk_hashValue(key, &index)) {
return NULL;
}
index &= (capacity-1);
KrkTableEntry * tombstone = NULL;
for (;;) {
KrkTableEntry * entry = &entries[index];
if (IS_KWARGS(entry->key)) {
if (IS_NONE(entry->value)) {
return tombstone != NULL ? tombstone : entry;
} else {
if (tombstone == entry) return tombstone;
if (tombstone == NULL) tombstone = entry;
}
} else if (krk_valuesSame(entry->key, key)) {
return entry;
}
index = (index + 1) & (capacity-1);
}
}
#ifdef __TINYC__
int __builtin_clz(unsigned int x) {
int i = 31;
@ -189,6 +212,18 @@ int krk_tableDelete(KrkTable * table, KrkValue key) {
return 1;
}
int krk_tableDeleteExact(KrkTable * table, KrkValue key) {
if (table->count == 0) return 0;
KrkTableEntry * entry = krk_findEntryExact(table->entries, table->capacity, key);
if (!entry || IS_KWARGS(entry->key)) {
return 0;
}
table->count--;
entry->key = KWARGS_VAL(0);
entry->value = KWARGS_VAL(0);
return 1;
}
KrkString * krk_tableFindString(KrkTable * table, const char * chars, size_t length, uint32_t hash) {
if (table->count == 0) return NULL;