diff --git a/SConstruct b/SConstruct index fd1a7e3eb6c35e126fdd3361a175bd0dc6ee97a0..7979b3393d58e2fef09992d8626d3ba2960f6839 100644 --- a/SConstruct +++ b/SConstruct @@ -73,6 +73,12 @@ AddOption('--coverage', action='store_true', help='Build with coverage instrumentation') +AddOption('--force-debug', + dest='force_debug', + default=False, + action='store_true', + help='Build with debug symbols, even in the opt variant') + AddOption('--gprof', dest='gprof', default=False, @@ -135,6 +141,12 @@ if GetOption('coverage'): else: env.ParseConfig('llvm-config --ldflags') +if GetOption('force_debug'): + if env['CC'] == 'cl': + env.Append(CCFLAGS=['/Z7']) + else: + env.Append(CCFLAGS=['-g']) + if GetOption('gprof'): if env['CC'] == 'gcc' and env['CXX'] == 'g++': env.Append(CCFLAGS=['-pg'], diff --git a/src/backends/packrat.c b/src/backends/packrat.c index 276dfd171f4c8a13ab68953a69f5bbd733c522ab..91e4a09224cb03c4eac23d1713dbbc70941d6618 100644 --- a/src/backends/packrat.c +++ b/src/backends/packrat.c @@ -3,6 +3,8 @@ #include "../internal.h" #include "../parsers/parser_internal.h" +static uint32_t cache_key_hash(const void* key); + // short-hand for creating lowlevel parse cache values (parse result case) static HParserCacheValue * cached_result(HParseState *state, HParseResult *result) { @@ -56,31 +58,38 @@ static inline HParseResult* perform_lowlevel_parse(HParseState *state, const HPa return tmp_res; } -HParserCacheValue* recall(HParserCacheKey *k, HParseState *state) { - HParserCacheValue *cached = h_hashtable_get(state->cache, k); +HParserCacheValue* recall(HParserCacheKey *k, HParseState *state, HHashValue keyhash) { + HParserCacheValue *cached = h_hashtable_get_precomp(state->cache, k, keyhash); HRecursionHead *head = h_hashtable_get(state->recursion_heads, &k->input_pos); - if (!head) { // No heads found + + if (!head) { + /* No heads found */ return cached; - } else { // Some heads found + } else { + /* Some heads found */ if (!cached && head->head_parser != k->parser && !h_slist_find(head->involved_set, k->parser)) { - // Nothing in the cache, and the key parser is not involved + /* Nothing in the cache, and the key parser is not involved */ cached = cached_result(state, NULL); cached->input_stream = k->input_pos; } if (h_slist_find(head->eval_set, k->parser)) { - // Something is in the cache, and the key parser is in the eval set. Remove the key parser from the eval set of the head. + /* + * Something is in the cache, and the key parser is in the eval set. + * Remove the key parser from the eval set of the head. + */ head->eval_set = h_slist_remove_all(head->eval_set, k->parser); HParseResult *tmp_res = perform_lowlevel_parse(state, k->parser); - // update the cache + /* update the cache */ if (!cached) { - cached = cached_result(state, tmp_res); - h_hashtable_put(state->cache, k, cached); + cached = cached_result(state, tmp_res); + h_hashtable_put_precomp(state->cache, k, cached, keyhash); } else { - cached->value_type = PC_RIGHT; - cached->right = tmp_res; - cached->input_stream = state->input_stream; + cached->value_type = PC_RIGHT; + cached->right = tmp_res; + cached->input_stream = state->input_stream; } } + return cached; } } @@ -180,36 +189,50 @@ HParseResult* lr_answer(HParserCacheKey *k, HParseState *state, HLeftRec *growab /* Warth's recursion. Hi Alessandro! */ HParseResult* h_do_parse(const HParser* parser, HParseState *state) { HParserCacheKey *key = a_new(HParserCacheKey, 1); + HHashValue keyhash; + HLeftRec *base = NULL; + HParserCacheValue *m = NULL, *cached = NULL; + key->input_pos = state->input_stream; key->parser = parser; - HParserCacheValue *m = NULL; + keyhash = cache_key_hash(key); + if (parser->vtable->higher) { - m = recall(key, state); + m = recall(key, state, keyhash); } - // check to see if there is already a result for this object... + + /* check to see if there is already a result for this object... */ if (!m) { - // It doesn't exist, so create a dummy result to cache - HLeftRec *base = NULL; - // But only cache it now if there's some chance it could grow; primitive parsers can't + /* + * But only cache it now if there's some chance it could grow; primitive + * parsers can't + */ if (parser->vtable->higher) { base = a_new(HLeftRec, 1); base->seed = NULL; base->rule = parser; base->head = NULL; h_slist_push(state->lr_stack, base); - // cache it - h_hashtable_put(state->cache, key, cached_lr(state, base)); - // parse the input + /* cache it */ + h_hashtable_put_precomp(state->cache, key, + cached_lr(state, base), keyhash); } + + /* parse the input */ HParseResult *tmp_res = perform_lowlevel_parse(state, parser); if (parser->vtable->higher) { - // the base variable has passed equality tests with the cache + /* the base variable has passed equality tests with the cache */ h_slist_pop(state->lr_stack); - // update the cached value to our new position - HParserCacheValue *cached = h_hashtable_get(state->cache, key); + /* update the cached value to our new position */ + cached = h_hashtable_get_precomp(state->cache, key, keyhash); assert(cached != NULL); cached->input_stream = state->input_stream; } - // setupLR, used below, mutates the LR to have a head if appropriate, so we check to see if we have one + + /* + * setupLR, used below, mutates the LR to have a head if appropriate, + * so we check to see if we have one + */ if (!base || NULL == base->head) { - h_hashtable_put(state->cache, key, cached_result(state, tmp_res)); + h_hashtable_put_precomp(state->cache, key, + cached_result(state, tmp_res), keyhash); return tmp_res; } else { base->seed = tmp_res; @@ -217,7 +240,7 @@ HParseResult* h_do_parse(const HParser* parser, HParseState *state) { return res; } } else { - // it exists! + /* it exists! */ state->input_stream = m->input_stream; if (PC_LEFT == m->value_type) { setupLR(parser, state, m->left); diff --git a/src/datastructures.c b/src/datastructures.c index 451afb94ec39932dfe1f8c58aa82c0777f73b011..99d821f1a93e8fbfa2189a581b6fd59afb367bc7 100644 --- a/src/datastructures.c +++ b/src/datastructures.c @@ -149,13 +149,14 @@ HHashTable* h_hashtable_new(HArena *arena, HEqualFunc equalFunc, HHashFunc hashF return ht; } -void* h_hashtable_get(const HHashTable* ht, const void* key) { - HHashValue hashval = ht->hashFunc(key); +void * h_hashtable_get_precomp(const HHashTable *ht, const void *key, + HHashValue hashval) { + HHashTableEntry *hte = NULL; + #ifdef CONSISTENCY_CHECK assert((ht->capacity & (ht->capacity - 1)) == 0); // capacity is a power of 2 #endif - HHashTableEntry *hte = NULL; for (hte = &ht->contents[hashval & (ht->capacity - 1)]; hte != NULL; hte = hte->next) { @@ -169,9 +170,16 @@ void* h_hashtable_get(const HHashTable* ht, const void* key) { return hte->value; } } + return NULL; } +void * h_hashtable_get(const HHashTable *ht, const void *key) { + HHashValue hashval = ht->hashFunc(key); + + return h_hashtable_get_precomp(ht, key, hashval); +} + void h_hashtable_put_raw(HHashTable* ht, HHashTableEntry* new_entry); void h_hashtable_ensure_capacity(HHashTable* ht, size_t n) { @@ -197,7 +205,21 @@ void h_hashtable_ensure_capacity(HHashTable* ht, size_t n) { //h_arena_free(ht->arena, old_contents); } -void h_hashtable_put(HHashTable* ht, const void* key, void* value) { +void h_hashtable_put_precomp(HHashTable *ht, const void *key, void *value, + HHashValue hashval) { + HHashTableEntry entry = { + .key = key, + .value = value, + .hashval = hashval + }; + + /* Rebalance if necessary */ + h_hashtable_ensure_capacity(ht, ht->used + 1); + /* Insert it */ + h_hashtable_put_raw(ht, &entry); +} + +void h_hashtable_put(HHashTable *ht, const void *key, void *value) { // # Start with a rebalancing h_hashtable_ensure_capacity(ht, ht->used + 1); diff --git a/src/internal.h b/src/internal.h index 324fcbafc5ef7601fac70ceaea04894b8d46010d..07420681275a989925a08f6c596e3bc4a59202c1 100644 --- a/src/internal.h +++ b/src/internal.h @@ -367,16 +367,21 @@ HSlist* h_slist_remove_all(HSlist *slist, const void* item); void h_slist_free(HSlist *slist); static inline bool h_slist_empty(const HSlist *sl) { return (sl->head == NULL); } -HHashTable* h_hashtable_new(HArena *arena, HEqualFunc equalFunc, HHashFunc hashFunc); -void* h_hashtable_get(const HHashTable* ht, const void* key); -void h_hashtable_put(HHashTable* ht, const void* key, void* value); -void h_hashtable_update(HHashTable* dst, const HHashTable *src); -void h_hashtable_merge(void *(*combine)(void *v1, const void *v2), +HHashTable* h_hashtable_new(HArena *arena, HEqualFunc equalFunc, + HHashFunc hashFunc); +void * h_hashtable_get_precomp(const HHashTable *ht, const void *key, + HHashValue hashval); +void * h_hashtable_get(const HHashTable *ht, const void *key); +void h_hashtable_put_precomp(HHashTable *ht, const void *key, + void *value, HHashValue hashval); +void h_hashtable_put(HHashTable *ht, const void *key, void *value); +void h_hashtable_update(HHashTable *dst, const HHashTable *src); +void h_hashtable_merge(void *(*combine)(void *v1, const void *v2), HHashTable *dst, const HHashTable *src); -int h_hashtable_present(const HHashTable* ht, const void* key); -void h_hashtable_del(HHashTable* ht, const void* key); -void h_hashtable_free(HHashTable* ht); -static inline bool h_hashtable_empty(const HHashTable* ht) { return (ht->used == 0); } +int h_hashtable_present(const HHashTable *ht, const void *key); +void h_hashtable_del(HHashTable *ht, const void *key); +void h_hashtable_free(HHashTable *ht); +static inline bool h_hashtable_empty(const HHashTable *ht) { return (ht->used == 0); } typedef HHashTable HHashSet; #define h_hashset_new(a,eq,hash) h_hashtable_new(a,eq,hash)