aboutsummaryrefslogtreecommitdiff
path: root/engines/sci/engine
diff options
context:
space:
mode:
authorMax Horn2010-06-28 11:22:41 +0000
committerMax Horn2010-06-28 11:22:41 +0000
commit31b29027144e3a76ab6e8c71a0014ca6121218c0 (patch)
tree722fd79896f1063fbdab7f336e9913dd9e2170a3 /engines/sci/engine
parent30218a2c324bc67f724100051ab9884a351928fb (diff)
downloadscummvm-rg350-31b29027144e3a76ab6e8c71a0014ca6121218c0.tar.gz
scummvm-rg350-31b29027144e3a76ab6e8c71a0014ca6121218c0.tar.bz2
scummvm-rg350-31b29027144e3a76ab6e8c71a0014ca6121218c0.zip
SCI: Revise GC interface: use Common::Array<reg_t> instead of callbacks
This means a little bit more overhead but makes the code much more readable and understandable. svn-id: r50429
Diffstat (limited to 'engines/sci/engine')
-rw-r--r--engines/sci/engine/gc.cpp35
-rw-r--r--engines/sci/engine/script.h6
-rw-r--r--engines/sci/engine/segment.cpp89
-rw-r--r--engines/sci/engine/segment.h35
4 files changed, 101 insertions, 64 deletions
diff --git a/engines/sci/engine/gc.cpp b/engines/sci/engine/gc.cpp
index c2f1c15776..59f62c8996 100644
--- a/engines/sci/engine/gc.cpp
+++ b/engines/sci/engine/gc.cpp
@@ -46,6 +46,11 @@ struct WorklistManager {
_map.setVal(reg, true);
_worklist.push_back(reg);
}
+
+ void push(const Common::Array<reg_t> &tmp) {
+ for (Common::Array<reg_t>::const_iterator it = tmp.begin(); it != tmp.end(); ++it)
+ push(*it);
+ }
};
static reg_t_hash_map *normalise_hashmap_ptrs(SegManager *segMan, reg_t_hash_map &nonnormal_map) {
@@ -65,11 +70,6 @@ static reg_t_hash_map *normalise_hashmap_ptrs(SegManager *segMan, reg_t_hash_map
}
-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 *segMan = s->_segMan;
reg_t_hash_map *normal_map = NULL;
@@ -125,15 +125,7 @@ reg_t_hash_map *find_all_used_references(EngineState *s) {
Script *script = (Script *)segMan->_heap[i];
if (script->getLockers()) { // Explicitly loaded?
- // Locals, if present
- wm.push(make_reg(script->_localsSegment, 0));
-
- // All objects (may be classes, may be indirectly reachable)
- ObjMap::iterator it;
- const ObjMap::iterator end = script->_objects.end();
- for (it = script->_objects.begin(); it != end; ++it) {
- wm.push(it->_value.getPos());
- }
+ wm.push(script->listObjectReferences());
}
}
@@ -146,8 +138,10 @@ reg_t_hash_map *find_all_used_references(EngineState *s) {
wm._worklist.pop_back();
if (reg.segment != stack_seg) { // No need to repeat this one
debugC(2, kDebugLevelGC, "[GC] Checking %04x:%04x", PRINT_REG(reg));
- if (reg.segment < segMan->_heap.size() && segMan->_heap[reg.segment])
- segMan->_heap[reg.segment]->listAllOutgoingReferences(reg, &wm, add_outgoing_refs);
+ if (reg.segment < segMan->_heap.size() && segMan->_heap[reg.segment]) {
+ // Valid heap object? Find its outgoing references!
+ wm.push(segMan->_heap[reg.segment]->listAllOutgoingReferences(reg));
+ }
}
}
@@ -167,8 +161,7 @@ struct deallocator_t {
reg_t_hash_map *use_map;
};
-void free_unless_used(void *refcon, reg_t addr) {
- deallocator_t *deallocator = (deallocator_t *)refcon;
+static void free_unless_used(deallocator_t *deallocator, reg_t addr) {
reg_t_hash_map *use_map = deallocator->use_map;
if (!use_map->contains(addr)) {
@@ -201,7 +194,11 @@ void run_gc(EngineState *s) {
#ifdef DEBUG_GC
deallocator.segnames[deallocator.mobj->getType()] = deallocator.mobj->type; // FIXME: add a segment "name"
#endif
- deallocator.mobj->listAllDeallocatable(seg_nr, &deallocator, free_unless_used);
+ const Common::Array<reg_t> tmp = deallocator.mobj->listAllDeallocatable(seg_nr);
+ for (Common::Array<reg_t>::const_iterator it = tmp.begin(); it != tmp.end(); ++it) {
+ free_unless_used(&deallocator, *it);
+ }
+
}
}
diff --git a/engines/sci/engine/script.h b/engines/sci/engine/script.h
index aab073f3a1..490a7a81a3 100644
--- a/engines/sci/engine/script.h
+++ b/engines/sci/engine/script.h
@@ -104,8 +104,10 @@ public:
virtual SegmentRef dereference(reg_t pointer);
virtual reg_t findCanonicAddress(SegManager *segMan, reg_t sub_addr) const;
virtual void freeAtAddress(SegManager *segMan, reg_t sub_addr);
- virtual void listAllDeallocatable(SegmentId segId, void *param, NoteCallback note) const;
- virtual void listAllOutgoingReferences(reg_t object, void *param, NoteCallback note) const;
+ virtual Common::Array<reg_t> listAllDeallocatable(SegmentId segId) const;
+ virtual Common::Array<reg_t> listAllOutgoingReferences(reg_t object) const;
+
+ Common::Array<reg_t> listObjectReferences() const;
virtual void saveLoadWithSerializer(Common::Serializer &ser);
diff --git a/engines/sci/engine/segment.cpp b/engines/sci/engine/segment.cpp
index 2bbedf2dcf..f8a941fa7a 100644
--- a/engines/sci/engine/segment.cpp
+++ b/engines/sci/engine/segment.cpp
@@ -218,20 +218,22 @@ void Script::freeAtAddress(SegManager *segMan, reg_t addr) {
segMan->deallocateScript(_nr);
}
-void Script::listAllDeallocatable(SegmentId segId, void *param, NoteCallback note) const {
- (*note)(param, make_reg(segId, 0));
+Common::Array<reg_t> Script::listAllDeallocatable(SegmentId segId) const {
+ const reg_t r = make_reg(segId, 0);
+ return Common::Array<reg_t>(&r, 1);
}
-void Script::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback note) const {
+Common::Array<reg_t> Script::listAllOutgoingReferences(reg_t addr) const {
+ Common::Array<reg_t> tmp;
if (addr.offset <= _bufSize && addr.offset >= -SCRIPT_OBJECT_MAGIC_OFFSET && RAW_IS_OBJECT(_buf + addr.offset)) {
const Object *obj = getObject(addr.offset);
if (obj) {
// Note all local variables, if we have a local variable environment
if (_localsSegment)
- (*note)(param, make_reg(_localsSegment, 0));
+ tmp.push_back(make_reg(_localsSegment, 0));
for (uint i = 0; i < obj->getVarCount(); i++)
- (*note)(param, obj->getVariable(i));
+ tmp.push_back(obj->getVariable(i));
} else {
error("Request for outgoing script-object reference at %04x:%04x failed", PRINT_REG(addr));
}
@@ -239,12 +241,30 @@ void Script::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback not
/* warning("Unexpected request for outgoing script-object references at %04x:%04x", PRINT_REG(addr));*/
/* Happens e.g. when we're looking into strings */
}
+ return tmp;
}
+Common::Array<reg_t> Script::listObjectReferences() const {
+ Common::Array<reg_t> tmp;
+
+ // Locals, if present
+ if (_localsSegment)
+ tmp.push_back(make_reg(_localsSegment, 0));
+
+ // All objects (may be classes, may be indirectly reachable)
+ ObjMap::iterator it;
+ const ObjMap::iterator end = _objects.end();
+ for (it = _objects.begin(); it != end; ++it) {
+ tmp.push_back(it->_value.getPos());
+ }
+
+ return tmp;
+}
//-------------------- clones --------------------
-void CloneTable::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback note) const {
+Common::Array<reg_t> CloneTable::listAllOutgoingReferences(reg_t addr) const {
+ Common::Array<reg_t> tmp;
// assert(addr.segment == _segId);
if (!isValidEntry(addr.offset)) {
@@ -255,11 +275,13 @@ void CloneTable::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback
// Emit all member variables (including references to the 'super' delegate)
for (uint i = 0; i < clone->getVarCount(); i++)
- (*note)(param, clone->getVariable(i));
+ tmp.push_back(clone->getVariable(i));
// Note that this also includes the 'base' object, which is part of the script and therefore also emits the locals.
- (*note)(param, clone->getPos());
+ tmp.push_back(clone->getPos());
//debugC(2, kDebugLevelGC, "[GC] Reporting clone-pos %04x:%04x", PRINT_REG(clone->pos));
+
+ return tmp;
}
void CloneTable::freeAtAddress(SegManager *segMan, reg_t addr) {
@@ -293,11 +315,14 @@ reg_t LocalVariables::findCanonicAddress(SegManager *segMan, reg_t addr) const {
return make_reg(owner_seg, 0);
}
-void LocalVariables::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback note) const {
+Common::Array<reg_t> LocalVariables::listAllOutgoingReferences(reg_t addr) const {
+ Common::Array<reg_t> tmp;
// assert(addr.segment == _segId);
for (uint i = 0; i < _locals.size(); i++)
- (*note)(param, _locals[i]);
+ tmp.push_back(_locals[i]);
+
+ return tmp;
}
@@ -307,11 +332,14 @@ reg_t DataStack::findCanonicAddress(SegManager *segMan, reg_t addr) const {
return addr;
}
-void DataStack::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback note) const {
+Common::Array<reg_t> DataStack::listAllOutgoingReferences(reg_t object) const {
+ Common::Array<reg_t> tmp;
fprintf(stderr, "Emitting %d stack entries\n", _capacity);
for (int i = 0; i < _capacity; i++)
- (*note)(param, _entries[i]);
+ tmp.push_back(_entries[i]);
fprintf(stderr, "DONE");
+
+ return tmp;
}
@@ -320,18 +348,20 @@ void ListTable::freeAtAddress(SegManager *segMan, reg_t sub_addr) {
freeEntry(sub_addr.offset);
}
-void ListTable::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback note) const {
+Common::Array<reg_t> ListTable::listAllOutgoingReferences(reg_t addr) const {
+ Common::Array<reg_t> tmp;
if (!isValidEntry(addr.offset)) {
error("Invalid list referenced for outgoing references: %04x:%04x", PRINT_REG(addr));
- return;
}
const List *list = &(_table[addr.offset]);
- note(param, list->first);
- note(param, list->last);
+ tmp.push_back(list->first);
+ tmp.push_back(list->last);
// We could probably get away with just one of them, but
// let's be conservative here.
+
+ return tmp;
}
@@ -340,19 +370,21 @@ void NodeTable::freeAtAddress(SegManager *segMan, reg_t sub_addr) {
freeEntry(sub_addr.offset);
}
-void NodeTable::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback note) const {
+Common::Array<reg_t> NodeTable::listAllOutgoingReferences(reg_t addr) const {
+ Common::Array<reg_t> tmp;
if (!isValidEntry(addr.offset)) {
error("Invalid node referenced for outgoing references: %04x:%04x", PRINT_REG(addr));
- return;
}
const Node *node = &(_table[addr.offset]);
// We need all four here. Can't just stick with 'pred' OR 'succ' because node operations allow us
// to walk around from any given node
- note(param, node->pred);
- note(param, node->succ);
- note(param, node->key);
- note(param, node->value);
+ tmp.push_back(node->pred);
+ tmp.push_back(node->succ);
+ tmp.push_back(node->key);
+ tmp.push_back(node->value);
+
+ return tmp;
}
@@ -473,8 +505,9 @@ reg_t DynMem::findCanonicAddress(SegManager *segMan, reg_t addr) const {
return addr;
}
-void DynMem::listAllDeallocatable(SegmentId segId, void *param, NoteCallback note) const {
- (*note)(param, make_reg(segId, 0));
+Common::Array<reg_t> DynMem::listAllDeallocatable(SegmentId segId) const {
+ const reg_t r = make_reg(segId, 0);
+ return Common::Array<reg_t>(&r, 1);
}
#ifdef ENABLE_SCI32
@@ -492,10 +525,10 @@ void ArrayTable::freeAtAddress(SegManager *segMan, reg_t sub_addr) {
freeEntry(sub_addr.offset);
}
-void ArrayTable::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback note) const {
+Common::Array<reg_t> ArrayTable::listAllOutgoingReferences(reg_t addr) const {
+ Common::Array<reg_t> tmp;
if (!isValidEntry(addr.offset)) {
error("Invalid array referenced for outgoing references: %04x:%04x", PRINT_REG(addr));
- return;
}
const SciArray<reg_t> *array = &(_table[addr.offset]);
@@ -503,8 +536,10 @@ void ArrayTable::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback
for (uint32 i = 0; i < array->getSize(); i++) {
reg_t value = array->getValue(i);
if (value.segment != 0)
- note(param, value);
+ tmp.push_back(value);
}
+
+ return tmp;
}
Common::String SciString::toString() const {
diff --git a/engines/sci/engine/segment.h b/engines/sci/engine/segment.h
index b621e53412..c12efecf1c 100644
--- a/engines/sci/engine/segment.h
+++ b/engines/sci/engine/segment.h
@@ -80,8 +80,6 @@ enum SegmentType {
struct SegmentObj : public Common::Serializable {
SegmentType _type;
- typedef void (*NoteCallback)(void *param, reg_t addr); // FIXME: Bad choice of name
-
public:
static SegmentObj *createSegmentObj(SegmentType type);
@@ -125,16 +123,19 @@ public:
* @param note Invoked for each address on which free_at_address() makes sense
* @param param parameter passed to 'note'
*/
- virtual void listAllDeallocatable(SegmentId segId, void *param, NoteCallback note) const {}
+ virtual Common::Array<reg_t> listAllDeallocatable(SegmentId segId) const {
+ return Common::Array<reg_t>();
+ }
/**
* Iterates over all references reachable from the specified object.
- * @param object object (within the current segment) to analyse
- * @param param parameter passed to 'note'
- * @param note Invoked for each outgoing reference within the object
+ * @param object object (within the current segment) to analyse
+ * @return refs a list of outgoing references within the object
* Note: This function may also choose to report numbers (segment 0) as adresses
*/
- virtual void listAllOutgoingReferences(reg_t object, void *param, NoteCallback note) const {}
+ virtual Common::Array<reg_t> listAllOutgoingReferences(reg_t object) const {
+ return Common::Array<reg_t>();
+ }
};
@@ -195,7 +196,7 @@ public:
virtual bool isValidOffset(uint16 offset) const;
virtual SegmentRef dereference(reg_t pointer);
virtual reg_t findCanonicAddress(SegManager *segMan, reg_t sub_addr) const;
- virtual void listAllOutgoingReferences(reg_t object, void *param, NoteCallback note) const;
+ virtual Common::Array<reg_t> listAllOutgoingReferences(reg_t object) const;
virtual void saveLoadWithSerializer(Common::Serializer &ser);
};
@@ -349,7 +350,7 @@ public:
virtual bool isValidOffset(uint16 offset) const;
virtual SegmentRef dereference(reg_t pointer);
virtual reg_t findCanonicAddress(SegManager *segMan, reg_t sub_addr) const;
- virtual void listAllOutgoingReferences(reg_t object, void *param, NoteCallback note) const;
+ virtual Common::Array<reg_t> listAllOutgoingReferences(reg_t object) const;
virtual void saveLoadWithSerializer(Common::Serializer &ser);
};
@@ -437,10 +438,12 @@ public:
entries_used--;
}
- virtual void listAllDeallocatable(SegmentId segId, void *param, NoteCallback note) const {
+ virtual Common::Array<reg_t> listAllDeallocatable(SegmentId segId) const {
+ Common::Array<reg_t> tmp;
for (uint i = 0; i < _table.size(); i++)
if (isValidEntry(i))
- (*note)(param, make_reg(segId, i));
+ tmp.push_back(make_reg(segId, i));
+ return tmp;
}
};
@@ -450,7 +453,7 @@ struct CloneTable : public Table<Clone> {
CloneTable() : Table<Clone>(SEG_TYPE_CLONES) {}
virtual void freeAtAddress(SegManager *segMan, reg_t sub_addr);
- virtual void listAllOutgoingReferences(reg_t object, void *param, NoteCallback note) const;
+ virtual Common::Array<reg_t> listAllOutgoingReferences(reg_t object) const;
virtual void saveLoadWithSerializer(Common::Serializer &ser);
};
@@ -461,7 +464,7 @@ struct NodeTable : public Table<Node> {
NodeTable() : Table<Node>(SEG_TYPE_NODES) {}
virtual void freeAtAddress(SegManager *segMan, reg_t sub_addr);
- virtual void listAllOutgoingReferences(reg_t object, void *param, NoteCallback note) const;
+ virtual Common::Array<reg_t> listAllOutgoingReferences(reg_t object) const;
virtual void saveLoadWithSerializer(Common::Serializer &ser);
};
@@ -472,7 +475,7 @@ struct ListTable : public Table<List> {
ListTable() : Table<List>(SEG_TYPE_LISTS) {}
virtual void freeAtAddress(SegManager *segMan, reg_t sub_addr);
- virtual void listAllOutgoingReferences(reg_t object, void *param, NoteCallback note) const;
+ virtual Common::Array<reg_t> listAllOutgoingReferences(reg_t object) const;
virtual void saveLoadWithSerializer(Common::Serializer &ser);
};
@@ -511,7 +514,7 @@ public:
virtual bool isValidOffset(uint16 offset) const;
virtual SegmentRef dereference(reg_t pointer);
virtual reg_t findCanonicAddress(SegManager *segMan, reg_t sub_addr) const;
- virtual void listAllDeallocatable(SegmentId segId, void *param, NoteCallback note) const;
+ virtual Common::Array<reg_t> listAllDeallocatable(SegmentId segId) const;
virtual void saveLoadWithSerializer(Common::Serializer &ser);
};
@@ -645,7 +648,7 @@ struct ArrayTable : public Table<SciArray<reg_t> > {
ArrayTable() : Table<SciArray<reg_t> >(SEG_TYPE_ARRAY) {}
virtual void freeAtAddress(SegManager *segMan, reg_t sub_addr);
- virtual void listAllOutgoingReferences(reg_t object, void *param, NoteCallback note) const;
+ virtual Common::Array<reg_t> listAllOutgoingReferences(reg_t object) const;
void saveLoadWithSerializer(Common::Serializer &ser);
SegmentRef dereference(reg_t pointer);