diff options
author | Max Horn | 2009-05-03 09:17:55 +0000 |
---|---|---|
committer | Max Horn | 2009-05-03 09:17:55 +0000 |
commit | 5ef0e38fdd4381b174ae7742ff18390dd86a53a2 (patch) | |
tree | 0d83c1c325dadfd6197b03d950b76989ecb3716d | |
parent | 4d57c1f9a9e849f5d8cd3d56da6bcb51da0789d5 (diff) | |
download | scummvm-rg350-5ef0e38fdd4381b174ae7742ff18390dd86a53a2.tar.gz scummvm-rg350-5ef0e38fdd4381b174ae7742ff18390dd86a53a2.tar.bz2 scummvm-rg350-5ef0e38fdd4381b174ae7742ff18390dd86a53a2.zip |
SCI: Changed VM GC code to use Common::Array
svn-id: r40263
-rw-r--r-- | engines/sci/engine/gc.cpp | 145 |
1 files changed, 42 insertions, 103 deletions
diff --git a/engines/sci/engine/gc.cpp b/engines/sci/engine/gc.cpp index c3fcfff75f..abdcd9f26f 100644 --- a/engines/sci/engine/gc.cpp +++ b/engines/sci/engine/gc.cpp @@ -24,89 +24,39 @@ */ #include "sci/engine/gc.h" +#include "common/array.h" namespace Sci { -#define WORKLIST_CHUNK_SIZE 32 - //#define DEBUG_GC //#define DEBUG_GC_VERBOSE -struct worklist_t { - int used; - reg_t entries[WORKLIST_CHUNK_SIZE]; - worklist_t *next; -}; - -static worklist_t *fresh_worklist(worklist_t *old) { - worklist_t *retval = (worklist_t*)sci_malloc(sizeof(worklist_t)); - retval->used = 0; - retval->next = old; - return retval; -} - -static worklist_t *new_worklist() { - return fresh_worklist(NULL); -} +struct WorklistManager { + Common::Array<reg_t> _worklist; + reg_t_hash_map _map; -static void worklist_push(worklist_t **wlp, reg_t_hash_map *hashmap, reg_t reg) { - worklist_t *wl = *wlp; + void push(reg_t reg) { + if (!reg.segment) // No numbers + return; - if (!reg.segment) // No numbers - return; + #ifdef DEBUG_GC_VERBOSE + sciprintf("[GC] Adding "PREG"\n", PRINT_REG(reg)); + #endif -#ifdef DEBUG_GC_VERBOSE - sciprintf("[GC] Adding "PREG"\n", PRINT_REG(reg)); -#endif - - if (hashmap->contains(reg)) - return; // already dealt with it - - hashmap->setVal(reg, true); - - if (!wl || wl->used == WORKLIST_CHUNK_SIZE) - *wlp = wl = fresh_worklist(wl); - - wl->entries[wl->used++] = reg; -} - -static int worklist_has_next(worklist_t *wl) { - return (wl && wl->used); -} + if (_map.contains(reg)) + return; // already dealt with it -static reg_t worklist_pop(worklist_t **wlp) { - worklist_t *wl = *wlp; - reg_t retval; - - if (!wl || !wl->used) { - error("Attempt to pop from empty worklist"); - } - - retval = wl->entries[--wl->used]; - - if (!wl->used) { - *wlp = wl->next; - free(wl); - } - - return retval; -} - -static void free_worklist(worklist_t *wl) { - if (wl) { - if (wl->next) - free_worklist(wl->next); - free(wl); + _map.setVal(reg, true); + _worklist.push_back(reg); } -} +}; -static reg_t_hash_map *normalise_hashmap_ptrs(reg_t_hash_map *nonnormal_map, SegInterface **interfaces, int interfaces_nr) { +static reg_t_hash_map *normalise_hashmap_ptrs(reg_t_hash_map &nonnormal_map, const Common::Array<SegInterface *> &interfaces) { reg_t_hash_map *normal_map = new reg_t_hash_map(); - for (reg_t_hash_map::iterator i = nonnormal_map->begin(); i != nonnormal_map->end(); ++i) { - SegInterface *interfce; + for (reg_t_hash_map::iterator i = nonnormal_map.begin(); i != nonnormal_map.end(); ++i) { reg_t reg = i->_key; - interfce = (reg.segment < interfaces_nr) ? interfaces[reg.segment] : NULL; + SegInterface *interfce = (reg.segment < interfaces.size()) ? interfaces[reg.segment] : NULL; if (interfce) { reg = interfce->findCanonicAddress(reg); @@ -118,28 +68,19 @@ static reg_t_hash_map *normalise_hashmap_ptrs(reg_t_hash_map *nonnormal_map, Seg } -struct worklist_manager_t { - reg_t_hash_map *nonnormal_map; - worklist_t **worklist_ref; -}; - -void add_outgoing_refs(void *pre_wm, reg_t addr) { - worklist_manager_t *wm = (worklist_manager_t *) pre_wm; - worklist_push(wm->worklist_ref, wm->nonnormal_map, addr); +void add_outgoing_refs(void *refcon, reg_t addr) { + WorklistManager *wm = (WorklistManager *)refcon; + wm->push(addr); } reg_t_hash_map *find_all_used_references(EngineState *s) { SegManager *sm = s->seg_manager; - SegInterface **interfaces = (SegInterface **)sci_calloc(sizeof(SegInterface *), sm->heap_size); - reg_t_hash_map *nonnormal_map = new reg_t_hash_map(); + Common::Array<SegInterface *> interfaces; reg_t_hash_map *normal_map = NULL; - worklist_t *worklist = new_worklist(); - worklist_manager_t worklist_manager; + WorklistManager wm; int i; - worklist_manager.worklist_ref = &worklist; - worklist_manager.nonnormal_map = nonnormal_map; - + interfaces.resize(sm->heap_size); for (i = 1; i < sm->heap_size; i++) if (sm->heap[i] == NULL) interfaces[i] = NULL; @@ -148,8 +89,8 @@ reg_t_hash_map *find_all_used_references(EngineState *s) { // Initialise // Init: Registers - worklist_push(&worklist, nonnormal_map, s->r_acc); - worklist_push(&worklist, nonnormal_map, s->r_prev); + wm.push(s->r_acc); + wm.push(s->r_prev); // Init: Value Stack // We do this one by hand since the stack doesn't know the current execution stack { @@ -157,7 +98,7 @@ reg_t_hash_map *find_all_used_references(EngineState *s) { reg_t *pos; for (pos = s->stack_base; pos < xs.sp; pos++) - worklist_push(&worklist, nonnormal_map, *pos); + wm.push(*pos); } #ifdef DEBUG_GC_VERBOSE sciprintf("[GC] -- Finished adding value stack"); @@ -168,10 +109,10 @@ reg_t_hash_map *find_all_used_references(EngineState *s) { ExecStack &es = s->_executionStack[i]; if (es.type != EXEC_STACK_TYPE_KERNEL) { - worklist_push(&worklist, nonnormal_map, es.objp); - worklist_push(&worklist, nonnormal_map, es.sendp); + wm.push(es.objp); + wm.push(es.sendp); if (es.type == EXEC_STACK_TYPE_VARSELECTOR) - worklist_push(&worklist, nonnormal_map, *(es.addr.varp)); + wm.push(*(es.addr.varp)); } } #ifdef DEBUG_GC_VERBOSE @@ -188,12 +129,12 @@ reg_t_hash_map *find_all_used_references(EngineState *s) { int obj_nr; // Locals, if present - worklist_push(&worklist, nonnormal_map, make_reg(script->locals_segment, 0)); + wm.push(make_reg(script->locals_segment, 0)); // All objects (may be classes, may be indirectly reachable) for (obj_nr = 0; obj_nr < script->objects_nr; obj_nr++) { Object *obj = script->objects + obj_nr; - worklist_push(&worklist, nonnormal_map, obj->pos); + wm.push(obj->pos); } } } @@ -202,29 +143,26 @@ reg_t_hash_map *find_all_used_references(EngineState *s) { #endif // Run Worklist Algorithm - while (worklist_has_next(worklist)) { - reg_t reg = worklist_pop(&worklist); + while (!wm._worklist.empty()) { + reg_t reg = wm._worklist.back(); + wm._worklist.pop_back(); if (reg.segment != s->stack_segment) { // No need to repeat this one #ifdef DEBUG_GC_VERBOSE sciprintf("[GC] Checking "PREG"\n", PRINT_REG(reg)); #endif if (reg.segment < sm->heap_size && interfaces[reg.segment]) - interfaces[reg.segment]->listAllOutgoingReferences(s, reg, - &worklist_manager, add_outgoing_refs); + interfaces[reg.segment]->listAllOutgoingReferences(s, reg, &wm, add_outgoing_refs); } } // Normalise - normal_map = normalise_hashmap_ptrs(nonnormal_map, interfaces, sm->heap_size); + normal_map = normalise_hashmap_ptrs(wm._map, interfaces); // Cleanup for (i = 1; i < sm->heap_size; i++) if (interfaces[i]) delete interfaces[i]; - free(interfaces); - delete nonnormal_map; - return normal_map; } @@ -237,8 +175,8 @@ struct deallocator_t { reg_t_hash_map *use_map; }; -void free_unless_used(void *pre_use_map, reg_t addr) { - deallocator_t *deallocator = (deallocator_t *)pre_use_map; +void free_unless_used(void *refcon, reg_t addr) { + deallocator_t *deallocator = (deallocator_t *)refcon; reg_t_hash_map *use_map = deallocator->use_map; if (!use_map->contains(addr)) { @@ -246,7 +184,7 @@ void free_unless_used(void *pre_use_map, reg_t addr) { deallocator->interfce->freeAtAddress(addr); #ifdef DEBUG_GC sciprintf("[GC] Deallocating "PREG"\n", PRINT_REG(addr)); - deallocator->segcount[deallocator->interfce->type_id]++; + deallocator->segcount[deallocator->interfce->getType()]++; #endif } @@ -258,6 +196,7 @@ void run_gc(EngineState *s) { SegManager *sm = s->seg_manager; #ifdef DEBUG_GC + extern int c_segtable(EngineState *s); c_segtable(s); sciprintf("[GC] Running...\n"); memset(&(deallocator.segcount), 0, sizeof(int) * (MEM_OBJ_MAX + 1)); @@ -269,7 +208,7 @@ void run_gc(EngineState *s) { if (sm->heap[seg_nr] != NULL) { deallocator.interfce = sm->getSegInterface(seg_nr); #ifdef DEBUG_GC - deallocator.segnames[deallocator.interfce->type_id] = deallocator.interfce->type; + deallocator.segnames[deallocator.interfce->getType()] = deallocator.interfce->type; #endif deallocator.interfce->listAllDeallocatable(&deallocator, free_unless_used); delete deallocator.interfce; |