[Scummvm-cvs-logs] SF.net SVN: scummvm:[41166] scummvm/trunk/engines/sci

fingolfin at users.sourceforge.net fingolfin at users.sourceforge.net
Thu Jun 4 13:45:17 CEST 2009


Revision: 41166
          http://scummvm.svn.sourceforge.net/scummvm/?rev=41166&view=rev
Author:   fingolfin
Date:     2009-06-04 11:45:17 +0000 (Thu, 04 Jun 2009)

Log Message:
-----------
SCI: Moved MemObject code into a separate source file

Modified Paths:
--------------
    scummvm/trunk/engines/sci/console.h
    scummvm/trunk/engines/sci/engine/seg_manager.cpp
    scummvm/trunk/engines/sci/engine/seg_manager.h
    scummvm/trunk/engines/sci/engine/vm.h
    scummvm/trunk/engines/sci/module.mk

Added Paths:
-----------
    scummvm/trunk/engines/sci/engine/memobj.cpp
    scummvm/trunk/engines/sci/engine/memobj.h

Modified: scummvm/trunk/engines/sci/console.h
===================================================================
--- scummvm/trunk/engines/sci/console.h	2009-06-04 11:44:55 UTC (rev 41165)
+++ scummvm/trunk/engines/sci/console.h	2009-06-04 11:45:17 UTC (rev 41166)
@@ -33,6 +33,7 @@
 namespace Sci {
 
 class SciEngine;
+struct List;
 
 // Refer to the "addresses" command on how to pass address parameters
 int parse_reg_t(EngineState *s, const char *str, reg_t *dest);

Added: scummvm/trunk/engines/sci/engine/memobj.cpp
===================================================================
--- scummvm/trunk/engines/sci/engine/memobj.cpp	                        (rev 0)
+++ scummvm/trunk/engines/sci/engine/memobj.cpp	2009-06-04 11:45:17 UTC (rev 41166)
@@ -0,0 +1,399 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/endian.h"
+
+#include "sci/sci.h"
+#include "sci/engine/memobj.h"
+#include "sci/engine/intmap.h"
+#include "sci/engine/seg_manager.h"
+#include "sci/engine/state.h"
+#include "sci/tools.h"
+
+namespace Sci {
+
+MemObject *MemObject::createMemObject(MemObjectType type) {
+	MemObject *mem = 0;
+	switch (type) {
+	case MEM_OBJ_SCRIPT:
+		mem = new Script();
+		break;
+	case MEM_OBJ_CLONES:
+		mem = new CloneTable();
+		break;
+	case MEM_OBJ_LOCALS:
+		mem = new LocalVariables();
+		break;
+	case MEM_OBJ_SYS_STRINGS:
+		mem = new SystemStrings();
+		break;
+	case MEM_OBJ_STACK:
+		mem = new DataStack();
+		break;
+	case MEM_OBJ_HUNK:
+		mem = new HunkTable();
+		break;
+	case MEM_OBJ_STRING_FRAG:
+		mem = new StringFrag();
+		break;
+	case MEM_OBJ_LISTS:
+		mem = new ListTable();
+		break;
+	case MEM_OBJ_NODES:
+		mem = new NodeTable();
+		break;
+	case MEM_OBJ_DYNMEM:
+		mem = new DynMem();
+		break;
+	default:
+		error("Unknown MemObject type %d", type);
+		break;
+	}
+
+	assert(mem);
+	mem->_type = type;
+	return mem;
+}
+
+void Script::freeScript() {
+	free(buf);
+	buf = NULL;
+	buf_size = 0;
+
+	_objects.clear();
+
+	delete obj_indices;
+	obj_indices = 0;
+	_codeBlocks.clear();
+}
+
+// memory operations
+
+void Script::mcpyInOut(int dst, const void *src, size_t n) {
+	if (buf) {
+		assert(dst + n <= buf_size);
+		memcpy(buf + dst, src, n);
+	}
+}
+
+int16 Script::getHeap(uint16 offset) const {
+	assert(offset + 1 < (int)buf_size);
+	return READ_LE_UINT16(buf + offset);
+//	return (buf[offset] | (buf[offset+1]) << 8);
+}
+
+void Script::incrementLockers() {
+	lockers++;
+}
+
+void Script::decrementLockers() {
+	if (lockers > 0)
+		lockers--;
+}
+
+int Script::getLockers() const {
+	return lockers;
+}
+
+void Script::setLockers(int lockers_) {
+	lockers = lockers_;
+}
+
+void Script::setExportTableOffset(int offset) {
+	if (offset) {
+		export_table = (uint16 *)(buf + offset + 2);
+		exports_nr = READ_LE_UINT16((byte *)(export_table - 1));
+	} else {
+		export_table = NULL;
+		exports_nr = 0;
+	}
+}
+
+void Script::setSynonymsOffset(int offset) {
+	synonyms = buf + offset;
+}
+
+byte *Script::getSynonyms() const {
+	return synonyms;
+}
+
+void Script::setSynonymsNr(int n) {
+	synonyms_nr = n;
+}
+
+int Script::getSynonymsNr() const {
+	return synonyms_nr;
+}
+
+byte *MemObject::dereference(reg_t pointer, int *size) {
+	error("Error: Trying to dereference pointer %04x:%04x to inappropriate segment",
+		          PRINT_REG(pointer));
+	return NULL;
+}
+
+byte *Script::dereference(reg_t pointer, int *size) {
+	if (pointer.offset > buf_size) {
+		sciprintf("Error: Attempt to dereference invalid pointer %04x:%04x into script segment (script size=%d)\n",
+				  PRINT_REG(pointer), (uint)buf_size);
+		return NULL;
+	}
+	if (size)
+		*size = buf_size - pointer.offset;
+	return (byte *)(buf + pointer.offset);
+}
+
+byte *LocalVariables::dereference(reg_t pointer, int *size) {
+	// FIXME: The following doesn't seem to be endian safe.
+	// To fix this, we'd have to always treat the reg_t
+	// values stored here as in the little endian format.
+	int count = _locals.size() * sizeof(reg_t);
+	byte *base = (byte *)&_locals[0];
+
+	if (size)
+		*size = count;
+
+	return base + pointer.offset;
+}
+
+byte *DataStack::dereference(reg_t pointer, int *size) {
+	int count = nr * sizeof(reg_t);
+	byte *base = (byte *)entries;
+
+	if (size)
+		*size = count;
+
+	return base + pointer.offset;
+}
+
+byte *DynMem::dereference(reg_t pointer, int *size) {
+	int count = _size;
+	byte *base = (byte *)_buf;
+
+	if (size)
+		*size = count;
+
+	return base + pointer.offset;
+}
+
+byte *SystemStrings::dereference(reg_t pointer, int *size) {
+	if (size)
+		*size = strings[pointer.offset].max_size;
+	if (pointer.offset < SYS_STRINGS_MAX && strings[pointer.offset].name)
+		return (byte *)(strings[pointer.offset].value);
+
+	// This occurs in KQ5CD when interacting with certain objects
+	warning("Attempt to dereference invalid pointer %04x:%04x", PRINT_REG(pointer));
+	return NULL;
+}
+
+
+//-------------------- script --------------------
+reg_t Script::findCanonicAddress(SegManager *segmgr, reg_t addr) {
+	addr.offset = 0;
+	return addr;
+}
+
+void Script::freeAtAddress(SegManager *segmgr, reg_t addr) {
+	/*
+		sciprintf("[GC] Freeing script %04x:%04x\n", PRINT_REG(addr));
+		if (locals_segment)
+			sciprintf("[GC] Freeing locals %04x:0000\n", locals_segment);
+	*/
+
+	if (_markedAsDeleted)
+		segmgr->deallocateScript(nr);
+}
+
+void Script::listAllDeallocatable(SegmentId segId, void *param, NoteCallback note) {
+	(*note)(param, make_reg(segId, 0));
+}
+
+void Script::listAllOutgoingReferences(EngineState *s, reg_t addr, void *param, NoteCallback note) {
+	Script *script = this;
+
+	if (addr.offset <= script->buf_size && addr.offset >= -SCRIPT_OBJECT_MAGIC_OFFSET && RAW_IS_OBJECT(script->buf + addr.offset)) {
+		int idx = RAW_GET_CLASS_INDEX(script, addr);
+		if (idx >= 0 && (uint)idx < script->_objects.size()) {
+			// Note all local variables, if we have a local variable environment
+			if (script->locals_segment)
+				(*note)(param, make_reg(script->locals_segment, 0));
+
+			Object &obj = script->_objects[idx];
+			for (uint i = 0; i < obj._variables.size(); i++)
+				(*note)(param, obj._variables[i]);
+		} else {
+			warning("Request for outgoing script-object reference at %04x:%04x yielded invalid index %d", PRINT_REG(addr), idx);
+		}
+	} else {
+		/*		warning("Unexpected request for outgoing script-object references at %04x:%04x", PRINT_REG(addr));*/
+		/* Happens e.g. when we're looking into strings */
+	}
+}
+
+
+//-------------------- clones --------------------
+
+template<typename T>
+void Table<T>::listAllDeallocatable(SegmentId segId, void *param, NoteCallback note) {
+	for (uint i = 0; i < _table.size(); i++)
+		if (isValidEntry(i))
+			(*note)(param, make_reg(segId, i));
+}
+
+void CloneTable::listAllOutgoingReferences(EngineState *s, reg_t addr, void *param, NoteCallback note) {
+	CloneTable *clone_table = this;
+	Clone *clone;
+
+//	assert(addr.segment == _segId);
+
+	if (!clone_table->isValidEntry(addr.offset)) {
+		warning("Unexpected request for outgoing references from clone at %04x:%04x", PRINT_REG(addr));
+//		BREAKPOINT();
+		return;
+	}
+
+	clone = &(clone_table->_table[addr.offset]);
+
+	// Emit all member variables (including references to the 'super' delegate)
+	for (uint i = 0; i < clone->_variables.size(); i++)
+		(*note)(param, clone->_variables[i]);
+
+	// Note that this also includes the 'base' object, which is part of the script and therefore also emits the locals.
+	(*note)(param, clone->pos);
+	//sciprintf("[GC] Reporting clone-pos %04x:%04x\n", PRINT_REG(clone->pos));
+}
+
+void CloneTable::freeAtAddress(SegManager *segmgr, reg_t addr) {
+	CloneTable *clone_table = this;
+	Object *victim_obj;
+
+//	assert(addr.segment == _segId);
+
+	victim_obj = &(clone_table->_table[addr.offset]);
+
+#ifdef GC_DEBUG
+	if (!(victim_obj->flags & OBJECT_FLAG_FREED))
+		sciprintf("[GC] Warning: Clone %04x:%04x not reachable and not freed (freeing now)\n", PRINT_REG(addr));
+#ifdef GC_DEBUG_VERBOSE
+	else
+		sciprintf("[GC-DEBUG] Clone %04x:%04x: Freeing\n", PRINT_REG(addr));
+#endif
+#endif
+	/*
+		sciprintf("[GC] Clone %04x:%04x: Freeing\n", PRINT_REG(addr));
+		sciprintf("[GC] Clone had pos %04x:%04x\n", PRINT_REG(victim_obj->pos));
+	*/
+	clone_table->freeEntry(addr.offset);
+}
+
+
+//-------------------- locals --------------------
+reg_t LocalVariables::findCanonicAddress(SegManager *segmgr, reg_t addr) {
+	// Reference the owning script
+	SegmentId owner_seg = segmgr->segGet(script_id);
+
+	assert(owner_seg >= 0);
+
+	return make_reg(owner_seg, 0);
+}
+
+void LocalVariables::listAllOutgoingReferences(EngineState *s, reg_t addr, void *param, NoteCallback note) {
+//	assert(addr.segment == _segId);
+
+	for (uint i = 0; i < _locals.size(); i++)
+		(*note)(param, _locals[i]);
+}
+
+
+//-------------------- stack --------------------
+reg_t DataStack::findCanonicAddress(SegManager *segmgr, reg_t addr) {
+	addr.offset = 0;
+	return addr;
+}
+
+void DataStack::listAllOutgoingReferences(EngineState *s, reg_t addr, void *param, NoteCallback note) {
+	fprintf(stderr, "Emitting %d stack entries\n", nr);
+	for (int i = 0; i < nr; i++)
+		(*note)(param, entries[i]);
+	fprintf(stderr, "DONE");
+}
+
+
+//-------------------- lists --------------------
+void ListTable::freeAtAddress(SegManager *segmgr, reg_t sub_addr) {
+	freeEntry(sub_addr.offset);
+}
+
+void ListTable::listAllOutgoingReferences(EngineState *s, reg_t addr, void *param, NoteCallback note) {
+	if (!isValidEntry(addr.offset)) {
+		warning("Invalid list referenced for outgoing references: %04x:%04x", PRINT_REG(addr));
+		return;
+	}
+
+	List *list = &(_table[addr.offset]);
+
+	note(param, list->first);
+	note(param, list->last);
+	// We could probably get away with just one of them, but
+	// let's be conservative here.
+}
+
+
+//-------------------- nodes --------------------
+void NodeTable::freeAtAddress(SegManager *segmgr, reg_t sub_addr) {
+	freeEntry(sub_addr.offset);
+}
+
+void NodeTable::listAllOutgoingReferences(EngineState *s, reg_t addr, void *param, NoteCallback note) {
+	if (!isValidEntry(addr.offset)) {
+		warning("Invalid node referenced for outgoing references: %04x:%04x", PRINT_REG(addr));
+		return;
+	}
+	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);
+}
+
+
+//-------------------- hunk --------------------
+
+//-------------------- dynamic memory --------------------
+
+reg_t DynMem::findCanonicAddress(SegManager *segmgr, reg_t addr) {
+	addr.offset = 0;
+	return addr;
+}
+
+void DynMem::listAllDeallocatable(SegmentId segId, void *param, NoteCallback note) {
+	(*note)(param, make_reg(segId, 0));
+}
+
+
+} // End of namespace Sci


