commit 26c867a2be47d8d3abb78089c719055d2afbb3ee
Author: Willem Jan Palenstijn <wjp@usecode.org>
Date:   Fri May 13 08:44:40 2011 +0200

    Add some GC debugging code

diff --git a/engines/sci/engine/gc.cpp b/engines/sci/engine/gc.cpp
index b40677d..f1e0fca 100644
--- a/engines/sci/engine/gc.cpp
+++ b/engines/sci/engine/gc.cpp
@@ -46,11 +46,11 @@ const char *segmentTypeNames[] = {
 };
 #endif
 
-void WorklistManager::push(reg_t reg) {
+void WorklistManager::push(reg_t reg, const Common::String& reason) {
 	if (!reg.segment) // No numbers
 		return;
 
-	debugC(kDebugLevelGC, "[GC] Adding %04x:%04x", PRINT_REG(reg));
+	debugC(kDebugLevelGC, "[GC] Adding %04x:%04x (%s)", PRINT_REG(reg), reason.c_str());
 
 	if (_map.contains(reg))
 		return; // already dealt with it
@@ -59,9 +59,9 @@ void WorklistManager::push(reg_t reg) {
 	_worklist.push_back(reg);
 }
 
-void WorklistManager::pushArray(const Common::Array<reg_t> &tmp) {
+void WorklistManager::pushArray(const Common::Array<reg_t> &tmp, const Common::String& reason) {
 	for (Common::Array<reg_t>::const_iterator it = tmp.begin(); it != tmp.end(); ++it)
-		push(*it);
+		push(*it, reason);
 }
 
 static AddrSet *normalizeAddresses(SegManager *segMan, const AddrSet &nonnormal_map) {
@@ -94,9 +94,13 @@ static void processWorkList(SegManager *segMan, WorklistManager &wm, const Commo
 			// root of the problem lies elsewhere. These shouldn't be in the
 			// stack at all (unless these really are script bugs, in which case
 			// we should just keep the sanity check).
-			if (reg.segment < heap.size() && heap[reg.segment] && heap[reg.segment]->isValidOffset(reg.offset)) {
+			if (reg.segment < heap.size() && heap[reg.segment] && !heap[reg.segment]->isValidOffset(reg.offset)) {
+				warning("[GC] Invalid offset %04x:%04x ", PRINT_REG(reg));
+			}
+			if (reg.segment < heap.size() && heap[reg.segment]) { // && heap[reg.segment]->isValidOffset(reg.offset)) {
 				// Valid heap object? Find its outgoing references!
-				wm.pushArray(heap[reg.segment]->listAllOutgoingReferences(reg));
+				Common::String reason = Common::String::format("Outgoing ref from %04x:%04x", PRINT_REG(reg));
+				wm.pushArray(heap[reg.segment]->listAllOutgoingReferences(reg), reason.c_str());
 			}
 		}
 	}
@@ -108,8 +112,8 @@ AddrSet *findAllActiveReferences(EngineState *s) {
 	WorklistManager wm;
 
 	// Initialize registers
-	wm.push(s->r_acc);
-	wm.push(s->r_prev);
+	wm.push(s->r_acc, "r_acc");
+	wm.push(s->r_prev, "r_prev");
 
 	// Initialize value stack
 	// We do this one by hand since the stack doesn't know the current execution stack
@@ -123,8 +127,10 @@ AddrSet *findAllActiveReferences(EngineState *s) {
 
 	const StackPtr sp = iter->sp;
 
-	for (reg_t *pos = s->stack_base; pos < sp; pos++)
-		wm.push(*pos);
+	for (reg_t *pos = s->stack_base; pos < sp; pos++) {
+		Common::String reason = Common::String::format("On stack (offset %02lX)", pos - s->stack_base);
+		wm.push(*pos, reason.c_str());
+	}
 
 	debugC(kDebugLevelGC, "[GC] -- Finished adding value stack");
 
@@ -134,10 +140,10 @@ AddrSet *findAllActiveReferences(EngineState *s) {
 		const ExecStack &es = *iter;
 
 		if (es.type != EXEC_STACK_TYPE_KERNEL) {
-			wm.push(es.objp);
-			wm.push(es.sendp);
+			wm.push(es.objp, "objp on exec stack");
+			wm.push(es.sendp, "sendp on exec stack");
 			if (es.type == EXEC_STACK_TYPE_VARSELECTOR)
-				wm.push(*(es.getVarPointer(s->_segMan)));
+				wm.push(*(es.getVarPointer(s->_segMan)), "varselector on exec stack");
 		}
 	}
 
@@ -152,7 +158,8 @@ AddrSet *findAllActiveReferences(EngineState *s) {
 			Script *script = (Script *)heap[i];
 
 			if (script->getLockers()) { // Explicitly loaded?
-				wm.pushArray(script->listObjectReferences());
+				Common::String reason = Common::String::format("reference from script %d", script->getScriptNumber());
+				wm.pushArray(script->listObjectReferences(), reason.c_str());
 			}
 		}
 	}
diff --git a/engines/sci/engine/gc.h b/engines/sci/engine/gc.h
index 97aa651..952ec48 100644
--- a/engines/sci/engine/gc.h
+++ b/engines/sci/engine/gc.h
@@ -59,8 +59,8 @@ struct WorklistManager {
 	Common::Array<reg_t> _worklist;
 	AddrSet _map;	// used for 2 contains() calls, inside push() and run_gc()
 
-	void push(reg_t reg);
-	void pushArray(const Common::Array<reg_t> &tmp);
+	void push(reg_t reg, const Common::String& reason);
+	void pushArray(const Common::Array<reg_t> &tmp, const Common::String& reason);
 };
 
 
diff --git a/engines/sci/graphics/ports.cpp b/engines/sci/graphics/ports.cpp
index 9412976..16b3554 100644
--- a/engines/sci/graphics/ports.cpp
+++ b/engines/sci/graphics/ports.cpp
@@ -710,8 +710,8 @@ void GfxPorts::processEngineHunkList(WorklistManager &wm) {
 	for (PortList::const_iterator it = _windowList.begin(); it != _windowList.end(); ++it) {
 		if ((*it)->isWindow()) {
 			Window *wnd = ((Window *)*it);
-			wm.push(wnd->hSaved1);
-			wm.push(wnd->hSaved2);
+			wm.push(wnd->hSaved1, "hSaved1 from window");
+			wm.push(wnd->hSaved2, "hSaved2 from window");
 		}
 	}
 }
