aboutsummaryrefslogtreecommitdiff
path: root/engines
diff options
context:
space:
mode:
authorMax Horn2009-06-04 11:45:17 +0000
committerMax Horn2009-06-04 11:45:17 +0000
commit6b1110b82d37c067dec5668d9ddaa1e51e5d0e91 (patch)
treeb7bb811579a8b03e86573c9da968a055c8ee07e9 /engines
parent4f08dc538c91874aadb3abdd16eacee9a9ccccf6 (diff)
downloadscummvm-rg350-6b1110b82d37c067dec5668d9ddaa1e51e5d0e91.tar.gz
scummvm-rg350-6b1110b82d37c067dec5668d9ddaa1e51e5d0e91.tar.bz2
scummvm-rg350-6b1110b82d37c067dec5668d9ddaa1e51e5d0e91.zip
SCI: Moved MemObject code into a separate source file
svn-id: r41166
Diffstat (limited to 'engines')
-rw-r--r--engines/sci/console.h1
-rw-r--r--engines/sci/engine/memobj.cpp399
-rw-r--r--engines/sci/engine/memobj.h556
-rw-r--r--engines/sci/engine/seg_manager.cpp360
-rw-r--r--engines/sci/engine/seg_manager.h1
-rw-r--r--engines/sci/engine/vm.h517
-rw-r--r--engines/sci/module.mk1
7 files changed, 959 insertions, 876 deletions
diff --git a/engines/sci/console.h b/engines/sci/console.h
index f0975837df..b97b14f354 100644
--- a/engines/sci/console.h
+++ b/engines/sci/console.h
@@ -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);
diff --git a/engines/sci/engine/memobj.cpp b/engines/sci/engine/memobj.cpp
new file mode 100644
index 0000000000..ef48270b41
--- /dev/null
+++ b/engines/sci/engine/memobj.cpp
@@ -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
diff --git a/engines/sci/engine/memobj.h b/engines/sci/engine/memobj.h
new file mode 100644
index 0000000000..a871d2dcb6
--- /dev/null
+++ b/engines/sci/engine/memobj.h
@@ -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
diff --git a/engines/sci/engine/seg_manager.cpp b/engines/sci/engine/seg_manager.cpp
index 69a939dae9..840c9bc525 100644
--- a/engines/sci/engine/seg_manager.cpp
+++ b/engines/sci/engine/seg_manager.cpp
@@ -232,49 +232,6 @@ int SegManager::deallocateScript(int script_nr) {
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 @@ MemObject *SegManager::memObjAllocate(SegmentId segid, int hash_id, MemObjectTyp
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 @@ bool SegManager::scriptIsLoaded(SegmentId seg) {
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 @@ Hunk *SegManager::alloc_Hunk(reg_t *addr) {
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 @@ void SegManager::dbgPrint(const char* msg, void *i) {
}
-//-------------------- 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
diff --git a/engines/sci/engine/seg_manager.h b/engines/sci/engine/seg_manager.h
index 643385fd74..dc91d60e69 100644
--- a/engines/sci/engine/seg_manager.h
+++ b/engines/sci/engine/seg_manager.h
@@ -29,6 +29,7 @@
#include "common/scummsys.h"
#include "common/serializer.h"
#include "sci/engine/vm.h"
+#include "sci/engine/memobj.h"
namespace Sci {
diff --git a/engines/sci/engine/vm.h b/engines/sci/engine/vm.h
index 70802bb377..39ffbb2760 100644
--- a/engines/sci/engine/vm.h
+++ b/engines/sci/engine/vm.h
@@ -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,128 +37,8 @@ namespace Sci {
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;
-
-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);
-};
+struct Object;
/** Number of bytes to be allocated for the stack */
#define VM_STACK_SIZE 0x1000
@@ -243,400 +122,6 @@ struct Class {
#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 {
diff --git a/engines/sci/module.mk b/engines/sci/module.mk
index f67d81e6e9..f2c58bcd8d 100644
--- a/engines/sci/module.mk
+++ b/engines/sci/module.mk
@@ -27,6 +27,7 @@ MODULE_OBJS = \
engine/ksound.o \
engine/kstring.o \
engine/message.o \
+ engine/memobj.o \
engine/said.o \
engine/savegame.o \
engine/script.o \