aboutsummaryrefslogtreecommitdiff
path: root/engines/sci/engine
diff options
context:
space:
mode:
Diffstat (limited to 'engines/sci/engine')
-rw-r--r--engines/sci/engine/kernel.cpp2
-rw-r--r--engines/sci/engine/savegame.cpp12
-rw-r--r--engines/sci/engine/scriptdebug.cpp6
-rw-r--r--engines/sci/engine/seg_manager.cpp203
-rw-r--r--engines/sci/engine/seg_manager.h4
-rw-r--r--engines/sci/engine/vm.cpp12
-rw-r--r--engines/sci/engine/vm.h134
7 files changed, 226 insertions, 147 deletions
diff --git a/engines/sci/engine/kernel.cpp b/engines/sci/engine/kernel.cpp
index 4da9b62348..a08b31effe 100644
--- a/engines/sci/engine/kernel.cpp
+++ b/engines/sci/engine/kernel.cpp
@@ -722,7 +722,7 @@ int determine_reg_type(EngineState *s, reg_t reg, int allow_invalid) {
return KSIG_NODE | KSIG_INVALID;
case MEM_OBJ_DYNMEM:
- if (allow_invalid || reg.offset < (*(DynMem *)mobj).size)
+ if (allow_invalid || reg.offset < (*(DynMem *)mobj)._size)
return KSIG_REF;
else
return KSIG_REF | KSIG_INVALID;
diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp
index 800774f01c..9c276aa0cc 100644
--- a/engines/sci/engine/savegame.cpp
+++ b/engines/sci/engine/savegame.cpp
@@ -394,13 +394,13 @@ static void sync_SystemStrings(Common::Serializer &s, SystemStrings &obj) {
}
static void sync_DynMem(Common::Serializer &s, DynMem &obj) {
- s.syncAsSint32LE(obj.size);
- syncCStr(s, &obj.description);
- if (!obj.buf && obj.size) {
- obj.buf = (byte *)sci_calloc(obj.size, 1);
+ s.syncAsSint32LE(obj._size);
+ syncCStr(s, &obj._description);
+ if (!obj._buf && obj._size) {
+ obj._buf = (byte *)sci_calloc(obj._size, 1);
}
- if (obj.size)
- s.syncBytes(obj.buf, obj.size);
+ if (obj._size)
+ s.syncBytes(obj._buf, obj._size);
}
#pragma mark -
diff --git a/engines/sci/engine/scriptdebug.cpp b/engines/sci/engine/scriptdebug.cpp
index 82d6461ebe..738b74367c 100644
--- a/engines/sci/engine/scriptdebug.cpp
+++ b/engines/sci/engine/scriptdebug.cpp
@@ -325,7 +325,7 @@ int c_segtable(EngineState *s) {
break;
case MEM_OBJ_DYNMEM:
- sciprintf("M dynmem: %d bytes", (*(DynMem *)mobj).size);
+ sciprintf("M dynmem: %d bytes", (*(DynMem *)mobj)._size);
break;
case MEM_OBJ_STRING_FRAG:
@@ -483,9 +483,9 @@ static void _c_single_seg_info(EngineState *s, MemObject *mobj) {
case MEM_OBJ_DYNMEM: {
sciprintf("dynmem (%s): %d bytes\n",
- (*(DynMem *)mobj).description ? (*(DynMem *)mobj).description : "no description", (*(DynMem *)mobj).size);
+ (*(DynMem *)mobj)._description ? (*(DynMem *)mobj)._description : "no description", (*(DynMem *)mobj)._size);
- sci_hexdump((*(DynMem *)mobj).buf, (*(DynMem *)mobj).size, 0);
+ sci_hexdump((*(DynMem *)mobj)._buf, (*(DynMem *)mobj)._size, 0);
}
break;
diff --git a/engines/sci/engine/seg_manager.cpp b/engines/sci/engine/seg_manager.cpp
index 773969514b..eccd1f793f 100644
--- a/engines/sci/engine/seg_manager.cpp
+++ b/engines/sci/engine/seg_manager.cpp
@@ -114,7 +114,7 @@ SegManager::~SegManager() {
// Returns : 0 - allocation failure
// 1 - allocated successfully
// seg_id - allocated segment id
-MemObject *SegManager::allocateScript(EngineState *s, int script_nr, int* seg_id) {
+Script *SegManager::allocateScript(EngineState *s, int script_nr, int* seg_id) {
int seg;
bool was_added;
MemObject* mem;
@@ -122,7 +122,7 @@ MemObject *SegManager::allocateScript(EngineState *s, int script_nr, int* seg_id
seg = id_seg_map->checkKey(script_nr, true, &was_added);
if (!was_added) {
*seg_id = seg;
- return _heap[*seg_id];
+ return (Script *)_heap[*seg_id];
}
// allocate the MemObject
@@ -133,7 +133,7 @@ MemObject *SegManager::allocateScript(EngineState *s, int script_nr, int* seg_id
}
*seg_id = seg;
- return mem;
+ return (Script *)mem;
}
void SegManager::setScriptSize(Script &scr, EngineState *s, int script_nr) {
@@ -176,11 +176,11 @@ int SegManager::initialiseScript(Script &scr, EngineState *s, int script_nr) {
// allocate the script.buf
setScriptSize(scr, s, script_nr);
- scr.buf = (byte*)sci_malloc(scr.buf_size);
+ scr.buf = (byte *)sci_malloc(scr.buf_size);
dbgPrint("scr.buf ", scr.buf);
if (!scr.buf) {
- freeScript(scr);
+ scr.freeScript();
sciprintf("SegManager: Not enough memory space for script size");
scr.buf_size = 0;
return 0;
@@ -215,68 +215,35 @@ int SegManager::initialiseScript(Script &scr, EngineState *s, int script_nr) {
int SegManager::deallocate(int seg, bool recursive) {
MemObject *mobj;
VERIFY(check(seg), "invalid seg id");
- int i;
mobj = _heap[seg];
id_seg_map->removeKey(mobj->getSegMgrId());
switch (mobj->getType()) {
case MEM_OBJ_SCRIPT:
- freeScript((*(Script *)mobj));
-
- (*(Script *)mobj).buf = NULL;
+ // FIXME: Get rid of the recursive flag, so that we can move the
+ // following into the destructor. The only time it is set to false
+ // is in the SegManager destructor.
if (recursive && (*(Script *)mobj).locals_segment)
deallocate((*(Script *)mobj).locals_segment, recursive);
break;
case MEM_OBJ_LOCALS:
- free((*(LocalVariables *)mobj).locals);
- (*(LocalVariables *)mobj).locals = NULL;
break;
case MEM_OBJ_DYNMEM:
- free((*(DynMem *)mobj).description);
- (*(DynMem *)mobj).description = NULL;
- free((*(DynMem *)mobj).buf);
- (*(DynMem *)mobj).buf = NULL;
break;
case MEM_OBJ_SYS_STRINGS:
- for (i = 0; i < SYS_STRINGS_MAX; i++) {
- SystemString *str = &(*(SystemStrings *)mobj).strings[i];
- if (str->name) {
- free(str->name);
- str->name = NULL;
-
- free(str->value);
- str->value = NULL;
-
- str->max_size = 0;
- }
- }
break;
case MEM_OBJ_STACK:
- free((*(dstack_t *)mobj).entries);
- (*(dstack_t *)mobj).entries = NULL;
break;
case MEM_OBJ_LISTS:
- free((*(ListTable *)mobj).table);
- (*(ListTable *)mobj).table = NULL;
- (*(ListTable *)mobj).entries_nr = (*(ListTable *)mobj).max_entry = 0;
break;
case MEM_OBJ_NODES:
- free((*(NodeTable *)mobj).table);
- (*(NodeTable *)mobj).table = NULL;
- (*(NodeTable *)mobj).entries_nr = (*(NodeTable *)mobj).max_entry = 0;
break;
case MEM_OBJ_CLONES:
- free((*(CloneTable *)mobj).table);
- (*(CloneTable *)mobj).table = NULL;
- (*(CloneTable *)mobj).entries_nr = (*(CloneTable *)mobj).max_entry = 0;
break;
case MEM_OBJ_HUNK:
- free((*(HunkTable *)mobj).table);
- (*(HunkTable *)mobj).table = NULL;
- (*(HunkTable *)mobj).entries_nr = (*(HunkTable *)mobj).max_entry = 0;
break;
case MEM_OBJ_STRING_FRAG:
break;
@@ -393,30 +360,28 @@ MemObject *SegManager::memObjAllocate(SegmentId segid, int hash_id, MemObjectTyp
return mem;
}
-void SegManager::freeScript(Script &scr) {
- if (scr.buf) {
- free(scr.buf);
- scr.buf = NULL;
- scr.buf_size = 0;
+void Script::freeScript() {
+ if (buf) {
+ free(buf);
+ buf = NULL;
+ buf_size = 0;
}
- if (scr.objects) {
- int i;
-
- for (i = 0; i < scr.objects_nr; i++) {
- Object* object = &scr.objects[i];
+ if (objects) {
+ for (int i = 0; i < objects_nr; i++) {
+ Object *object = &objects[i];
if (object->variables) {
free(object->variables);
object->variables = NULL;
object->variables_nr = 0;
}
}
- free(scr.objects);
- scr.objects = NULL;
- scr.objects_nr = 0;
+ free(objects);
+ objects = NULL;
+ objects_nr = 0;
}
- delete scr.obj_indices;
- free(scr.code);
+ delete obj_indices;
+ free(code);
}
// memory operations
@@ -979,12 +944,7 @@ dstack_t *SegManager::allocateStack(int size, SegmentId *segid) {
}
SystemStrings *SegManager::allocateSysStrings(SegmentId *segid) {
- MemObject *mobj = allocNonscriptSegment(MEM_OBJ_SYS_STRINGS, segid);
- SystemStrings *retval = (SystemStrings *)mobj;
-
- memset(retval->strings, 0, sizeof(retval->strings));
-
- return retval;
+ return (SystemStrings *)allocNonscriptSegment(MEM_OBJ_SYS_STRINGS, segid);
}
SegmentId SegManager::allocateStringFrags() {
@@ -1088,7 +1048,6 @@ Clone *SegManager::alloc_Clone(reg_t *addr) {
if (!Clones_seg_id) {
mobj = allocNonscriptSegment(MEM_OBJ_CLONES, &(Clones_seg_id));
- (*(CloneTable *)mobj).initTable();
} else
mobj = _heap[Clones_seg_id];
@@ -1106,7 +1065,6 @@ List *SegManager::alloc_List(reg_t *addr) {
if (!Lists_seg_id) {
mobj = allocNonscriptSegment(MEM_OBJ_LISTS, &(Lists_seg_id));
- (*(ListTable *)mobj).initTable();
} else
mobj = _heap[Lists_seg_id];
@@ -1124,7 +1082,6 @@ Node *SegManager::alloc_Node(reg_t *addr) {
if (!Nodes_seg_id) {
mobj = allocNonscriptSegment(MEM_OBJ_NODES, &(Nodes_seg_id));
- (*(NodeTable *)mobj).initTable();
} else
mobj = _heap[Nodes_seg_id];
@@ -1142,7 +1099,6 @@ Hunk *SegManager::alloc_Hunk(reg_t *addr) {
if (!Hunks_seg_id) {
mobj = allocNonscriptSegment(MEM_OBJ_HUNK, &(Hunks_seg_id));
- (*(HunkTable *)mobj).initTable();
} else
mobj = _heap[Hunks_seg_id];
@@ -1153,70 +1109,71 @@ Hunk *SegManager::alloc_Hunk(reg_t *addr) {
return &(table->table[offset]);
}
-
-
-byte *SegManager::dereference(reg_t pointer, int *size) {
- MemObject *mobj;
- byte *base = NULL;
- int count;
-
- if (!pointer.segment || (pointer.segment >= _heap.size()) || !_heap[pointer.segment]) {
- sciprintf("Error: Attempt to dereference invalid pointer "PREG"!\n",
+byte *MemObject::dereference(reg_t pointer, int *size) {
+ error("Error: Trying to dereference pointer "PREG" to inappropriate segment",
PRINT_REG(pointer));
- return NULL; /* Invalid */
+ return NULL;
+}
+
+byte *Script::dereference(reg_t pointer, int *size) {
+ if (pointer.offset > buf_size) {
+ sciprintf("Error: Attempt to dereference invalid pointer "PREG" 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);
+}
- mobj = _heap[pointer.segment];
+byte *LocalVariables::dereference(reg_t pointer, int *size) {
+ int count = nr * sizeof(reg_t);
+ byte *base = (byte *)locals;
- switch (mobj->getType()) {
- case MEM_OBJ_SCRIPT:
- if (pointer.offset > (*(Script *)mobj).buf_size) {
- sciprintf("Error: Attempt to dereference invalid pointer "PREG" into script segment (script size=%d)\n",
- PRINT_REG(pointer), (uint)(*(Script *)mobj).buf_size);
- return NULL;
- }
- if (size)
- *size = (*(Script *)mobj).buf_size - pointer.offset;
- return (byte *)((*(Script *)mobj).buf + pointer.offset);
- break;
+ if (size)
+ *size = count;
- case MEM_OBJ_LOCALS:
- count = (*(LocalVariables *)mobj).nr * sizeof(reg_t);
- base = (byte *)(*(LocalVariables *)mobj).locals;
- break;
+ return base + pointer.offset;
+}
- case MEM_OBJ_STACK:
- count = (*(dstack_t *)mobj).nr * sizeof(reg_t);
- base = (byte *)(*(dstack_t *)mobj).entries;
- break;
+byte *dstack_t::dereference(reg_t pointer, int *size) {
+ int count = nr * sizeof(reg_t);
+ byte *base = (byte *)entries;
- case MEM_OBJ_DYNMEM:
- count = (*(DynMem *)mobj).size;
- base = (byte *)(*(DynMem *)mobj).buf;
- break;
+ if (size)
+ *size = count;
- case MEM_OBJ_SYS_STRINGS:
- if (size)
- *size = (*(SystemStrings *)mobj).strings[pointer.offset].max_size;
- if (pointer.offset < SYS_STRINGS_MAX && (*(SystemStrings *)mobj).strings[pointer.offset].name)
- return (byte *)((*(SystemStrings *)mobj).strings[pointer.offset].value);
- else {
- sciprintf("Error: Attempt to dereference invalid pointer "PREG"!\n",
- PRINT_REG(pointer));
- return NULL;
- }
+ return base + pointer.offset;
+}
- default:
- error("Error: Trying to dereference pointer "PREG" to inappropriate segment",
- PRINT_REG(pointer));
- return NULL;
- }
+byte *DynMem::dereference(reg_t pointer, int *size) {
+ int count = _size;
+ byte *base = (byte *)_buf;
if (size)
*size = count;
- return
- base + pointer.offset;
+ 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);
+
+ error("Attempt to dereference invalid pointer "PREG"", PRINT_REG(pointer));
+ return NULL;
+}
+
+byte *SegManager::dereference(reg_t pointer, int *size) {
+ if (!pointer.segment || (pointer.segment >= _heap.size()) || !_heap[pointer.segment]) {
+ error("Attempt to dereference invalid pointer "PREG"", PRINT_REG(pointer));
+ return NULL; /* Invalid */
+ }
+
+ MemObject *mobj = _heap[pointer.segment];
+ return mobj->dereference(pointer, size);
}
unsigned char *SegManager::allocDynmem(int size, const char *descr, reg_t *addr) {
@@ -1226,16 +1183,16 @@ unsigned char *SegManager::allocDynmem(int size, const char *descr, reg_t *addr)
DynMem &d = *(DynMem *)mobj;
- d.size = size;
+ d._size = size;
if (size == 0)
- d.buf = NULL;
+ d._buf = NULL;
else
- d.buf = (byte *)sci_malloc(size);
+ d._buf = (byte *)sci_malloc(size);
- d.description = sci_strdup(descr);
+ d._description = sci_strdup(descr);
- return (unsigned char *)(d.buf);
+ return (unsigned char *)(d._buf);
}
const char *SegManager::getDescription(reg_t addr) {
@@ -1246,7 +1203,7 @@ const char *SegManager::getDescription(reg_t addr) {
switch (mobj->getType()) {
case MEM_OBJ_DYNMEM:
- return (*(DynMem *)mobj).description;
+ return (*(DynMem *)mobj)._description;
default:
return "";
}
diff --git a/engines/sci/engine/seg_manager.h b/engines/sci/engine/seg_manager.h
index 6a2cc14e65..c76d056383 100644
--- a/engines/sci/engine/seg_manager.h
+++ b/engines/sci/engine/seg_manager.h
@@ -62,15 +62,13 @@ public:
// 1. Scripts
- void freeScript(Script &scr);
-
// Allocate a script into the segment manager
// Parameters: (int) script_nr: number of the script to load
// (state_t *) s: The state containing resource manager handlers to load the
// script data
// Returns : (int) 0 on failure, 1 on success
// (int) *seg_id: The segment ID of the newly allocated segment, on success
- MemObject *allocateScript(EngineState *s, int script_nr, int* seg_id);
+ Script *allocateScript(EngineState *s, int script_nr, int* seg_id);
// The script must then be initialised; see section (1b.), below.
diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp
index 079be6975f..7f997d62d3 100644
--- a/engines/sci/engine/vm.cpp
+++ b/engines/sci/engine/vm.cpp
@@ -1667,7 +1667,6 @@ int script_instantiate_common(EngineState *s, int script_nr, Resource **script,
int seg;
int seg_id;
int marked_for_deletion;
- MemObject *mem;
reg_t reg;
*was_new = 1;
@@ -1693,6 +1692,7 @@ int script_instantiate_common(EngineState *s, int script_nr, Resource **script,
return 0;
}
+ Script *scr = 0;
seg = s->seg_manager->segGet(script_nr);
if (s->seg_manager->scriptIsLoaded(script_nr, SCRIPT_ID)) {
marked_for_deletion = s->seg_manager->scriptMarkedDeleted(script_nr);
@@ -1701,17 +1701,17 @@ int script_instantiate_common(EngineState *s, int script_nr, Resource **script,
return seg;
} else {
seg_id = seg;
- mem = s->seg_manager->_heap[seg];
- assert(mem);
- s->seg_manager->freeScript(*(Script *)mem);
+ scr = (Script *)s->seg_manager->_heap[seg];
+ assert(scr);
+ scr->freeScript();
}
- } else if (!(mem = s->seg_manager->allocateScript(s, script_nr, &seg_id))) { // ALL YOUR SCRIPT BASE ARE BELONG TO US
+ } else if (!(scr = s->seg_manager->allocateScript(s, script_nr, &seg_id))) { // ALL YOUR SCRIPT BASE ARE BELONG TO US
sciprintf("Not enough heap space for script size 0x%x of script 0x%x, should this happen?`\n", (*script)->size, script_nr);
script_debug_flag = script_error_flag = 1;
return 0;
}
- s->seg_manager->initialiseScript(*(Script *)mem, s, script_nr);
+ s->seg_manager->initialiseScript(*scr, s, script_nr);
reg.segment = seg_id;
reg.offset = 0;
diff --git a/engines/sci/engine/vm.h b/engines/sci/engine/vm.h
index f036ccb496..5576d98871 100644
--- a/engines/sci/engine/vm.h
+++ b/engines/sci/engine/vm.h
@@ -28,6 +28,7 @@
/* VM and kernel declarations */
+//#include "common/serializer.h"
#include "sci/scicore/versions.h" // for sci_version_t
#include "sci/engine/vm_types.h" // for reg_t
#include "sci/engine/heapmgr.h"
@@ -50,10 +51,15 @@ enum MemObjectType {
MEM_OBJ_MAX // For sanity checking
};
-struct MemObject {
+struct MemObject /* : public Common::Serializable */ {
MemObjectType _type;
int _segmgrId; /**< Internal value used by the seg_manager's hash map */
+public:
+ virtual ~MemObject() {}
+
+ virtual byte *dereference(reg_t pointer, int *size);
+
inline MemObjectType getType() const { return _type; }
inline int getSegMgrId() const { return _segmgrId; }
@@ -80,6 +86,29 @@ struct SystemString {
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 */
@@ -180,6 +209,21 @@ struct LocalVariables : public MemObject {
int script_id; /**< Script ID this local variable block belongs to */
reg_t *locals;
int nr;
+
+public:
+ LocalVariables() {
+ script_id = 0;
+ locals = 0;
+ nr = 0;
+ }
+ ~LocalVariables() {
+ free(locals);
+ locals = NULL;
+ }
+
+ virtual byte *dereference(reg_t pointer, int *size);
+
+// virtual void saveLoadWithSerializer(Common::Serializer &ser);
};
/** Clone has been marked as 'freed' */
@@ -227,7 +271,7 @@ struct CodeBlock {
struct Script : public MemObject {
int nr; /**< Script number */
- byte* buf; /**< Static data buffer, or NULL if not used */
+ byte *buf; /**< Static data buffer, or NULL if not used */
size_t buf_size;
size_t script_size;
size_t heap_size;
@@ -257,12 +301,65 @@ struct Script : public MemObject {
int code_blocks_allocated;
int relocated;
int marked_as_deleted;
+
+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;
+
+ objects = NULL;
+ objects_allocated = 0;
+ objects_nr = 0;
+
+ locals_offset = 0;
+ locals_segment = 0;
+ locals_block = NULL;
+
+ code = NULL;
+ code_blocks_nr = 0;
+ code_blocks_allocated = 0;
+ relocated = 0;
+ marked_as_deleted = 0;
+ }
+
+ ~Script() {
+ freeScript();
+ }
+
+ virtual byte *dereference(reg_t pointer, int *size);
+
+// virtual void saveLoadWithSerializer(Common::Serializer &ser);
+
+ void freeScript();
};
/** Data stack */
struct dstack_t : MemObject {
int nr; /**< Number of stack entries */
reg_t *entries;
+
+public:
+ dstack_t() {
+ nr = 0;
+ entries = NULL;
+ }
+ ~dstack_t() {
+ free(entries);
+ entries = NULL;
+ }
+
+ virtual byte *dereference(reg_t pointer, int *size);
+
+// virtual void saveLoadWithSerializer(Common::Serializer &ser);
};
#define CLONE_USED -1
@@ -301,6 +398,20 @@ struct Table : public MemObject {
Entry *table;
+public:
+ Table() {
+ initTable();
+ }
+ ~Table() {
+ // FIXME: Shouldn't we make sure that all table entries are disposed
+ // of properly?
+ free(table);
+ table = NULL;
+ entries_nr = max_entry = 0;
+ }
+
+// virtual void saveLoadWithSerializer(Common::Serializer &ser);
+
void initTable() {
entries_nr = INITIAL;
max_entry = 0;
@@ -352,9 +463,22 @@ void free_Hunk_entry(HunkTable *table, int index);
// Free-style memory
struct DynMem : public MemObject {
- int size;
- char *description;
- byte *buf;
+ 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 void saveLoadWithSerializer(Common::Serializer &ser);
};
/** Contains selector IDs for a few selected selectors */