Property changes on: scummvm/trunk/engines/sci/engine/memobj.cpp
___________________________________________________________________
Added: svn:mime-type
   + text/plain
Added: svn:keywords
   + Date Rev Author URL Id
Added: svn:eol-style
   + native

Added: scummvm/trunk/engines/sci/engine/memobj.h
===================================================================
--- scummvm/trunk/engines/sci/engine/memobj.h	                        (rev 0)
+++ scummvm/trunk/engines/sci/engine/memobj.h	2009-06-04 11:45:17 UTC (rev 41166)
@@ -0,0 +1,556 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef SCI_ENGINE_MEMOBJ_H
+#define SCI_ENGINE_MEMOBJ_H
+
+#include "common/serializer.h"
+#include "sci/engine/vm_types.h"	// for reg_t
+
+//#include "common/util.h"
+
+namespace Sci {
+
+enum MemObjectType {
+	MEM_OBJ_INVALID = 0,
+	MEM_OBJ_SCRIPT = 1,
+	MEM_OBJ_CLONES = 2,
+	MEM_OBJ_LOCALS = 3,
+	MEM_OBJ_STACK = 4,
+	MEM_OBJ_SYS_STRINGS = 5,
+	MEM_OBJ_LISTS = 6,
+	MEM_OBJ_NODES = 7,
+	MEM_OBJ_HUNK = 8,
+	MEM_OBJ_DYNMEM = 9,
+	MEM_OBJ_STRING_FRAG = 10,
+
+	MEM_OBJ_MAX // For sanity checking
+};
+
+struct MemObject : public Common::Serializable {
+	MemObjectType _type;
+	int _segmgrId; /**< Internal value used by the seg_manager's hash map */
+
+	typedef void (*NoteCallback)(void *param, reg_t addr);	// FIXME: Bad choice of name
+
+public:
+	static MemObject *createMemObject(MemObjectType type);
+
+public:
+	virtual ~MemObject() {}
+
+	inline MemObjectType getType() const { return _type; }
+	inline int getSegMgrId() const { return _segmgrId; }
+
+	/**
+	 * Dereferences a raw memory pointer.
+	 * @param reg   reference to dereference
+	 * @param size  if not NULL, set to the theoretical maximum size of the referenced data block
+	 * @return              the data block referenced
+	 */
+	virtual byte *dereference(reg_t pointer, int *size);
+
+	/**
+	 * Finds the canonic address associated with sub_reg.
+	 *
+	 * For each valid address a, there exists a canonic address c(a) such that c(a) = c(c(a)).
+	 * This address "governs" a in the sense that deallocating c(a) will deallocate a.
+	 *
+	 * @param sub_addr		base address whose canonic address is to be found
+	 */
+	virtual reg_t findCanonicAddress(SegManager *segmgr, reg_t sub_addr) { return sub_addr; }
+
+	/**
+	 * Deallocates all memory associated with the specified address.
+	 * @param sub_addr		address (within the given segment) to deallocate
+	 */
+	virtual void freeAtAddress(SegManager *segmgr, reg_t sub_addr) {}
+
+	/**
+	 * Iterates over and reports all addresses within the current segment.
+	 * @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) {}
+
+	/**
+	 * 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
+	 * Note: This function may also choose to report numbers (segment 0) as adresses
+	 */
+	virtual void listAllOutgoingReferences(EngineState *s, reg_t object, void *param, NoteCallback note) {}
+};
+
+
+// TODO: Implement the following class
+struct StringFrag : public MemObject {
+	virtual void saveLoadWithSerializer(Common::Serializer &ser);
+};
+
+struct IntMapper;
+
+enum {
+	SYS_STRINGS_MAX = 4,
+
+	SYS_STRING_SAVEDIR = 0,
+	SYS_STRING_PARSER_BASE = 1,
+
+	MAX_PARSER_BASE = 64
+};
+
+struct SystemString {
+	char *name;
+	int max_size;
+	reg_t *value;
+};
+
+struct SystemStrings : public MemObject {
+	SystemString strings[SYS_STRINGS_MAX];
+
+public:
+	SystemStrings() {
+		memset(strings, 0, sizeof(strings));
+	}
+	~SystemStrings() {
+		for (int i = 0; i < SYS_STRINGS_MAX; i++) {
+			SystemString *str = &strings[i];
+			if (str->name) {
+				free(str->name);
+				str->name = NULL;
+
+				free(str->value);
+				str->value = NULL;
+
+				str->max_size = 0;
+			}
+		}
+	}
+
+	virtual byte *dereference(reg_t pointer, int *size);
+
+	virtual void saveLoadWithSerializer(Common::Serializer &ser);
+};
+
+/** This struct is used to buffer the list of send calls in send_selector() */
+struct CallsStruct {
+	union {
+		reg_t func;
+		reg_t *var;
+	} address;
+	StackPtr argp;
+	int argc;
+	Selector selector;
+	StackPtr sp; /**< Stack pointer */
+	int type; /**< Same as ExecStack.type */
+};
+
+struct LocalVariables : public MemObject {
+	int script_id; /**< Script ID this local variable block belongs to */
+	Common::Array<reg_t> _locals;
+
+public:
+	LocalVariables() {
+		script_id = 0;
+	}
+
+	virtual byte *dereference(reg_t pointer, int *size);
+	virtual reg_t findCanonicAddress(SegManager *segmgr, reg_t sub_addr);
+	virtual void listAllOutgoingReferences(EngineState *s, reg_t object, void *param, NoteCallback note);
+
+	virtual void saveLoadWithSerializer(Common::Serializer &ser);
+};
+
+/** Clone has been marked as 'freed' */
+#define OBJECT_FLAG_FREED (0x1 << 0)
+
+struct Object {
+	int flags;
+	reg_t pos; /**< Object offset within its script; for clones, this is their base */
+	int variable_names_nr; /**< Number of variable names, may be less than variables_nr */
+	int methods_nr;
+	byte *base; /**< Points to a buffer all relative references (code, strings) point to */
+	byte *base_obj; /**< base + object offset within base */
+	uint16 *base_method; /**< Pointer to the method selector area for this object */
+	uint16 *base_vars; /**< Pointer to the varselector area for this object */
+	Common::Array<reg_t> _variables;
+};
+
+struct CodeBlock {
+	reg_t pos;
+	int size;
+};
+
+#define VM_OBJECT_GET_VARSELECTOR(obj, i)  \
+	(s->version < SCI_VERSION_1_1 ? \
+	 READ_LE_UINT16(obj->base_obj + obj->_variables.size() * 2 + i*2) : \
+	 *(obj->base_vars + i))
+#define VM_OBJECT_READ_PROPERTY(obj, i) (obj->_variables[i])
+#define VM_OBJECT_GET_FUNCSELECTOR(obj, i) \
+	(s->version < SCI_VERSION_1_1 ? \
+	 READ_LE_UINT16((byte *) (obj->base_method + i)) : \
+	 READ_LE_UINT16((byte *) (obj->base_method + i*2 + 1)))
+#define VM_OBJECT_READ_FUNCTION(obj, i) \
+	(s->version < SCI_VERSION_1_1 ? \
+	 make_reg(obj->pos.segment, \
+		 READ_LE_UINT16((byte *) (obj->base_method \
+				 + obj->methods_nr + 1 \
+				 + i))) : \
+	 make_reg(obj->pos.segment, \
+		 READ_LE_UINT16((byte *) (obj->base_method \
+				 + i * 2 + 2))))
+
+
+
+
+struct Script : public MemObject {
+	int nr; /**< Script number */
+	byte *buf; /**< Static data buffer, or NULL if not used */
+	size_t buf_size;
+	size_t script_size;
+	size_t heap_size;
+
+	byte *synonyms; /**< Synonyms block or 0 if not present*/
+	byte *heap_start; /**< Start of heap if SCI1.1, NULL otherwise */
+	uint16 *export_table; /**< Abs. offset of the export table or 0 if not present */
+
+	IntMapper *obj_indices;
+
+	int exports_nr; /**< Number of entries in the exports table */
+	int synonyms_nr; /**< Number of entries in the synonyms block */
+	int lockers; /**< Number of classes and objects that require this script */
+
+	/**
+	 * Table for objects, contains property variables.
+	 * Indexed by the value stored at SCRIPT_LOCALVARPTR_OFFSET,
+	 * see VM_OBJECT_[GS]ET_INDEX()
+	 */
+	Common::Array<Object> _objects;
+
+	int locals_offset;
+	int locals_segment; /**< The local variable segment */
+	LocalVariables *locals_block;
+
+	Common::Array<CodeBlock> _codeBlocks;
+	int relocated;
+	bool _markedAsDeleted;
+
+public:
+	Script() {
+		nr = 0;
+		buf = NULL;
+		buf_size = 0;
+		script_size = 0;
+		heap_size = 0;
+
+		synonyms = NULL;
+		heap_start = NULL;
+		export_table = NULL;
+
+		obj_indices = NULL;
+
+		locals_offset = 0;
+		locals_segment = 0;
+		locals_block = NULL;
+
+		relocated = 0;
+		_markedAsDeleted = 0;
+	}
+
+	~Script() {
+		freeScript();
+	}
+
+	void freeScript();
+
+	virtual byte *dereference(reg_t pointer, int *size);
+	virtual reg_t findCanonicAddress(SegManager *segmgr, reg_t sub_addr);
+	virtual void freeAtAddress(SegManager *segmgr, reg_t sub_addr);
+	virtual void listAllDeallocatable(SegmentId segId, void *param, NoteCallback note);
+	virtual void listAllOutgoingReferences(EngineState *s, reg_t object, void *param, NoteCallback note);
+
+	virtual void saveLoadWithSerializer(Common::Serializer &ser);
+
+	// script lock operations
+
+	/** Increments the number of lockers of this script by one. */
+	void incrementLockers();
+
+	/** Decrements the number of lockers of this script by one. */
+	void decrementLockers();
+
+	/**
+	 * Retrieves the number of locks held on this script.
+	 * @return the number of locks held on the previously identified script
+	 */
+	int getLockers() const;
+
+	/** Sets the number of locks held on this script. */
+	void setLockers(int lockers);
+
+	/**
+	 * Retrieves a pointer to the synonyms associated with this script
+	 * @return	pointer to the synonyms, in non-parsed format.
+	 */
+	byte *getSynonyms() const;
+
+	/**
+	 * Retrieves the number of synonyms associated with this script.
+	 * @return	the number of synonyms associated with this script
+	 */
+	int getSynonymsNr() const;
+
+
+	/**
+	 * Sets the script-relative offset of the exports table.
+	 * @param offset	script-relative exports table offset
+	 */
+	void setExportTableOffset(int offset);
+
+	/**
+	 * Sets the script-relative offset of the synonyms associated with this script.
+	 * @param offset	script-relative offset of the synonyms block
+	 */
+	void setSynonymsOffset(int offset);
+
+	/**
+	 * Sets the number of synonyms associated with this script,
+	 * @param nr		number of synonyms, as to be stored within the script
+	 */
+	void setSynonymsNr(int nr);
+
+
+	/**
+	 * Copies a byte string into a script's heap representation.
+	 * @param dst	script-relative offset of the destination area
+	 * @param src	pointer to the data source location
+	 * @param n		number of bytes to copy
+	 */
+	void mcpyInOut(int dst, const void *src, size_t n);
+
+
+	/**
+	 * Marks the script as deleted.
+	 * This will not actually delete the script.  If references remain present on the
+	 * heap or the stack, the script will stay in memory in a quasi-deleted state until
+	 * either unreachable (resulting in its eventual deletion) or reloaded (resulting
+	 * in its data being updated).
+	 */
+	void markDeleted() {
+		_markedAsDeleted = true;
+	}
+
+	/**
+	 * Marks the script as not deleted.
+	 */
+	void unmarkDeleted() {
+		_markedAsDeleted = false;
+	}
+
+	/**
+	 * Determines whether the script is marked as being deleted.
+	 */
+	bool isMarkedAsDeleted() const {
+		return _markedAsDeleted;
+	}
+
+	/**
+	 * Retrieves a 16 bit value from within a script's heap representation.
+	 * @param offset	offset to read from
+	 * @return the value read from the specified location
+	 */
+	int16 getHeap(uint16 offset) const;
+
+};
+
+/** Data stack */
+struct DataStack : MemObject {
+	int nr; /**< Number of stack entries */
+	reg_t *entries;
+
+public:
+	DataStack() {
+		nr = 0;
+		entries = NULL;
+	}
+	~DataStack() {
+		free(entries);
+		entries = NULL;
+	}
+
+	virtual byte *dereference(reg_t pointer, int *size);
+	virtual reg_t findCanonicAddress(SegManager *segmgr, reg_t sub_addr);
+	virtual void listAllOutgoingReferences(EngineState *s, reg_t object, void *param, NoteCallback note);
+
+	virtual void saveLoadWithSerializer(Common::Serializer &ser);
+};
+
+#define CLONE_USED -1
+#define CLONE_NONE -1
+
+typedef Object Clone;
+
+struct Node {
+	reg_t pred; /**< Predecessor node */
+	reg_t succ; /**< Successor node */
+	reg_t key;
+	reg_t value;
+}; /* List nodes */
+
+struct List {
+	reg_t first;
+	reg_t last;
+};
+
+struct Hunk {
+	void *mem;
+	unsigned int size;
+	const char *type;
+};
+
+template<typename T>
+struct Table : public MemObject {
+	typedef T value_type;
+	struct Entry : public T {
+		int next_free; /* Only used for free entries */
+	};
+	enum { HEAPENTRY_INVALID = -1 };
+
+
+	int first_free; /**< Beginning of a singly linked list for entries */
+	int entries_used; /**< Statistical information */
+
+	Common::Array<Entry> _table;
+
+public:
+	Table() {
+		initTable();
+	}
+
+	void initTable() {
+		entries_used = 0;
+		first_free = HEAPENTRY_INVALID;
+		_table.clear();
+	}
+
+	int allocEntry() {
+		entries_used++;
+		if (first_free != HEAPENTRY_INVALID) {
+			int oldff = first_free;
+			first_free = _table[oldff].next_free;
+
+			_table[oldff].next_free = oldff;
+			return oldff;
+		} else {
+			uint newIdx = _table.size();
+			_table.push_back(Entry());
+			_table[newIdx].next_free = newIdx;	// Tag as 'valid'
+			return newIdx;
+		}
+	}
+
+	bool isValidEntry(int idx) {
+		return idx >= 0 && (uint)idx < _table.size() && _table[idx].next_free == idx;
+	}
+
+	virtual void freeEntry(int idx) {
+		if (idx < 0 || (uint)idx >= _table.size())
+			::error("Table::freeEntry: Attempt to release invalid table index %d", idx);
+
+		_table[idx].next_free = first_free;
+		first_free = idx;
+		entries_used--;
+	}
+
+	virtual void listAllDeallocatable(SegmentId segId, void *param, NoteCallback note);
+};
+
+
+/* CloneTable */
+struct CloneTable : public Table<Clone> {
+	virtual void freeAtAddress(SegManager *segmgr, reg_t sub_addr);
+	virtual void listAllOutgoingReferences(EngineState *s, reg_t object, void *param, NoteCallback note);
+
+	virtual void saveLoadWithSerializer(Common::Serializer &ser);
+};
+
+
+/* NodeTable */
+struct NodeTable : public Table<Node> {
+	virtual void freeAtAddress(SegManager *segmgr, reg_t sub_addr);
+	virtual void listAllOutgoingReferences(EngineState *s, reg_t object, void *param, NoteCallback note);
+
+	virtual void saveLoadWithSerializer(Common::Serializer &ser);
+};
+
+
+/* ListTable */
+struct ListTable : public Table<List> {
+	virtual void freeAtAddress(SegManager *segmgr, reg_t sub_addr);
+	virtual void listAllOutgoingReferences(EngineState *s, reg_t object, void *param, NoteCallback note);
+
+	virtual void saveLoadWithSerializer(Common::Serializer &ser);
+};
+
+
+/* HunkTable */
+struct HunkTable : public Table<Hunk> {
+	virtual void freeEntry(int idx) {
+		Table<Hunk>::freeEntry(idx);
+
+		free(_table[idx].mem);
+	}
+
+	virtual void saveLoadWithSerializer(Common::Serializer &ser);
+};
+
+
+// Free-style memory
+struct DynMem : public MemObject {
+	int _size;
+	char *_description;
+	byte *_buf;
+
+public:
+	DynMem() : _size(0), _description(0), _buf(0) {}
+	~DynMem() {
+		free(_description);
+		_description = NULL;
+		free(_buf);
+		_buf = NULL;
+	}
+
+	virtual byte *dereference(reg_t pointer, int *size);
+	virtual reg_t findCanonicAddress(SegManager *segmgr, reg_t sub_addr);
+	virtual void listAllDeallocatable(SegmentId segId, void *param, NoteCallback note);
+
+	virtual void saveLoadWithSerializer(Common::Serializer &ser);
+};
+
+
+} // End of namespace Sci
+
+#endif // SCI_ENGINE_VM_H


Property changes on: scummvm/trunk/engines/sci/engine/memobj.h
___________________________________________________________________
Added: svn:mime-type
   + text/plain
Added: svn:keywords
   + Date Rev Author URL Id
Added: svn:eol-style
   + native

Modified: scummvm/trunk/engines/sci/engine/seg_manager.cpp
===================================================================
--- scummvm/trunk/engines/sci/engine/seg_manager.cpp	2009-06-04 11:44:55 UTC (rev 41165)
+++ scummvm/trunk/engines/sci/engine/seg_manager.cpp	2009-06-04 11:45:17 UTC (rev 41166)
@@ -232,49 +232,6 @@
 	return 1;
 }
 
-MemObject *MemObject::createMemObject(MemObjectType type) {
-	MemObject *mem = 0;
-	switch (type) {
-	case MEM_OBJ_SCRIPT:
-		mem = new Script();
-		break;
-	case MEM_OBJ_CLONES:
-		mem = new CloneTable();
-		break;
-	case MEM_OBJ_LOCALS:
-		mem = new LocalVariables();
-		break;
-	case MEM_OBJ_SYS_STRINGS:
-		mem = new SystemStrings();
-		break;
-	case MEM_OBJ_STACK:
-		mem = new DataStack();
-		break;
-	case MEM_OBJ_HUNK:
-		mem = new HunkTable();
-		break;
-	case MEM_OBJ_STRING_FRAG:
-		mem = new StringFrag();
-		break;
-	case MEM_OBJ_LISTS:
-		mem = new ListTable();
-		break;
-	case MEM_OBJ_NODES:
-		mem = new NodeTable();
-		break;
-	case MEM_OBJ_DYNMEM:
-		mem = new DynMem();
-		break;
-	default:
-		error("Unknown MemObject type %d", type);
-		break;
-	}
-
-	assert(mem);
-	mem->_type = type;
-	return mem;
-}
-
 MemObject *SegManager::memObjAllocate(SegmentId segid, int hash_id, MemObjectType type) {
 	MemObject *mem = MemObject::createMemObject(type);
 	if (!mem) {
@@ -294,33 +251,6 @@
 	return mem;
 }
 
-void Script::freeScript() {
-	free(buf);
-	buf = NULL;
-	buf_size = 0;
-
-	_objects.clear();
-
-	delete obj_indices;
-	obj_indices = 0;
-	_codeBlocks.clear();
-}
-
-// memory operations
-
-void Script::mcpyInOut(int dst, const void *src, size_t n) {
-	if (buf) {
-		assert(dst + n <= buf_size);
-		memcpy(buf + dst, src, n);
-	}
-}
-
-int16 Script::getHeap(uint16 offset) const {
-	VERIFY(offset + 1 < (int)buf_size, "invalid offset\n");
-	return READ_LE_UINT16(buf + offset);
-//	return (buf[offset] | (buf[offset+1]) << 8);
-}
-
 // return the seg if script_id is valid and in the map, else -1
 SegmentId SegManager::segGet(int script_id) const {
 	return id_seg_map->lookupKey(script_id);
@@ -367,53 +297,10 @@
 	return getScriptIfLoaded(seg) != 0;
 }
 
-void Script::incrementLockers() {
-	lockers++;
-}
-
-void Script::decrementLockers() {
-	if (lockers > 0)
-		lockers--;
-}
-
-int Script::getLockers() const {
-	return lockers;
-}
-
-void Script::setLockers(int lockers_) {
-	lockers = lockers_;
-}
-
-void Script::setExportTableOffset(int offset) {
-	if (offset) {
-		export_table = (uint16 *)(buf + offset + 2);
-		exports_nr = READ_LE_UINT16((byte *)(export_table - 1));
-	} else {
-		export_table = NULL;
-		exports_nr = 0;
-	}
-}
-
 void SegManager::setExportWidth(int flag) {
 	exports_wide = flag;
 }
 
-void Script::setSynonymsOffset(int offset) {
-	synonyms = buf + offset;
-}
-
-byte *Script::getSynonyms() const {
-	return synonyms;
-}
-
-void Script::setSynonymsNr(int n) {
-	synonyms_nr = n;
-}
-
-int Script::getSynonymsNr() const {
-	return synonyms_nr;
-}
-
 int SegManager::relocateBlock(Common::Array<reg_t> &block, int block_location, SegmentId segment, int location) {
 	int rel = location - block_location;
 
@@ -925,67 +812,6 @@
 	return &(table->_table[offset]);
 }
 
-byte *MemObject::dereference(reg_t pointer, int *size) {
-	error("Error: Trying to dereference pointer %04x:%04x to inappropriate segment",
-		          PRINT_REG(pointer));
-	return NULL;
-}
-
-byte *Script::dereference(reg_t pointer, int *size) {
-	if (pointer.offset > buf_size) {
-		sciprintf("Error: Attempt to dereference invalid pointer %04x:%04x into script segment (script size=%d)\n",
-				  PRINT_REG(pointer), (uint)buf_size);
-		return NULL;
-	}
-	if (size)
-		*size = buf_size - pointer.offset;
-	return (byte *)(buf + pointer.offset);
-}
-
-byte *LocalVariables::dereference(reg_t pointer, int *size) {
-	// FIXME: The following doesn't seem to be endian safe.
-	// To fix this, we'd have to always treat the reg_t
-	// values stored here as in the little endian format.
-	int count = _locals.size() * sizeof(reg_t);
-	byte *base = (byte *)&_locals[0];
-
-	if (size)
-		*size = count;
-
-	return base + pointer.offset;
-}
-
-byte *DataStack::dereference(reg_t pointer, int *size) {
-	int count = nr * sizeof(reg_t);
-	byte *base = (byte *)entries;
-
-	if (size)
-		*size = count;
-
-	return base + pointer.offset;
-}
-
-byte *DynMem::dereference(reg_t pointer, int *size) {
-	int count = _size;
-	byte *base = (byte *)_buf;
-
-	if (size)
-		*size = count;
-
-	return base + pointer.offset;
-}
-
-byte *SystemStrings::dereference(reg_t pointer, int *size) {
-	if (size)
-		*size = strings[pointer.offset].max_size;
-	if (pointer.offset < SYS_STRINGS_MAX && strings[pointer.offset].name)
-		return (byte *)(strings[pointer.offset].value);
-
-	// This occurs in KQ5CD when interacting with certain objects
-	warning("Attempt to dereference invalid pointer %04x:%04x", PRINT_REG(pointer));
-	return NULL;
-}
-
 byte *SegManager::dereference(reg_t pointer, int *size) {
 	if (!pointer.segment || (pointer.segment >= _heap.size()) || !_heap[pointer.segment]) {
 		// This occurs in KQ5CD when interacting with certain objects
@@ -1048,191 +874,5 @@
 }
 
 
-//-------------------- script --------------------
-reg_t Script::findCanonicAddress(SegManager *segmgr, reg_t addr) {
-	addr.offset = 0;
-	return addr;
-}
 
-void Script::freeAtAddress(SegManager *segmgr, reg_t addr) {
-	/*
-		sciprintf("[GC] Freeing script %04x:%04x\n", PRINT_REG(addr));
-		if (locals_segment)
-			sciprintf("[GC] Freeing locals %04x:0000\n", locals_segment);
-	*/
-
-	if (_markedAsDeleted)
-		segmgr->deallocateScript(nr);
-}
-
-void Script::listAllDeallocatable(SegmentId segId, void *param, NoteCallback note) {
-	(*note)(param, make_reg(segId, 0));
-}
-
-void Script::listAllOutgoingReferences(EngineState *s, reg_t addr, void *param, NoteCallback note) {
-	Script *script = this;
-
-	if (addr.offset <= script->buf_size && addr.offset >= -SCRIPT_OBJECT_MAGIC_OFFSET && RAW_IS_OBJECT(script->buf + addr.offset)) {
-		int idx = RAW_GET_CLASS_INDEX(script, addr);
-		if (idx >= 0 && (uint)idx < script->_objects.size()) {
-			// Note all local variables, if we have a local variable environment
-			if (script->locals_segment)
-				(*note)(param, make_reg(script->locals_segment, 0));
-
-			Object &obj = script->_objects[idx];
-			for (uint i = 0; i < obj._variables.size(); i++)
-				(*note)(param, obj._variables[i]);
-		} else {
-			warning("Request for outgoing script-object reference at %04x:%04x yielded invalid index %d", PRINT_REG(addr), idx);
-		}
-	} else {
-		/*		warning("Unexpected request for outgoing script-object references at %04x:%04x", PRINT_REG(addr));*/
-		/* Happens e.g. when we're looking into strings */
-	}
-}
-
-
-//-------------------- clones --------------------
-
-template<typename T>
-void Table<T>::listAllDeallocatable(SegmentId segId, void *param, NoteCallback note) {
-	for (uint i = 0; i < _table.size(); i++)
-		if (isValidEntry(i))
-			(*note)(param, make_reg(segId, i));
-}
-
-void CloneTable::listAllOutgoingReferences(EngineState *s, reg_t addr, void *param, NoteCallback note) {
-	CloneTable *clone_table = this;
-	Clone *clone;
-
-//	assert(addr.segment == _segId);
-
-	if (!clone_table->isValidEntry(addr.offset)) {
-		warning("Unexpected request for outgoing references from clone at %04x:%04x", PRINT_REG(addr));
-//		BREAKPOINT();
-		return;
-	}
-
-	clone = &(clone_table->_table[addr.offset]);
-
-	// Emit all member variables (including references to the 'super' delegate)
-	for (uint i = 0; i < clone->_variables.size(); i++)
-		(*note)(param, clone->_variables[i]);
-
-	// Note that this also includes the 'base' object, which is part of the script and therefore also emits the locals.
-	(*note)(param, clone->pos);
-	//sciprintf("[GC] Reporting clone-pos %04x:%04x\n", PRINT_REG(clone->pos));
-}
-
-void CloneTable::freeAtAddress(SegManager *segmgr, reg_t addr) {
-	CloneTable *clone_table = this;
-	Object *victim_obj;
-
-//	assert(addr.segment == _segId);
-
-	victim_obj = &(clone_table->_table[addr.offset]);
-
-#ifdef GC_DEBUG
-	if (!(victim_obj->flags & OBJECT_FLAG_FREED))
-		sciprintf("[GC] Warning: Clone %04x:%04x not reachable and not freed (freeing now)\n", PRINT_REG(addr));
-#ifdef GC_DEBUG_VERBOSE
-	else
-		sciprintf("[GC-DEBUG] Clone %04x:%04x: Freeing\n", PRINT_REG(addr));
-#endif
-#endif
-	/*
-		sciprintf("[GC] Clone %04x:%04x: Freeing\n", PRINT_REG(addr));
-		sciprintf("[GC] Clone had pos %04x:%04x\n", PRINT_REG(victim_obj->pos));
-	*/
-	clone_table->freeEntry(addr.offset);
-}
-
-
-//-------------------- locals --------------------
-reg_t LocalVariables::findCanonicAddress(SegManager *segmgr, reg_t addr) {
-	// Reference the owning script
-	SegmentId owner_seg = segmgr->segGet(script_id);
-
-	assert(owner_seg >= 0);
-
-	return make_reg(owner_seg, 0);
-}
-
-void LocalVariables::listAllOutgoingReferences(EngineState *s, reg_t addr, void *param, NoteCallback note) {
-//	assert(addr.segment == _segId);
-
-	for (uint i = 0; i < _locals.size(); i++)
-		(*note)(param, _locals[i]);
-}
-
-
-//-------------------- stack --------------------
-reg_t DataStack::findCanonicAddress(SegManager *segmgr, reg_t addr) {
-	addr.offset = 0;
-	return addr;
-}
-
-void DataStack::listAllOutgoingReferences(EngineState *s, reg_t addr, void *param, NoteCallback note) {
-	fprintf(stderr, "Emitting %d stack entries\n", nr);
-	for (int i = 0; i < nr; i++)
-		(*note)(param, entries[i]);
-	fprintf(stderr, "DONE");
-}
-
-
-//-------------------- lists --------------------
-void ListTable::freeAtAddress(SegManager *segmgr, reg_t sub_addr) {
-	freeEntry(sub_addr.offset);
-}
-
-void ListTable::listAllOutgoingReferences(EngineState *s, reg_t addr, void *param, NoteCallback note) {
-	if (!isValidEntry(addr.offset)) {
-		warning("Invalid list referenced for outgoing references: %04x:%04x", PRINT_REG(addr));
-		return;
-	}
-
-	List *list = &(_table[addr.offset]);
-
-	note(param, list->first);
-	note(param, list->last);
-	// We could probably get away with just one of them, but
-	// let's be conservative here.
-}
-
-
-//-------------------- nodes --------------------
-void NodeTable::freeAtAddress(SegManager *segmgr, reg_t sub_addr) {
-	freeEntry(sub_addr.offset);
-}
-
-void NodeTable::listAllOutgoingReferences(EngineState *s, reg_t addr, void *param, NoteCallback note) {
-	if (!isValidEntry(addr.offset)) {
-		warning("Invalid node referenced for outgoing references: %04x:%04x", PRINT_REG(addr));
-		return;
-	}
-	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);
-}
-
-
-//-------------------- hunk --------------------
-
-//-------------------- dynamic memory --------------------
-
-reg_t DynMem::findCanonicAddress(SegManager *segmgr, reg_t addr) {
-	addr.offset = 0;
-	return addr;
-}
-
-void DynMem::listAllDeallocatable(SegmentId segId, void *param, NoteCallback note) {
-	(*note)(param, make_reg(segId, 0));
-}
-
-
 } // End of namespace Sci

Modified: scummvm/trunk/engines/sci/engine/seg_manager.h
===================================================================
--- scummvm/trunk/engines/sci/engine/seg_manager.h	2009-06-04 11:44:55 UTC (rev 41165)
+++ scummvm/trunk/engines/sci/engine/seg_manager.h	2009-06-04 11:45:17 UTC (rev 41166)
@@ -29,6 +29,7 @@
 #include "common/scummsys.h"
 #include "common/serializer.h"
 #include "sci/engine/vm.h"
+#include "sci/engine/memobj.h"
 
 namespace Sci {
 

Modified: scummvm/trunk/engines/sci/engine/vm.h
===================================================================
--- scummvm/trunk/engines/sci/engine/vm.h	2009-06-04 11:44:55 UTC (rev 41165)
+++ scummvm/trunk/engines/sci/engine/vm.h	2009-06-04 11:45:17 UTC (rev 41166)
@@ -28,7 +28,6 @@
 
 /* VM and kernel declarations */
 
-#include "common/serializer.h"
 #include "sci/engine/vm_types.h"	// for reg_t
 
 #include "common/util.h"
@@ -38,129 +37,9 @@
 class SegManager;
 struct EngineState;
 typedef int sci_version_t;
-
-enum MemObjectType {
-	MEM_OBJ_INVALID = 0,
-	MEM_OBJ_SCRIPT = 1,
-	MEM_OBJ_CLONES = 2,
-	MEM_OBJ_LOCALS = 3,
-	MEM_OBJ_STACK = 4,
-	MEM_OBJ_SYS_STRINGS = 5,
-	MEM_OBJ_LISTS = 6,
-	MEM_OBJ_NODES = 7,
-	MEM_OBJ_HUNK = 8,
-	MEM_OBJ_DYNMEM = 9,
-	MEM_OBJ_STRING_FRAG = 10,
-
-	MEM_OBJ_MAX // For sanity checking
-};
-
-struct MemObject : public Common::Serializable {
-	MemObjectType _type;
-	int _segmgrId; /**< Internal value used by the seg_manager's hash map */
-
-	typedef void (*NoteCallback)(void *param, reg_t addr);	// FIXME: Bad choice of name
-
-public:
-	static MemObject *createMemObject(MemObjectType type);
-
-public:
-	virtual ~MemObject() {}
-
-	inline MemObjectType getType() const { return _type; }
-	inline int getSegMgrId() const { return _segmgrId; }
-
-	/**
-	 * Dereferences a raw memory pointer.
-	 * @param reg   reference to dereference
-	 * @param size  if not NULL, set to the theoretical maximum size of the referenced data block
-	 * @return              the data block referenced
-	 */
-	virtual byte *dereference(reg_t pointer, int *size);
-
-	/**
-	 * Finds the canonic address associated with sub_reg.
-	 *
-	 * For each valid address a, there exists a canonic address c(a) such that c(a) = c(c(a)).
-	 * This address "governs" a in the sense that deallocating c(a) will deallocate a.
-	 *
-	 * @param sub_addr		base address whose canonic address is to be found
-	 */
-	virtual reg_t findCanonicAddress(SegManager *segmgr, reg_t sub_addr) { return sub_addr; }
-
-	/**
-	 * Deallocates all memory associated with the specified address.
-	 * @param sub_addr		address (within the given segment) to deallocate
-	 */
-	virtual void freeAtAddress(SegManager *segmgr, reg_t sub_addr) {}
-
-	/**
-	 * Iterates over and reports all addresses within the current segment.
-	 * @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) {}
-
-	/**
-	 * 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
-	 * Note: This function may also choose to report numbers (segment 0) as adresses
-	 */
-	virtual void listAllOutgoingReferences(EngineState *s, reg_t object, void *param, NoteCallback note) {}
-};
-
-
-// TODO: Implement the following class
-struct StringFrag : public MemObject {
-	virtual void saveLoadWithSerializer(Common::Serializer &ser);
-};
-
 struct IntMapper;
+struct Object;
 
-enum {
-	SYS_STRINGS_MAX = 4,
-
-	SYS_STRING_SAVEDIR = 0,
-	SYS_STRING_PARSER_BASE = 1,
-
-	MAX_PARSER_BASE = 64
-};
-
-struct SystemString {
-	char *name;
-	int max_size;
-	reg_t *value;
-};
-
-struct SystemStrings : public MemObject {
-	SystemString strings[SYS_STRINGS_MAX];
-
-public:
-	SystemStrings() {
-		memset(strings, 0, sizeof(strings));
-	}
-	~SystemStrings() {
-		for (int i = 0; i < SYS_STRINGS_MAX; i++) {
-			SystemString *str = &strings[i];
-			if (str->name) {
-				free(str->name);
-				str->name = NULL;
-
-				free(str->value);
-				str->value = NULL;
-
-				str->max_size = 0;
-			}
-		}
-	}
-
-	virtual byte *dereference(reg_t pointer, int *size);
-
-	virtual void saveLoadWithSerializer(Common::Serializer &ser);
-};
-
 /** Number of bytes to be allocated for the stack */
 #define VM_STACK_SIZE 0x1000
 
@@ -243,401 +122,7 @@
 
 #define IS_CLASS(obj) (obj->_variables[SCRIPT_INFO_SELECTOR].offset & SCRIPT_INFO_CLASS)
 
-/** This struct is used to buffer the list of send calls in send_selector() */
-struct CallsStruct {
-	union {
-		reg_t func;
-		reg_t *var;
-	} address;
-	StackPtr argp;
-	int argc;
-	Selector selector;
-	StackPtr sp; /**< Stack pointer */
-	int type; /**< Same as ExecStack.type */
-};
 
-struct LocalVariables : public MemObject {
-	int script_id; /**< Script ID this local variable block belongs to */
-	Common::Array<reg_t> _locals;
-
-public:
-	LocalVariables() {
-		script_id = 0;
-	}
-
-	virtual byte *dereference(reg_t pointer, int *size);
-	virtual reg_t findCanonicAddress(SegManager *segmgr, reg_t sub_addr);
-	virtual void listAllOutgoingReferences(EngineState *s, reg_t object, void *param, NoteCallback note);
-
-	virtual void saveLoadWithSerializer(Common::Serializer &ser);
-};
-
-/** Clone has been marked as 'freed' */
-#define OBJECT_FLAG_FREED (0x1 << 0)
-
-struct Object {
-	int flags;
-	reg_t pos; /**< Object offset within its script; for clones, this is their base */
-	int variable_names_nr; /**< Number of variable names, may be less than variables_nr */
-	int methods_nr;
-	byte *base; /**< Points to a buffer all relative references (code, strings) point to */
-	byte *base_obj; /**< base + object offset within base */
-	uint16 *base_method; /**< Pointer to the method selector area for this object */
-	uint16 *base_vars; /**< Pointer to the varselector area for this object */
-	Common::Array<reg_t> _variables;
-};
-
-struct CodeBlock {
-	reg_t pos;
-	int size;
-};
-
-#define VM_OBJECT_GET_VARSELECTOR(obj, i)  \
-	(s->version < SCI_VERSION_1_1 ? \
-	 READ_LE_UINT16(obj->base_obj + obj->_variables.size() * 2 + i*2) : \
-	 *(obj->base_vars + i))
-#define VM_OBJECT_READ_PROPERTY(obj, i) (obj->_variables[i])
-#define VM_OBJECT_GET_FUNCSELECTOR(obj, i) \
-	(s->version < SCI_VERSION_1_1 ? \
-	 READ_LE_UINT16((byte *) (obj->base_method + i)) : \
-	 READ_LE_UINT16((byte *) (obj->base_method + i*2 + 1)))
-#define VM_OBJECT_READ_FUNCTION(obj, i) \
-	(s->version < SCI_VERSION_1_1 ? \
-	 make_reg(obj->pos.segment, \
-		 READ_LE_UINT16((byte *) (obj->base_method \
-				 + obj->methods_nr + 1 \
-				 + i))) : \
-	 make_reg(obj->pos.segment, \
-		 READ_LE_UINT16((byte *) (obj->base_method \
-				 + i * 2 + 2))))
-
-
-
-
-struct Script : public MemObject {
-	int nr; /**< Script number */
-	byte *buf; /**< Static data buffer, or NULL if not used */
-	size_t buf_size;
-	size_t script_size;
-	size_t heap_size;
-
-	byte *synonyms; /**< Synonyms block or 0 if not present*/
-	byte *heap_start; /**< Start of heap if SCI1.1, NULL otherwise */
-	uint16 *export_table; /**< Abs. offset of the export table or 0 if not present */
-
-	IntMapper *obj_indices;
-
-	int exports_nr; /**< Number of entries in the exports table */
-	int synonyms_nr; /**< Number of entries in the synonyms block */
-	int lockers; /**< Number of classes and objects that require this script */
-
-	/**
-	 * Table for objects, contains property variables.
-	 * Indexed by the value stored at SCRIPT_LOCALVARPTR_OFFSET,
-	 * see VM_OBJECT_[GS]ET_INDEX()
-	 */
-	Common::Array<Object> _objects;
-
-	int locals_offset;
-	int locals_segment; /**< The local variable segment */
-	LocalVariables *locals_block;
-
-	Common::Array<CodeBlock> _codeBlocks;
-	int relocated;
-	bool _markedAsDeleted;
-
-public:
-	Script() {
-		nr = 0;
-		buf = NULL;
-		buf_size = 0;
-		script_size = 0;
-		heap_size = 0;
-
-		synonyms = NULL;
-		heap_start = NULL;
-		export_table = NULL;
-
-		obj_indices = NULL;
-
-		locals_offset = 0;
-		locals_segment = 0;
-		locals_block = NULL;
-
-		relocated = 0;
-		_markedAsDeleted = 0;
-	}
-
-	~Script() {
-		freeScript();
-	}
-
-	void freeScript();
-
-	virtual byte *dereference(reg_t pointer, int *size);
-	virtual reg_t findCanonicAddress(SegManager *segmgr, reg_t sub_addr);
-	virtual void freeAtAddress(SegManager *segmgr, reg_t sub_addr);
-	virtual void listAllDeallocatable(SegmentId segId, void *param, NoteCallback note);
-	virtual void listAllOutgoingReferences(EngineState *s, reg_t object, void *param, NoteCallback note);
-
-	virtual void saveLoadWithSerializer(Common::Serializer &ser);
-
-	// script lock operations
-
-	/** Increments the number of lockers of this script by one. */
-	void incrementLockers();
-
-	/** Decrements the number of lockers of this script by one. */
-	void decrementLockers();
-
-	/**
-	 * Retrieves the number of locks held on this script.
-	 * @return the number of locks held on the previously identified script
-	 */
-	int getLockers() const;
-
-	/** Sets the number of locks held on this script. */
-	void setLockers(int lockers);
-
-	/**
-	 * Retrieves a pointer to the synonyms associated with this script
-	 * @return	pointer to the synonyms, in non-parsed format.
-	 */
-	byte *getSynonyms() const;
-
-	/**
-	 * Retrieves the number of synonyms associated with this script.
-	 * @return	the number of synonyms associated with this script
-	 */
-	int getSynonymsNr() const;
-
-
-	/**
-	 * Sets the script-relative offset of the exports table.
-	 * @param offset	script-relative exports table offset
-	 */
-	void setExportTableOffset(int offset);
-
-	/**
-	 * Sets the script-relative offset of the synonyms associated with this script.
-	 * @param offset	script-relative offset of the synonyms block
-	 */
-	void setSynonymsOffset(int offset);
-
-	/**
-	 * Sets the number of synonyms associated with this script,
-	 * @param nr		number of synonyms, as to be stored within the script
-	 */
-	void setSynonymsNr(int nr);
-
-
-	/**
-	 * Copies a byte string into a script's heap representation.
-	 * @param dst	script-relative offset of the destination area
-	 * @param src	pointer to the data source location
-	 * @param n		number of bytes to copy
-	 */
-	void mcpyInOut(int dst, const void *src, size_t n);
-
-
-	/**
-	 * Marks the script as deleted.
-	 * This will not actually delete the script.  If references remain present on the
-	 * heap or the stack, the script will stay in memory in a quasi-deleted state until
-	 * either unreachable (resulting in its eventual deletion) or reloaded (resulting
-	 * in its data being updated).
-	 */
-	void markDeleted() {
-		_markedAsDeleted = true;
-	}
-
-	/**
-	 * Marks the script as not deleted.
-	 */
-	void unmarkDeleted() {
-		_markedAsDeleted = false;
-	}
-
-	/**
-	 * Determines whether the script is marked as being deleted.
-	 */
-	bool isMarkedAsDeleted() const {
-		return _markedAsDeleted;
-	}
-
-	/**
-	 * Retrieves a 16 bit value from within a script's heap representation.
-	 * @param offset	offset to read from
-	 * @return the value read from the specified location
-	 */
-	int16 getHeap(uint16 offset) const;
-
-};
-
-/** Data stack */
-struct DataStack : MemObject {
-	int nr; /**< Number of stack entries */
-	reg_t *entries;
-
-public:
-	DataStack() {
-		nr = 0;
-		entries = NULL;
-	}
-	~DataStack() {
-		free(entries);
-		entries = NULL;
-	}
-
-	virtual byte *dereference(reg_t pointer, int *size);
-	virtual reg_t findCanonicAddress(SegManager *segmgr, reg_t sub_addr);
-	virtual void listAllOutgoingReferences(EngineState *s, reg_t object, void *param, NoteCallback note);
-
-	virtual void saveLoadWithSerializer(Common::Serializer &ser);
-};
-
-#define CLONE_USED -1
-#define CLONE_NONE -1
-
-typedef Object Clone;
-
-struct Node {
-	reg_t pred; /**< Predecessor node */
-	reg_t succ; /**< Successor node */
-	reg_t key;
-	reg_t value;
-}; /* List nodes */
-
-struct List {
-	reg_t first;
-	reg_t last;
-};
-
-struct Hunk {
-	void *mem;
-	unsigned int size;
-	const char *type;
-};
-
-template<typename T>
-struct Table : public MemObject {
-	typedef T value_type;
-	struct Entry : public T {
-		int next_free; /* Only used for free entries */
-	};
-	enum { HEAPENTRY_INVALID = -1 };
-
-
-	int first_free; /**< Beginning of a singly linked list for entries */
-	int entries_used; /**< Statistical information */
-
-	Common::Array<Entry> _table;
-
-public:
-	Table() {
-		initTable();
-	}
-
-	void initTable() {
-		entries_used = 0;
-		first_free = HEAPENTRY_INVALID;
-		_table.clear();
-	}
-
-	int allocEntry() {
-		entries_used++;
-		if (first_free != HEAPENTRY_INVALID) {
-			int oldff = first_free;
-			first_free = _table[oldff].next_free;
-
-			_table[oldff].next_free = oldff;
-			return oldff;
-		} else {
-			uint newIdx = _table.size();
-			_table.push_back(Entry());
-			_table[newIdx].next_free = newIdx;	// Tag as 'valid'
-			return newIdx;
-		}
-	}
-
-	bool isValidEntry(int idx) {
-		return idx >= 0 && (uint)idx < _table.size() && _table[idx].next_free == idx;
-	}
-
-	virtual void freeEntry(int idx) {
-		if (idx < 0 || (uint)idx >= _table.size())
-			::error("Table::freeEntry: Attempt to release invalid table index %d", idx);
-
-		_table[idx].next_free = first_free;
-		first_free = idx;
-		entries_used--;
-	}
-
-	virtual void listAllDeallocatable(SegmentId segId, void *param, NoteCallback note);
-};
-
-
-/* CloneTable */
-struct CloneTable : public Table<Clone> {
-	virtual void freeAtAddress(SegManager *segmgr, reg_t sub_addr);
-	virtual void listAllOutgoingReferences(EngineState *s, reg_t object, void *param, NoteCallback note);
-
-	virtual void saveLoadWithSerializer(Common::Serializer &ser);
-};
-
-
-/* NodeTable */
-struct NodeTable : public Table<Node> {
-	virtual void freeAtAddress(SegManager *segmgr, reg_t sub_addr);
-	virtual void listAllOutgoingReferences(EngineState *s, reg_t object, void *param, NoteCallback note);
-
-	virtual void saveLoadWithSerializer(Common::Serializer &ser);
-};
-
-
-/* ListTable */
-struct ListTable : public Table<List> {
-	virtual void freeAtAddress(SegManager *segmgr, reg_t sub_addr);
-	virtual void listAllOutgoingReferences(EngineState *s, reg_t object, void *param, NoteCallback note);
-
-	virtual void saveLoadWithSerializer(Common::Serializer &ser);
-};
-
-
-/* HunkTable */
-struct HunkTable : public Table<Hunk> {
-	virtual void freeEntry(int idx) {
-		Table<Hunk>::freeEntry(idx);
-
-		free(_table[idx].mem);
-	}
-
-	virtual void saveLoadWithSerializer(Common::Serializer &ser);
-};
-
-
-// Free-style memory
-struct DynMem : public MemObject {
-	int _size;
-	char *_description;
-	byte *_buf;
-
-public:
-	DynMem() : _size(0), _description(0), _buf(0) {}
-	~DynMem() {
-		free(_description);
-		_description = NULL;
-		free(_buf);
-		_buf = NULL;
-	}
-
-	virtual byte *dereference(reg_t pointer, int *size);
-	virtual reg_t findCanonicAddress(SegManager *segmgr, reg_t sub_addr);
-	virtual void listAllDeallocatable(SegmentId segId, void *param, NoteCallback note);
-
-	virtual void saveLoadWithSerializer(Common::Serializer &ser);
-};
-
 /** Contains selector IDs for a few selected selectors */
 struct selector_map_t {
 	Selector init; /**< Init function */

Modified: scummvm/trunk/engines/sci/module.mk
===================================================================
--- scummvm/trunk/engines/sci/module.mk	2009-06-04 11:44:55 UTC (rev 41165)
+++ scummvm/trunk/engines/sci/module.mk	2009-06-04 11:45:17 UTC (rev 41166)
@@ -27,6 +27,7 @@
 	engine/ksound.o \
 	engine/kstring.o \
 	engine/message.o \
+	engine/memobj.o \
 	engine/said.o \
 	engine/savegame.o \
 	engine/script.o \


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.




More information about the Scummvm-git-logs mailing list