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

thebluegr at users.sourceforge.net thebluegr at users.sourceforge.net
Sun Jun 27 22:38:43 CEST 2010


Revision: 50396
          http://scummvm.svn.sourceforge.net/scummvm/?rev=50396&view=rev
Author:   thebluegr
Date:     2010-06-27 20:38:43 +0000 (Sun, 27 Jun 2010)

Log Message:
-----------
SCI: Moved all the script-related code inside script.cpp/.h, and all script opcode-related code inside vm.cpp/.h

Modified Paths:
--------------
    scummvm/trunk/engines/sci/engine/kscripts.cpp
    scummvm/trunk/engines/sci/engine/script.cpp
    scummvm/trunk/engines/sci/engine/script.h
    scummvm/trunk/engines/sci/engine/seg_manager.cpp
    scummvm/trunk/engines/sci/engine/seg_manager.h
    scummvm/trunk/engines/sci/engine/segment.cpp
    scummvm/trunk/engines/sci/engine/segment.h
    scummvm/trunk/engines/sci/engine/vm.cpp
    scummvm/trunk/engines/sci/engine/vm.h

Modified: scummvm/trunk/engines/sci/engine/kscripts.cpp
===================================================================
--- scummvm/trunk/engines/sci/engine/kscripts.cpp	2010-06-27 20:38:41 UTC (rev 50395)
+++ scummvm/trunk/engines/sci/engine/kscripts.cpp	2010-06-27 20:38:43 UTC (rev 50396)
@@ -25,6 +25,8 @@
 
 #include "sci/sci.h"
 #include "sci/resource.h"
+#include "sci/engine/seg_manager.h"
+#include "sci/engine/script.h"
 #include "sci/engine/state.h"
 #include "sci/engine/selector.h"
 #include "sci/engine/kernel.h"

Modified: scummvm/trunk/engines/sci/engine/script.cpp
===================================================================
--- scummvm/trunk/engines/sci/engine/script.cpp	2010-06-27 20:38:41 UTC (rev 50395)
+++ scummvm/trunk/engines/sci/engine/script.cpp	2010-06-27 20:38:43 UTC (rev 50396)
@@ -35,129 +35,355 @@
 
 namespace Sci {
 
-#define END Script_None
+Script::Script() : SegmentObj(SEG_TYPE_SCRIPT) {
+	_nr = 0;
+	_buf = NULL;
+	_bufSize = 0;
+	_scriptSize = 0;
+	_heapSize = 0;
 
-opcode_format g_opcode_formats[128][4] = {
-	/*00*/
-	{Script_None}, {Script_None}, {Script_None}, {Script_None},
-	/*04*/
-	{Script_None}, {Script_None}, {Script_None}, {Script_None},
-	/*08*/
-	{Script_None}, {Script_None}, {Script_None}, {Script_None},
-	/*0C*/
-	{Script_None}, {Script_None}, {Script_None}, {Script_None},
-	/*10*/
-	{Script_None}, {Script_None}, {Script_None}, {Script_None},
-	/*14*/
-	{Script_None}, {Script_None}, {Script_None}, {Script_SRelative, END},
-	/*18*/
-	{Script_SRelative, END}, {Script_SRelative, END}, {Script_SVariable, END}, {Script_None},
-	/*1C*/
-	{Script_SVariable, END}, {Script_None}, {Script_None}, {Script_Variable, END},
-	/*20*/
-	{Script_SRelative, Script_Byte, END}, {Script_Variable, Script_Byte, END}, {Script_Variable, Script_Byte, END}, {Script_Variable, Script_SVariable, Script_Byte, END},
-	/*24 (24=ret)*/
-	{Script_End}, {Script_Byte, END}, {Script_Invalid}, {Script_Invalid},
-	/*28*/
-	{Script_Variable, END}, {Script_Invalid}, {Script_Byte, END}, {Script_Variable, Script_Byte, END},
-	/*2C*/
-	{Script_SVariable, END}, {Script_SVariable, Script_Variable, END}, {Script_None}, {Script_Invalid},
-	/*30*/
-	{Script_None}, {Script_Property, END}, {Script_Property, END}, {Script_Property, END},
-	/*34*/
-	{Script_Property, END}, {Script_Property, END}, {Script_Property, END}, {Script_Property, END},
-	/*38*/
-	{Script_Property, END}, {Script_SRelative, END}, {Script_SRelative, END}, {Script_None},
-	/*3C*/
-	{Script_None}, {Script_None}, {Script_None}, {Script_Word},
-	/*40-4F*/
-	{Script_Global, END}, {Script_Local, END}, {Script_Temp, END}, {Script_Param, END},
-	{Script_Global, END}, {Script_Local, END}, {Script_Temp, END}, {Script_Param, END},
-	{Script_Global, END}, {Script_Local, END}, {Script_Temp, END}, {Script_Param, END},
-	{Script_Global, END}, {Script_Local, END}, {Script_Temp, END}, {Script_Param, END},
-	/*50-5F*/
-	{Script_Global, END}, {Script_Local, END}, {Script_Temp, END}, {Script_Param, END},
-	{Script_Global, END}, {Script_Local, END}, {Script_Temp, END}, {Script_Param, END},
-	{Script_Global, END}, {Script_Local, END}, {Script_Temp, END}, {Script_Param, END},
-	{Script_Global, END}, {Script_Local, END}, {Script_Temp, END}, {Script_Param, END},
-	/*60-6F*/
-	{Script_Global, END}, {Script_Local, END}, {Script_Temp, END}, {Script_Param, END},
-	{Script_Global, END}, {Script_Local, END}, {Script_Temp, END}, {Script_Param, END},
-	{Script_Global, END}, {Script_Local, END}, {Script_Temp, END}, {Script_Param, END},
-	{Script_Global, END}, {Script_Local, END}, {Script_Temp, END}, {Script_Param, END},
-	/*70-7F*/
-	{Script_Global, END}, {Script_Local, END}, {Script_Temp, END}, {Script_Param, END},
-	{Script_Global, END}, {Script_Local, END}, {Script_Temp, END}, {Script_Param, END},
-	{Script_Global, END}, {Script_Local, END}, {Script_Temp, END}, {Script_Param, END},
-	{Script_Global, END}, {Script_Local, END}, {Script_Temp, END}, {Script_Param, END}
-};
-#undef END
+	_synonyms = NULL;
+	_heapStart = NULL;
+	_exportTable = NULL;
 
-// TODO: script_adjust_opcode_formats should probably be part of the
-// constructor (?) of a VirtualMachine or a ScriptManager class.
-void script_adjust_opcode_formats() {
-	if (g_sci->_features->detectLofsType() != SCI_VERSION_0_EARLY) {
-		g_opcode_formats[op_lofsa][0] = Script_Offset;
-		g_opcode_formats[op_lofss][0] = Script_Offset;
+	_localsOffset = 0;
+	_localsSegment = 0;
+	_localsBlock = NULL;
+	_localsCount = 0;
+
+	_markedAsDeleted = false;
+}
+
+Script::~Script() {
+	freeScript();
+}
+
+void Script::freeScript() {
+	free(_buf);
+	_buf = NULL;
+	_bufSize = 0;
+
+	_objects.clear();
+}
+
+void Script::init(int script_nr, ResourceManager *resMan) {
+	Resource *script = resMan->findResource(ResourceId(kResourceTypeScript, script_nr), 0);
+
+	_localsOffset = 0;
+	_localsBlock = NULL;
+	_localsCount = 0;
+
+	_markedAsDeleted = false;
+
+	_nr = script_nr;
+	_buf = 0;
+	_heapStart = 0;
+
+	_scriptSize = script->size;
+	_bufSize = script->size;
+	_heapSize = 0;
+
+	_lockers = 1;
+
+	if (getSciVersion() == SCI_VERSION_0_EARLY) {
+		_bufSize += READ_LE_UINT16(script->data) * 2;
+	} else if (getSciVersion() >= SCI_VERSION_1_1) {
+		/**
+		 * In SCI11, the heap was in a separate space from the script.
+		 * We append it to the end of the script, and adjust addressing accordingly.
+		 * However, since we address the heap with a 16-bit pointer, the combined
+		 * size of the stack and the heap must be 64KB. So far this has worked
+		 * for SCI11, SCI2 and SCI21 games. SCI3 games use a different script format,
+		 * and theoretically they can exceed the 64KB boundary using relocation.
+		 */
+		Resource *heap = resMan->findResource(ResourceId(kResourceTypeHeap, script_nr), 0);
+		_bufSize += heap->size;
+		_heapSize = heap->size;
+
+		// Ensure that the start of the heap resource can be word-aligned.
+		if (script->size & 2) {
+			_bufSize++;
+			_scriptSize++;
+		}
+
+		// As mentioned above, the script and the heap together should not exceed 64KB
+		if (script->size + heap->size > 65535)
+			error("Script and heap sizes combined exceed 64K. This means a fundamental "
+					"design bug was made regarding SCI1.1 and newer games.\nPlease "
+					"report this error to the ScummVM team");
 	}
+}
 
-#ifdef ENABLE_SCI32
-	// In SCI32, some arguments are now words instead of bytes
-	if (getSciVersion() >= SCI_VERSION_2) {
-		g_opcode_formats[op_calle][2] = Script_Word;
-		g_opcode_formats[op_callk][1] = Script_Word;
-		g_opcode_formats[op_super][1] = Script_Word;
-		g_opcode_formats[op_send][0] = Script_Word;
-		g_opcode_formats[op_self][0] = Script_Word;
-		g_opcode_formats[op_call][1] = Script_Word;
-		g_opcode_formats[op_callb][1] = Script_Word;
+void Script::load(ResourceManager *resMan) {
+	Resource *script = resMan->findResource(ResourceId(kResourceTypeScript, _nr), 0);
+	assert(script != 0);
+
+	_buf = (byte *)malloc(_bufSize);
+	assert(_buf);
+
+	assert(_bufSize >= script->size);
+	memcpy(_buf, script->data, script->size);
+
+	if (getSciVersion() >= SCI_VERSION_1_1) {
+		Resource *heap = resMan->findResource(ResourceId(kResourceTypeHeap, _nr), 0);
+		assert(heap != 0);
+
+		_heapStart = _buf + _scriptSize;
+
+		assert(_bufSize - _scriptSize <= heap->size);
+		memcpy(_heapStart, heap->data, heap->size);
 	}
-#endif
+
+	_exportTable = 0;
+	_numExports = 0;
+	_synonyms = 0;
+	_numSynonyms = 0;
+	
+	if (getSciVersion() >= SCI_VERSION_1_1) {
+		if (READ_LE_UINT16(_buf + 1 + 5) > 0) {	// does the script have an export table?
+			_exportTable = (const uint16 *)(_buf + 1 + 5 + 2);
+			_numExports = READ_SCI11ENDIAN_UINT16(_exportTable - 1);
+		}
+		_localsOffset = _scriptSize + 4;
+		_localsCount = READ_SCI11ENDIAN_UINT16(_buf + _localsOffset - 2);
+	} else {
+		_exportTable = (const uint16 *)findBlock(SCI_OBJ_EXPORTS);
+		if (_exportTable) {
+			_numExports = READ_SCI11ENDIAN_UINT16(_exportTable + 1);
+			_exportTable += 3;	// skip header plus 2 bytes (_exportTable is a uint16 pointer)
+		}
+		_synonyms = findBlock(SCI_OBJ_SYNONYMS);
+		if (_synonyms) {
+			_numSynonyms = READ_SCI11ENDIAN_UINT16(_synonyms + 2) / 4;
+			_synonyms += 4;	// skip header
+		}
+		const byte* localsBlock = findBlock(SCI_OBJ_LOCALVARS);
+		if (localsBlock) {
+			_localsOffset = localsBlock - _buf + 4;
+			_localsCount = (READ_LE_UINT16(_buf + _localsOffset - 2) - 4) >> 1;	// half block size
+		}
+	}
+
+	if (getSciVersion() > SCI_VERSION_0_EARLY) {
+		// Does the script actually have locals? If not, set the locals offset to 0
+		if (!_localsCount)
+			_localsOffset = 0;
+
+		if (_localsOffset + _localsCount * 2 + 1 >= (int)_bufSize) {
+			error("Locals extend beyond end of script: offset %04x, count %d vs size %d", _localsOffset, _localsCount, _bufSize);
+			_localsCount = (_bufSize - _localsOffset) >> 1;
+		}
+	} else {
+		// Old script block. There won't be a localvar block in this case.
+		// Instead, the script starts with a 16 bit int specifying the
+		// number of locals we need; these are then allocated and zeroed.
+		_localsCount = READ_LE_UINT16(_buf);
+		_localsOffset = -_localsCount * 2; // Make sure it's invalid
+	}
 }
 
-void SegManager::createClassTable() {
-	Resource *vocab996 = _resMan->findResource(ResourceId(kResourceTypeVocab, 996), 1);
+Object *Script::allocateObject(uint16 offset) {
+	return &_objects[offset];
+}
 
-	if (!vocab996)
-		error("SegManager: failed to open vocab 996");
+Object *Script::getObject(uint16 offset) {
+	if (_objects.contains(offset))
+		return &_objects[offset];
+	else
+		return 0;
+}
 
-	int totalClasses = vocab996->size >> 2;
-	_classTable.resize(totalClasses);
+const Object *Script::getObject(uint16 offset) const {
+	if (_objects.contains(offset))
+		return &_objects[offset];
+	else
+		return 0;
+}
 
-	for (uint16 classNr = 0; classNr < totalClasses; classNr++) {
-		uint16 scriptNr = READ_SCI11ENDIAN_UINT16(vocab996->data + classNr * 4 + 2);
+Object *Script::scriptObjInit(reg_t obj_pos, bool fullObjectInit) {
+	Object *obj;
 
-		_classTable[classNr].reg = NULL_REG;
-		_classTable[classNr].script = scriptNr;
+	if (getSciVersion() < SCI_VERSION_1_1 && fullObjectInit)
+		obj_pos.offset += 8;	// magic offset (SCRIPT_OBJECT_MAGIC_OFFSET)
+
+	VERIFY(obj_pos.offset < _bufSize, "Attempt to initialize object beyond end of script\n");
+
+	obj = allocateObject(obj_pos.offset);
+
+	VERIFY(obj_pos.offset + kOffsetFunctionArea < (int)_bufSize, "Function area pointer stored beyond end of script\n");
+
+	obj->init(_buf, obj_pos, fullObjectInit);
+
+	return obj;
+}
+
+void Script::scriptObjRemove(reg_t obj_pos) {
+	if (getSciVersion() < SCI_VERSION_1_1)
+		obj_pos.offset += 8;
+
+	_objects.erase(obj_pos.toUint16());
+}
+
+// This helper function is used by Script::relocateLocal and Object::relocate
+// Duplicate in segment.cpp and script.cpp
+static bool relocateBlock(Common::Array<reg_t> &block, int block_location, SegmentId segment, int location, size_t scriptSize) {
+	int rel = location - block_location;
+
+	if (rel < 0)
+		return false;
+
+	uint idx = rel >> 1;
+
+	if (idx >= block.size())
+		return false;
+
+	if (rel & 1) {
+		error("Attempt to relocate odd variable #%d.5e (relative to %04x)\n", idx, block_location);
+		return false;
 	}
+	block[idx].segment = segment; // Perform relocation
+	if (getSciVersion() >= SCI_VERSION_1_1)
+		block[idx].offset += scriptSize;
 
-	_resMan->unlockResource(vocab996);
+	return true;
 }
 
-reg_t SegManager::getClassAddress(int classnr, ScriptLoadType lock, reg_t caller) {
-	if (classnr == 0xffff)
-		return NULL_REG;
+bool Script::relocateLocal(SegmentId segment, int location) {
+	if (_localsBlock)
+		return relocateBlock(_localsBlock->_locals, _localsOffset, segment, location, _scriptSize);
+	else
+		return false;
+}
 
-	if (classnr < 0 || (int)_classTable.size() <= classnr || _classTable[classnr].script < 0) {
-		error("[VM] Attempt to dereference class %x, which doesn't exist (max %x)", classnr, _classTable.size());
-		return NULL_REG;
-	} else {
-		Class *the_class = &_classTable[classnr];
-		if (!the_class->reg.segment) {
-			getScriptSegment(the_class->script, lock);
+void Script::relocate(reg_t block) {
+	byte *heap = _buf;
+	uint16 heapSize = (uint16)_bufSize;
+	uint16 heapOffset = 0;
 
-			if (!the_class->reg.segment) {
-				error("[VM] Trying to instantiate class %x by instantiating script 0x%x (%03d) failed;", classnr, the_class->script, the_class->script);
-				return NULL_REG;
-			}
-		} else
-			if (caller.segment != the_class->reg.segment)
-				getScript(the_class->reg.segment)->incrementLockers();
+	if (getSciVersion() >= SCI_VERSION_1_1) {
+		heap = _heapStart;
+		heapSize = (uint16)_heapSize;
+		heapOffset = _scriptSize;
+	}
 
-		return the_class->reg;
+	VERIFY(block.offset < (uint16)heapSize && READ_SCI11ENDIAN_UINT16(heap + block.offset) * 2 + block.offset < (uint16)heapSize,
+	       "Relocation block outside of script\n");
+
+	int count = READ_SCI11ENDIAN_UINT16(heap + block.offset);
+	int exportIndex = 0;
+	int pos = 0;
+
+	for (int i = 0; i < count; i++) {
+		pos = READ_SCI11ENDIAN_UINT16(heap + block.offset + 2 + (exportIndex * 2)) + heapOffset;
+		// This occurs in SCI01/SCI1 games where usually one export value
+		// is zero. It seems that in this situation, we should skip the
+		// export and move to the next one, though the total count of valid
+		// exports remains the same
+		if (!pos) {
+			exportIndex++;
+			pos = READ_SCI11ENDIAN_UINT16(heap + block.offset + 2 + (exportIndex * 2)) + heapOffset;
+			if (!pos)
+				error("Script::relocate(): Consecutive zero exports found");
+		}
+
+		// In SCI0-SCI1, script local variables, objects and code are relocated. We only relocate
+		// locals and objects here, and ignore relocation of code blocks. In SCI1.1 and newer
+		// versions, only locals and objects are relocated.
+		if (!relocateLocal(block.segment, pos)) {
+			// Not a local? It's probably an object or code block. If it's an object, relocate it.
+			const ObjMap::iterator end = _objects.end();
+			for (ObjMap::iterator it = _objects.begin(); it != end; ++it)
+				if (it->_value.relocate(block.segment, pos, _scriptSize))
+					break;
+		}
+
+		exportIndex++;
 	}
 }
 
+void Script::incrementLockers() {
+	_lockers++;
+}
+
+void Script::decrementLockers() {
+	if (_lockers > 0)
+		_lockers--;
+}
+
+int Script::getLockers() const {
+	return _lockers;
+}
+
+void Script::setLockers(int lockers) {
+	_lockers = lockers;
+}
+
+uint16 Script::validateExportFunc(int pubfunct) {
+	bool exportsAreWide = (g_sci->_features->detectLofsType() == SCI_VERSION_1_MIDDLE);
+
+	if (_numExports <= pubfunct) {
+		error("validateExportFunc(): pubfunct is invalid");
+		return 0;
+	}
+
+	if (exportsAreWide)
+		pubfunct *= 2;
+	uint16 offset = READ_SCI11ENDIAN_UINT16(_exportTable + pubfunct);
+	VERIFY(offset < _bufSize, "invalid export function pointer");
+
+	return offset;
+}
+
+byte *Script::findBlock(int type) {
+	byte *buf = _buf;
+	bool oldScriptHeader = (getSciVersion() == SCI_VERSION_0_EARLY);
+
+	if (oldScriptHeader)
+		buf += 2;
+
+	do {
+		int seekerType = READ_LE_UINT16(buf);
+
+		if (seekerType == 0)
+			break;
+		if (seekerType == type)
+			return buf;
+
+		int seekerSize = READ_LE_UINT16(buf + 2);
+		assert(seekerSize > 0);
+		buf += seekerSize;
+	} while (1);
+
+	return NULL;
+}
+
+// memory operations
+
+void Script::mcpyInOut(int dst, const void *src, size_t n) {
+	if (_buf) {
+		assert(dst + n <= _bufSize);
+		memcpy(_buf + dst, src, n);
+	}
+}
+
+bool Script::isValidOffset(uint16 offset) const {
+	return offset < _bufSize;
+}
+
+SegmentRef Script::dereference(reg_t pointer) {
+	if (pointer.offset > _bufSize) {
+		error("Script::dereference(): Attempt to dereference invalid pointer %04x:%04x into script segment (script size=%d)",
+				  PRINT_REG(pointer), (uint)_bufSize);
+		return SegmentRef();
+	}
+
+	SegmentRef ret;
+	ret.isRaw = true;
+	ret.maxSize = _bufSize - pointer.offset;
+	ret.raw = _buf + pointer.offset;
+	return ret;
+}
+
 void SegManager::scriptInitialiseLocals(SegmentId segmentId) {
 	Script *scr = getScript(segmentId);
 

Modified: scummvm/trunk/engines/sci/engine/script.h
===================================================================
--- scummvm/trunk/engines/sci/engine/script.h	2010-06-27 20:38:41 UTC (rev 50395)
+++ scummvm/trunk/engines/sci/engine/script.h	2010-06-27 20:38:43 UTC (rev 50396)
@@ -27,6 +27,7 @@
 #define SCI_ENGINE_SCRIPT_H
 
 #include "common/str.h"
+#include "sci/engine/segment.h"
 
 namespace Sci {
 
@@ -49,160 +50,205 @@
 	SCI_OBJ_LOCALVARS
 };
 
-// Opcode formats
-enum opcode_format {
-	Script_Invalid = -1,
-	Script_None = 0,
-	Script_Byte,
-	Script_SByte,
-	Script_Word,
-	Script_SWord,
-	Script_Variable,
-	Script_SVariable,
-	Script_SRelative,
-	Script_Property,
-	Script_Global,
-	Script_Local,
-	Script_Temp,
-	Script_Param,
-	Script_Offset,
-	Script_End
-};
+typedef Common::HashMap<uint16, Object> ObjMap;
 
-enum sci_opcodes {
-	op_bnot     = 0x00,	// 000
-	op_add      = 0x01,	// 001
-	op_sub      = 0x02,	// 002
-	op_mul      = 0x03,	// 003
-	op_div      = 0x04,	// 004
-	op_mod      = 0x05,	// 005
-	op_shr      = 0x06,	// 006
-	op_shl      = 0x07,	// 007
-	op_xor      = 0x08,	// 008
-	op_and      = 0x09,	// 009
-	op_or       = 0x0a,	// 010
-	op_neg      = 0x0b,	// 011
-	op_not      = 0x0c,	// 012
-	op_eq_      = 0x0d,	// 013
-	op_ne_      = 0x0e,	// 014
-	op_gt_      = 0x0f,	// 015
-	op_ge_      = 0x10,	// 016
-	op_lt_      = 0x11,	// 017
-	op_le_      = 0x12,	// 018
-	op_ugt_     = 0x13,	// 019
-	op_uge_     = 0x14,	// 020
-	op_ult_     = 0x15,	// 021
-	op_ule_     = 0x16,	// 022
-	op_bt       = 0x17,	// 023
-	op_bnt      = 0x18,	// 024
-	op_jmp      = 0x19,	// 025
-	op_ldi      = 0x1a,	// 026
-	op_push     = 0x1b,	// 027
-	op_pushi    = 0x1c,	// 028
-	op_toss     = 0x1d,	// 029
-	op_dup      = 0x1e,	// 030
-	op_link     = 0x1f,	// 031
-	op_call     = 0x20,	// 032
-	op_callk    = 0x21,	// 033
-	op_callb    = 0x22,	// 034
-	op_calle    = 0x23,	// 035
-	op_ret      = 0x24,	// 036
-	op_send     = 0x25,	// 037
-	// dummy      0x26,	// 038
-	// dummy      0x27,	// 039
-	op_class    = 0x28,	// 040
-	// dummy      0x29,	// 041
-	op_self     = 0x2a,	// 042
-	op_super    = 0x2b,	// 043
-	op_rest     = 0x2c,	// 044
-	op_lea      = 0x2d,	// 045
-	op_selfID   = 0x2e,	// 046
-	// dummy      0x2f	// 047
-	op_pprev    = 0x30,	// 048
-	op_pToa     = 0x31,	// 049
-	op_aTop     = 0x32,	// 050
-	op_pTos     = 0x33,	// 051
-	op_sTop     = 0x34,	// 052
-	op_ipToa    = 0x35,	// 053
-	op_dpToa    = 0x36,	// 054
-	op_ipTos    = 0x37,	// 055
-	op_dpTos    = 0x38,	// 056
-	op_lofsa    = 0x39,	// 057
-	op_lofss    = 0x3a,	// 058
-	op_push0    = 0x3b,	// 059
-	op_push1    = 0x3c,	// 060
-	op_push2    = 0x3d,	// 061
-	op_pushSelf = 0x3e,	// 062
-	op_line     = 0x3f,	// 063
-	op_lag      = 0x40,	// 064
-	op_lal      = 0x41,	// 065
-	op_lat      = 0x42,	// 066
-	op_lap      = 0x43,	// 067
-	op_lsg      = 0x44,	// 068
-	op_lsl      = 0x45,	// 069
-	op_lst      = 0x46,	// 070
-	op_lsp      = 0x47,	// 071
-	op_lagi     = 0x48,	// 072
-	op_lali     = 0x49,	// 073
-	op_lati     = 0x4a,	// 074
-	op_lapi     = 0x4b,	// 075
-	op_lsgi     = 0x4c,	// 076
-	op_lsli     = 0x4d,	// 077
-	op_lsti     = 0x4e,	// 078
-	op_lspi     = 0x4f,	// 079
-	op_sag      = 0x50,	// 080
-	op_sal      = 0x51,	// 081
-	op_sat      = 0x52,	// 082
-	op_sap      = 0x53,	// 083
-	op_ssg      = 0x54,	// 084
-	op_ssl      = 0x55,	// 085
-	op_sst      = 0x56,	// 086
-	op_ssp      = 0x57,	// 087
-	op_sagi     = 0x58,	// 088
-	op_sali     = 0x59,	// 089
-	op_sati     = 0x5a,	// 090
-	op_sapi     = 0x5b,	// 091
-	op_ssgi     = 0x5c,	// 092
-	op_ssli     = 0x5d,	// 093
-	op_ssti     = 0x5e,	// 094
-	op_sspi     = 0x5f,	// 095
-	op_plusag   = 0x60,	// 096
-	op_plusal   = 0x61,	// 097
-	op_plusat   = 0x62,	// 098
-	op_plusap   = 0x63,	// 099
-	op_plussg   = 0x64,	// 100
-	op_plussl   = 0x65,	// 101
-	op_plusst   = 0x66,	// 102
-	op_plussp   = 0x67,	// 103
-	op_plusagi  = 0x68,	// 104
-	op_plusali  = 0x69,	// 105
-	op_plusati  = 0x6a,	// 106
-	op_plusapi  = 0x6b,	// 107
-	op_plussgi  = 0x6c,	// 108
-	op_plussli  = 0x6d,	// 109
-	op_plussti  = 0x6e,	// 110
-	op_plusspi  = 0x6f,	// 111
-	op_minusag  = 0x70,	// 112
-	op_minusal  = 0x71,	// 113
-	op_minusat  = 0x72,	// 114
-	op_minusap  = 0x73,	// 115
-	op_minussg  = 0x74,	// 116
-	op_minussl  = 0x75,	// 117
-	op_minusst  = 0x76,	// 118
-	op_minussp  = 0x77,	// 119
-	op_minusagi = 0x78,	// 120
-	op_minusali = 0x79,	// 121
-	op_minusati = 0x7a,	// 122
-	op_minusapi = 0x7b,	// 123
-	op_minussgi = 0x7c,	// 124
-	op_minussli = 0x7d,	// 125
-	op_minussti = 0x7e,	// 126
-	op_minusspi = 0x7f	// 127
+class Script : public SegmentObj {
+public:
+	int _nr; /**< Script number */
+	byte *_buf; /**< Static data buffer, or NULL if not used */
+	byte *_heapStart; /**< Start of heap if SCI1.1, NULL otherwise */
+
+	uint32 getScriptSize() { return _scriptSize; }
+	uint32 getHeapSize() { return _heapSize; }
+	uint32 getBufSize() { return _bufSize; }
+
+protected:
+	int _lockers; /**< Number of classes and objects that require this script */
+
+private:
+	size_t _scriptSize;
+	size_t _heapSize;
+	uint16 _bufSize;
+
+	const uint16 *_exportTable; /**< Abs. offset of the export table or 0 if not present */
+	uint16 _numExports; /**< Number of entries in the exports table */
+
+	const byte *_synonyms; /**< Synonyms block or 0 if not present*/
+	uint16 _numSynonyms; /**< Number of entries in the synonyms block */
+
+	int _localsOffset;
+	uint16 _localsCount;
+
+public:
+	/**
+	 * Table for objects, contains property variables.
+	 * Indexed by the TODO offset.
+	 */
+	ObjMap _objects;
+
+	int getLocalsOffset() const { return _localsOffset; }
+	uint16 getLocalsCount() const { return _localsCount; }
+	SegmentId _localsSegment; /**< The local variable segment */
+	LocalVariables *_localsBlock;
+
+	bool _markedAsDeleted;
+
+public:
+	Script();
+	~Script();
+
+	void freeScript();
+	void init(int script_nr, ResourceManager *resMan);
+	void load(ResourceManager *resMan);
+
+	virtual bool isValidOffset(uint16 offset) const;
+	virtual SegmentRef dereference(reg_t pointer);
+	virtual reg_t findCanonicAddress(SegManager *segMan, reg_t sub_addr) const;
+	virtual void freeAtAddress(SegManager *segMan, reg_t sub_addr);
+	virtual void listAllDeallocatable(SegmentId segId, void *param, NoteCallback note) const;
+	virtual void listAllOutgoingReferences(reg_t object, void *param, NoteCallback note) const;
+
+	virtual void saveLoadWithSerializer(Common::Serializer &ser);
+
+	Object *allocateObject(uint16 offset);
+	Object *getObject(uint16 offset);
+	const Object *getObject(uint16 offset) const;
+
+	/**
+	 * Initializes an object within the segment manager
+	 * @param obj_pos	Location (segment, offset) of the object. It must
+	 * 					point to the beginning of the script/class block
+	 * 					(as opposed to what the VM considers to be the
+	 * 					object location)
+	 * @returns			A newly created Object describing the object,
+	 * 					stored within the relevant script
+	 */
+	Object *scriptObjInit(reg_t obj_pos, bool fullObjectInit = true);
+
+	/**
+	 * Removes a script object
+	 * @param obj_pos	Location (segment, offset) of the object.
+	 */
+	void scriptObjRemove(reg_t obj_pos);
+
+	/**
+	 * Processes a relocation block witin a script
+	 *  This function is idempotent, but it must only be called after all
+	 *  objects have been instantiated, or a run-time error will occur.
+	 * @param obj_pos	Location (segment, offset) of the block
+	 * @return			Location of the relocation block
+	 */
+	void relocate(reg_t block);
+
+private:
+	bool relocateLocal(SegmentId segment, int location);
+
+public:
+	// 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 exports of this script
+	 * @return	pointer to the exports.
+	 */
+	const uint16 *getExportTable() const { return _exportTable; }
+
+	/**
+	 * Retrieves the number of exports of script.
+	 * @return	the number of exports of this script
+	 */
+	uint16 getExportsNr() const { return _numExports; }
+
+	/**
+	 * Retrieves a pointer to the synonyms associated with this script
+	 * @return	pointer to the synonyms, in non-parsed format.
+	 */
+	const byte *getSynonyms() const { return _synonyms; }
+
+	/**
+	 * Retrieves the number of synonyms associated with this script.
+	 * @return	the number of synonyms associated with this script
+	 */
+	uint16 getSynonymsNr() const { return _numSynonyms; }
+
+	/**
+	 * Validate whether the specified public function is exported by
+	 * the script in the specified segment.
+	 * @param pubfunct		Index of the function to validate
+	 * @return				NULL if the public function is invalid, its
+	 * 						offset into the script's segment otherwise
+	 */
+	uint16 validateExportFunc(int pubfunct);
+
+	/**
+	 * 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;
+	}
+
+	/**
+	 * Determines whether the script is marked as being deleted.
+	 */
+	bool isMarkedAsDeleted() const {
+		return _markedAsDeleted;
+	}
+
+	/**
+	 * 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);
+
+	/**
+	 * Finds the pointer where a block of a specific type starts from
+	 */
+	byte *findBlock(int type);
 };
 
-extern opcode_format g_opcode_formats[128][4];
+/**
+ * Makes sure that a script and its superclasses get loaded to the heap.
+ * If the script already has been loaded, only the number of lockers is
+ * increased. All scripts containing superclasses of this script are loaded
+ * recursively as well, unless 'recursive' is set to zero. The
+ * complementary function is "script_uninstantiate()" below.
+ * @param[in] resMan		The resource manager
+ * @param[in] segMan	The segment manager
+ * @param[in] script_nr		The script number to load
+ * @return					The script's segment ID or 0 if out of heap
+ */
+int script_instantiate(ResourceManager *resMan, SegManager *segMan, int script_nr);
 
-void script_adjust_opcode_formats();
+/**
+ * Decreases the numer of lockers of a script and unloads it if that number
+ * reaches zero.
+ * This function will recursively unload scripts containing its
+ * superclasses, if those aren't locked by other scripts as well.
+ * @param[in] segMan	The segment manager
+ * @param[in] version		The SCI version to use
+ * @param[in] script_nr	The script number that is requestet to be unloaded
+ */
+void script_uninstantiate(SegManager *segMan, int script_nr);
 
 } // End of namespace Sci
 

Modified: scummvm/trunk/engines/sci/engine/seg_manager.cpp
===================================================================
--- scummvm/trunk/engines/sci/engine/seg_manager.cpp	2010-06-27 20:38:41 UTC (rev 50395)
+++ scummvm/trunk/engines/sci/engine/seg_manager.cpp	2010-06-27 20:38:43 UTC (rev 50396)
@@ -26,6 +26,7 @@
 #include "sci/sci.h"
 #include "sci/engine/seg_manager.h"
 #include "sci/engine/state.h"
+#include "sci/engine/script.h"
 
 namespace Sci {
 
@@ -837,7 +838,6 @@
 	return ret;
 }
 
-
 byte *SegManager::allocDynmem(int size, const char *descr, reg_t *addr) {
 	SegmentId seg;
 	SegmentObj *mobj = allocSegment(new DynMem(), &seg);
@@ -949,4 +949,46 @@
 
 #endif
 
+void SegManager::createClassTable() {
+	Resource *vocab996 = _resMan->findResource(ResourceId(kResourceTypeVocab, 996), 1);
+
+	if (!vocab996)
+		error("SegManager: failed to open vocab 996");
+
+	int totalClasses = vocab996->size >> 2;
+	_classTable.resize(totalClasses);
+
+	for (uint16 classNr = 0; classNr < totalClasses; classNr++) {
+		uint16 scriptNr = READ_SCI11ENDIAN_UINT16(vocab996->data + classNr * 4 + 2);
+
+		_classTable[classNr].reg = NULL_REG;
+		_classTable[classNr].script = scriptNr;
+	}
+
+	_resMan->unlockResource(vocab996);
+}
+
+reg_t SegManager::getClassAddress(int classnr, ScriptLoadType lock, reg_t caller) {
+	if (classnr == 0xffff)
+		return NULL_REG;
+
+	if (classnr < 0 || (int)_classTable.size() <= classnr || _classTable[classnr].script < 0) {
+		error("[VM] Attempt to dereference class %x, which doesn't exist (max %x)", classnr, _classTable.size());
+		return NULL_REG;
+	} else {
+		Class *the_class = &_classTable[classnr];
+		if (!the_class->reg.segment) {
+			getScriptSegment(the_class->script, lock);
+
+			if (!the_class->reg.segment) {
+				error("[VM] Trying to instantiate class %x by instantiating script 0x%x (%03d) failed;", classnr, the_class->script, the_class->script);
+				return NULL_REG;
+			}
+		} else
+			if (caller.segment != the_class->reg.segment)
+				getScript(the_class->reg.segment)->incrementLockers();
+
+		return the_class->reg;
+	}
+}
 } // End of namespace Sci

Modified: scummvm/trunk/engines/sci/engine/seg_manager.h
===================================================================
--- scummvm/trunk/engines/sci/engine/seg_manager.h	2010-06-27 20:38:41 UTC (rev 50395)
+++ scummvm/trunk/engines/sci/engine/seg_manager.h	2010-06-27 20:38:43 UTC (rev 50396)
@@ -28,7 +28,9 @@
 
 #include "common/scummsys.h"
 #include "common/serializer.h"
+#include "sci/engine/script.h"
 #include "sci/engine/vm.h"
+#include "sci/engine/vm_types.h"
 #include "sci/engine/segment.h"
 
 namespace Sci {
@@ -42,8 +44,6 @@
 		error("%s, line, %d, %s", __FILE__, __LINE__, msg); \
 	}
 
-
-
 /**
  * Parameters for getScriptSegment().
  */
@@ -53,6 +53,7 @@
 	SCRIPT_GET_LOCK = 3 /**< Load, if neccessary, and lock */
 };
 
+class Script;
 
 class SegManager : public Common::Serializable {
 	friend class Console;

Modified: scummvm/trunk/engines/sci/engine/segment.cpp
===================================================================
--- scummvm/trunk/engines/sci/engine/segment.cpp	2010-06-27 20:38:41 UTC (rev 50395)
+++ scummvm/trunk/engines/sci/engine/segment.cpp	2010-06-27 20:38:43 UTC (rev 50396)
@@ -86,196 +86,8 @@
 	return mem;
 }
 
-Script::Script() : SegmentObj(SEG_TYPE_SCRIPT) {
-	_nr = 0;
-	_buf = NULL;
-	_bufSize = 0;
-	_scriptSize = 0;
-	_heapSize = 0;
-
-	_synonyms = NULL;
-	_heapStart = NULL;
-	_exportTable = NULL;
-
-	_localsOffset = 0;
-	_localsSegment = 0;
-	_localsBlock = NULL;
-	_localsCount = 0;
-
-	_markedAsDeleted = false;
-}
-
-Script::~Script() {
-	freeScript();
-}
-
-void Script::freeScript() {
-	free(_buf);
-	_buf = NULL;
-	_bufSize = 0;
-
-	_objects.clear();
-}
-
-void Script::init(int script_nr, ResourceManager *resMan) {
-	Resource *script = resMan->findResource(ResourceId(kResourceTypeScript, script_nr), 0);
-
-	_localsOffset = 0;
-	_localsBlock = NULL;
-	_localsCount = 0;
-
-	_markedAsDeleted = false;
-
-	_nr = script_nr;
-	_buf = 0;
-	_heapStart = 0;
-
-	_scriptSize = script->size;
-	_bufSize = script->size;
-	_heapSize = 0;
-
-	_lockers = 1;
-
-	if (getSciVersion() == SCI_VERSION_0_EARLY) {
-		_bufSize += READ_LE_UINT16(script->data) * 2;
-	} else if (getSciVersion() >= SCI_VERSION_1_1) {
-		/**
-		 * In SCI11, the heap was in a separate space from the script.
-		 * We append it to the end of the script, and adjust addressing accordingly.
-		 * However, since we address the heap with a 16-bit pointer, the combined
-		 * size of the stack and the heap must be 64KB. So far this has worked
-		 * for SCI11, SCI2 and SCI21 games. SCI3 games use a different script format,
-		 * and theoretically they can exceed the 64KB boundary using relocation.
-		 */
-		Resource *heap = resMan->findResource(ResourceId(kResourceTypeHeap, script_nr), 0);
-		_bufSize += heap->size;
-		_heapSize = heap->size;
-
-		// Ensure that the start of the heap resource can be word-aligned.
-		if (script->size & 2) {
-			_bufSize++;
-			_scriptSize++;
-		}
-
-		// As mentioned above, the script and the heap together should not exceed 64KB
-		if (script->size + heap->size > 65535)
-			error("Script and heap sizes combined exceed 64K. This means a fundamental "
-					"design bug was made regarding SCI1.1 and newer games.\nPlease "
-					"report this error to the ScummVM team");
-	}
-}
-
-void Script::load(ResourceManager *resMan) {
-	Resource *script = resMan->findResource(ResourceId(kResourceTypeScript, _nr), 0);
-	assert(script != 0);
-
-	_buf = (byte *)malloc(_bufSize);
-	assert(_buf);
-
-	assert(_bufSize >= script->size);
-	memcpy(_buf, script->data, script->size);
-
-	if (getSciVersion() >= SCI_VERSION_1_1) {
-		Resource *heap = resMan->findResource(ResourceId(kResourceTypeHeap, _nr), 0);
-		assert(heap != 0);
-
-		_heapStart = _buf + _scriptSize;
-
-		assert(_bufSize - _scriptSize <= heap->size);
-		memcpy(_heapStart, heap->data, heap->size);
-	}
-
-	_exportTable = 0;
-	_numExports = 0;
-	_synonyms = 0;
-	_numSynonyms = 0;
-	
-	if (getSciVersion() >= SCI_VERSION_1_1) {
-		if (READ_LE_UINT16(_buf + 1 + 5) > 0) {	// does the script have an export table?
-			_exportTable = (const uint16 *)(_buf + 1 + 5 + 2);
-			_numExports = READ_SCI11ENDIAN_UINT16(_exportTable - 1);
-		}
-		_localsOffset = _scriptSize + 4;
-		_localsCount = READ_SCI11ENDIAN_UINT16(_buf + _localsOffset - 2);
-	} else {
-		_exportTable = (const uint16 *)findBlock(SCI_OBJ_EXPORTS);
-		if (_exportTable) {
-			_numExports = READ_SCI11ENDIAN_UINT16(_exportTable + 1);
-			_exportTable += 3;	// skip header plus 2 bytes (_exportTable is a uint16 pointer)
-		}
-		_synonyms = findBlock(SCI_OBJ_SYNONYMS);
-		if (_synonyms) {
-			_numSynonyms = READ_SCI11ENDIAN_UINT16(_synonyms + 2) / 4;
-			_synonyms += 4;	// skip header
-		}
-		const byte* localsBlock = findBlock(SCI_OBJ_LOCALVARS);
-		if (localsBlock) {
-			_localsOffset = localsBlock - _buf + 4;
-			_localsCount = (READ_LE_UINT16(_buf + _localsOffset - 2) - 4) >> 1;	// half block size
-		}
-	}
-
-	if (getSciVersion() > SCI_VERSION_0_EARLY) {
-		// Does the script actually have locals? If not, set the locals offset to 0
-		if (!_localsCount)
-			_localsOffset = 0;
-
-		if (_localsOffset + _localsCount * 2 + 1 >= (int)_bufSize) {
-			error("Locals extend beyond end of script: offset %04x, count %d vs size %d", _localsOffset, _localsCount, _bufSize);
-			_localsCount = (_bufSize - _localsOffset) >> 1;
-		}
-	} else {
-		// Old script block. There won't be a localvar block in this case.
-		// Instead, the script starts with a 16 bit int specifying the
-		// number of locals we need; these are then allocated and zeroed.
-		_localsCount = READ_LE_UINT16(_buf);
-		_localsOffset = -_localsCount * 2; // Make sure it's invalid
-	}
-}
-
-Object *Script::allocateObject(uint16 offset) {
-	return &_objects[offset];
-}
-
-Object *Script::getObject(uint16 offset) {
-	if (_objects.contains(offset))
-		return &_objects[offset];
-	else
-		return 0;
-}
-
-const Object *Script::getObject(uint16 offset) const {
-	if (_objects.contains(offset))
-		return &_objects[offset];
-	else
-		return 0;
-}
-
-Object *Script::scriptObjInit(reg_t obj_pos, bool fullObjectInit) {
-	Object *obj;
-
-	if (getSciVersion() < SCI_VERSION_1_1 && fullObjectInit)
-		obj_pos.offset += 8;	// magic offset (SCRIPT_OBJECT_MAGIC_OFFSET)
-
-	VERIFY(obj_pos.offset < _bufSize, "Attempt to initialize object beyond end of script\n");
-
-	obj = allocateObject(obj_pos.offset);
-
-	VERIFY(obj_pos.offset + kOffsetFunctionArea < (int)_bufSize, "Function area pointer stored beyond end of script\n");
-
-	obj->init(_buf, obj_pos, fullObjectInit);
-
-	return obj;
-}
-
-void Script::scriptObjRemove(reg_t obj_pos) {
-	if (getSciVersion() < SCI_VERSION_1_1)
-		obj_pos.offset += 8;
-
-	_objects.erase(obj_pos.toUint16());
-}
-
 // This helper function is used by Script::relocateLocal and Object::relocate
+// Duplicate in segment.cpp and script.cpp
 static bool relocateBlock(Common::Array<reg_t> &block, int block_location, SegmentId segment, int location, size_t scriptSize) {
 	int rel = location - block_location;
 
@@ -298,149 +110,13 @@
 	return true;
 }
 
-bool Script::relocateLocal(SegmentId segment, int location) {
-	if (_localsBlock)
-		return relocateBlock(_localsBlock->_locals, _localsOffset, segment, location, _scriptSize);
-	else
-		return false;
-}
-
-void Script::relocate(reg_t block) {
-	byte *heap = _buf;
-	uint16 heapSize = (uint16)_bufSize;
-	uint16 heapOffset = 0;
-
-	if (getSciVersion() >= SCI_VERSION_1_1) {
-		heap = _heapStart;
-		heapSize = (uint16)_heapSize;
-		heapOffset = _scriptSize;
-	}
-
-	VERIFY(block.offset < (uint16)heapSize && READ_SCI11ENDIAN_UINT16(heap + block.offset) * 2 + block.offset < (uint16)heapSize,
-	       "Relocation block outside of script\n");
-
-	int count = READ_SCI11ENDIAN_UINT16(heap + block.offset);
-	int exportIndex = 0;
-	int pos = 0;
-
-	for (int i = 0; i < count; i++) {
-		pos = READ_SCI11ENDIAN_UINT16(heap + block.offset + 2 + (exportIndex * 2)) + heapOffset;
-		// This occurs in SCI01/SCI1 games where usually one export value
-		// is zero. It seems that in this situation, we should skip the
-		// export and move to the next one, though the total count of valid
-		// exports remains the same
-		if (!pos) {
-			exportIndex++;
-			pos = READ_SCI11ENDIAN_UINT16(heap + block.offset + 2 + (exportIndex * 2)) + heapOffset;
-			if (!pos)
-				error("Script::relocate(): Consecutive zero exports found");
-		}
-
-		// In SCI0-SCI1, script local variables, objects and code are relocated. We only relocate
-		// locals and objects here, and ignore relocation of code blocks. In SCI1.1 and newer
-		// versions, only locals and objects are relocated.
-		if (!relocateLocal(block.segment, pos)) {
-			// Not a local? It's probably an object or code block. If it's an object, relocate it.
-			const ObjMap::iterator end = _objects.end();
-			for (ObjMap::iterator it = _objects.begin(); it != end; ++it)
-				if (it->_value.relocate(block.segment, pos, _scriptSize))
-					break;
-		}
-
-		exportIndex++;
-	}
-}
-
-void Script::incrementLockers() {
-	_lockers++;
-}
-
-void Script::decrementLockers() {
-	if (_lockers > 0)
-		_lockers--;
-}
-
-int Script::getLockers() const {
-	return _lockers;
-}
-
-void Script::setLockers(int lockers) {
-	_lockers = lockers;
-}
-
-uint16 Script::validateExportFunc(int pubfunct) {
-	bool exportsAreWide = (g_sci->_features->detectLofsType() == SCI_VERSION_1_MIDDLE);
-
-	if (_numExports <= pubfunct) {
-		error("validateExportFunc(): pubfunct is invalid");
-		return 0;
-	}
-
-	if (exportsAreWide)
-		pubfunct *= 2;
-	uint16 offset = READ_SCI11ENDIAN_UINT16(_exportTable + pubfunct);
-	VERIFY(offset < _bufSize, "invalid export function pointer");
-
-	return offset;
-}
-
-byte *Script::findBlock(int type) {
-	byte *buf = _buf;
-	bool oldScriptHeader = (getSciVersion() == SCI_VERSION_0_EARLY);
-
-	if (oldScriptHeader)
-		buf += 2;
-
-	do {
-		int seekerType = READ_LE_UINT16(buf);
-
-		if (seekerType == 0)
-			break;
-		if (seekerType == type)
-			return buf;
-
-		int seekerSize = READ_LE_UINT16(buf + 2);
-		assert(seekerSize > 0);
-		buf += seekerSize;
-	} while (1);
-
-	return NULL;
-}
-
-
-// memory operations
-
-void Script::mcpyInOut(int dst, const void *src, size_t n) {
-	if (_buf) {
-		assert(dst + n <= _bufSize);
-		memcpy(_buf + dst, src, n);
-	}
-}
-
 SegmentRef SegmentObj::dereference(reg_t pointer) {
 	error("Error: Trying to dereference pointer %04x:%04x to inappropriate segment",
 		          PRINT_REG(pointer));
 	return SegmentRef();
 }
 
-bool Script::isValidOffset(uint16 offset) const {
-	return offset < _bufSize;
-}
 
-SegmentRef Script::dereference(reg_t pointer) {
-	if (pointer.offset > _bufSize) {
-		error("Script::dereference(): Attempt to dereference invalid pointer %04x:%04x into script segment (script size=%d)",
-				  PRINT_REG(pointer), (uint)_bufSize);
-		return SegmentRef();
-	}
-
-	SegmentRef ret;
-	ret.isRaw = true;
-	ret.maxSize = _bufSize - pointer.offset;
-	ret.raw = _buf + pointer.offset;
-	return ret;
-}
-
 bool LocalVariables::isValidOffset(uint16 offset) const {
 	return offset < _locals.size() * 2;
 }

Modified: scummvm/trunk/engines/sci/engine/segment.h
===================================================================
--- scummvm/trunk/engines/sci/engine/segment.h	2010-06-27 20:38:41 UTC (rev 50395)
+++ scummvm/trunk/engines/sci/engine/segment.h	2010-06-27 20:38:43 UTC (rev 50396)
@@ -331,182 +331,6 @@
 	reg_t _pos; /**< Object offset within its script; for clones, this is their base */
 };
 
-typedef Common::HashMap<uint16, Object> ObjMap;
-
-class Script : public SegmentObj {
-public:
-	int _nr; /**< Script number */
-	byte *_buf; /**< Static data buffer, or NULL if not used */
-	byte *_heapStart; /**< Start of heap if SCI1.1, NULL otherwise */
-
-	uint32 getScriptSize() { return _scriptSize; }
-	uint32 getHeapSize() { return _heapSize; }
-	uint32 getBufSize() { return _bufSize; }
-
-protected:
-	int _lockers; /**< Number of classes and objects that require this script */
-
-private:
-	size_t _scriptSize;
-	size_t _heapSize;
-	uint16 _bufSize;
-
-	const uint16 *_exportTable; /**< Abs. offset of the export table or 0 if not present */
-	uint16 _numExports; /**< Number of entries in the exports table */
-
-	const byte *_synonyms; /**< Synonyms block or 0 if not present*/
-	uint16 _numSynonyms; /**< Number of entries in the synonyms block */
-
-	int _localsOffset;
-	uint16 _localsCount;
-
-public:
-	/**
-	 * Table for objects, contains property variables.
-	 * Indexed by the TODO offset.
-	 */
-	ObjMap _objects;
-
-	int getLocalsOffset() const { return _localsOffset; }
-	uint16 getLocalsCount() const { return _localsCount; }
-	SegmentId _localsSegment; /**< The local variable segment */
-	LocalVariables *_localsBlock;
-
-	bool _markedAsDeleted;
-
-public:
-	Script();
-	~Script();
-
-	void freeScript();
-	void init(int script_nr, ResourceManager *resMan);
-	void load(ResourceManager *resMan);
-
-	virtual bool isValidOffset(uint16 offset) const;
-	virtual SegmentRef dereference(reg_t pointer);
-	virtual reg_t findCanonicAddress(SegManager *segMan, reg_t sub_addr) const;
-	virtual void freeAtAddress(SegManager *segMan, reg_t sub_addr);
-	virtual void listAllDeallocatable(SegmentId segId, void *param, NoteCallback note) const;
-	virtual void listAllOutgoingReferences(reg_t object, void *param, NoteCallback note) const;
-
-	virtual void saveLoadWithSerializer(Common::Serializer &ser);
-
-	Object *allocateObject(uint16 offset);
-	Object *getObject(uint16 offset);
-	const Object *getObject(uint16 offset) const;
-
-	/**
-	 * Initializes an object within the segment manager
-	 * @param obj_pos	Location (segment, offset) of the object. It must
-	 * 					point to the beginning of the script/class block
-	 * 					(as opposed to what the VM considers to be the
-	 * 					object location)
-	 * @returns			A newly created Object describing the object,
-	 * 					stored within the relevant script
-	 */
-	Object *scriptObjInit(reg_t obj_pos, bool fullObjectInit = true);
-
-	/**
-	 * Removes a script object
-	 * @param obj_pos	Location (segment, offset) of the object.
-	 */
-	void scriptObjRemove(reg_t obj_pos);
-
-	/**
-	 * Processes a relocation block witin a script
-	 *  This function is idempotent, but it must only be called after all
-	 *  objects have been instantiated, or a run-time error will occur.
-	 * @param obj_pos	Location (segment, offset) of the block
-	 * @return			Location of the relocation block
-	 */
-	void relocate(reg_t block);
-
-private:
-	bool relocateLocal(SegmentId segment, int location);
-
-public:
-	// 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 exports of this script
-	 * @return	pointer to the exports.
-	 */
-	const uint16 *getExportTable() const { return _exportTable; }
-
-	/**
-	 * Retrieves the number of exports of script.
-	 * @return	the number of exports of this script
-	 */
-	uint16 getExportsNr() const { return _numExports; }
-
-	/**
-	 * Retrieves a pointer to the synonyms associated with this script
-	 * @return	pointer to the synonyms, in non-parsed format.
-	 */
-	const byte *getSynonyms() const { return _synonyms; }
-
-	/**
-	 * Retrieves the number of synonyms associated with this script.
-	 * @return	the number of synonyms associated with this script
-	 */
-	uint16 getSynonymsNr() const { return _numSynonyms; }
-
-	/**
-	 * Validate whether the specified public function is exported by
-	 * the script in the specified segment.
-	 * @param pubfunct		Index of the function to validate
-	 * @return				NULL if the public function is invalid, its
-	 * 						offset into the script's segment otherwise
-	 */
-	uint16 validateExportFunc(int pubfunct);
-
-	/**
-	 * 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;
-	}
-
-	/**
-	 * Determines whether the script is marked as being deleted.
-	 */
-	bool isMarkedAsDeleted() const {
-		return _markedAsDeleted;
-	}
-
-	/**
-	 * 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);
-
-	/**
-	 * Finds the pointer where a block of a specific type starts from
-	 */
-	byte *findBlock(int type);
-};
-
 /** Data stack */
 struct DataStack : SegmentObj {
 	int _capacity; /**< Number of stack entries */

Modified: scummvm/trunk/engines/sci/engine/vm.cpp
===================================================================
--- scummvm/trunk/engines/sci/engine/vm.cpp	2010-06-27 20:38:41 UTC (rev 50395)
+++ scummvm/trunk/engines/sci/engine/vm.cpp	2010-06-27 20:38:43 UTC (rev 50396)
@@ -49,6 +49,86 @@
 
 #define SCI_XS_CALLEE_LOCALS ((SegmentId)-1)
 
+#define END Script_None
+
+opcode_format g_opcode_formats[128][4] = {
+	/*00*/
+	{Script_None}, {Script_None}, {Script_None}, {Script_None},
+	/*04*/
+	{Script_None}, {Script_None}, {Script_None}, {Script_None},
+	/*08*/
+	{Script_None}, {Script_None}, {Script_None}, {Script_None},
+	/*0C*/
+	{Script_None}, {Script_None}, {Script_None}, {Script_None},
+	/*10*/
+	{Script_None}, {Script_None}, {Script_None}, {Script_None},
+	/*14*/
+	{Script_None}, {Script_None}, {Script_None}, {Script_SRelative, END},
+	/*18*/
+	{Script_SRelative, END}, {Script_SRelative, END}, {Script_SVariable, END}, {Script_None},
+	/*1C*/
+	{Script_SVariable, END}, {Script_None}, {Script_None}, {Script_Variable, END},
+	/*20*/
+	{Script_SRelative, Script_Byte, END}, {Script_Variable, Script_Byte, END}, {Script_Variable, Script_Byte, END}, {Script_Variable, Script_SVariable, Script_Byte, END},
+	/*24 (24=ret)*/
+	{Script_End}, {Script_Byte, END}, {Script_Invalid}, {Script_Invalid},
+	/*28*/
+	{Script_Variable, END}, {Script_Invalid}, {Script_Byte, END}, {Script_Variable, Script_Byte, END},
+	/*2C*/
+	{Script_SVariable, END}, {Script_SVariable, Script_Variable, END}, {Script_None}, {Script_Invalid},
+	/*30*/
+	{Script_None}, {Script_Property, END}, {Script_Property, END}, {Script_Property, END},
+	/*34*/
+	{Script_Property, END}, {Script_Property, END}, {Script_Property, END}, {Script_Property, END},
+	/*38*/
+	{Script_Property, END}, {Script_SRelative, END}, {Script_SRelative, END}, {Script_None},
+	/*3C*/
+	{Script_None}, {Script_None}, {Script_None}, {Script_Word},
+	/*40-4F*/
+	{Script_Global, END}, {Script_Local, END}, {Script_Temp, END}, {Script_Param, END},
+	{Script_Global, END}, {Script_Local, END}, {Script_Temp, END}, {Script_Param, END},
+	{Script_Global, END}, {Script_Local, END}, {Script_Temp, END}, {Script_Param, END},
+	{Script_Global, END}, {Script_Local, END}, {Script_Temp, END}, {Script_Param, END},
+	/*50-5F*/
+	{Script_Global, END}, {Script_Local, END}, {Script_Temp, END}, {Script_Param, END},
+	{Script_Global, END}, {Script_Local, END}, {Script_Temp, END}, {Script_Param, END},
+	{Script_Global, END}, {Script_Local, END}, {Script_Temp, END}, {Script_Param, END},
+	{Script_Global, END}, {Script_Local, END}, {Script_Temp, END}, {Script_Param, END},
+	/*60-6F*/
+	{Script_Global, END}, {Script_Local, END}, {Script_Temp, END}, {Script_Param, END},
+	{Script_Global, END}, {Script_Local, END}, {Script_Temp, END}, {Script_Param, END},
+	{Script_Global, END}, {Script_Local, END}, {Script_Temp, END}, {Script_Param, END},
+	{Script_Global, END}, {Script_Local, END}, {Script_Temp, END}, {Script_Param, END},
+	/*70-7F*/
+	{Script_Global, END}, {Script_Local, END}, {Script_Temp, END}, {Script_Param, END},
+	{Script_Global, END}, {Script_Local, END}, {Script_Temp, END}, {Script_Param, END},
+	{Script_Global, END}, {Script_Local, END}, {Script_Temp, END}, {Script_Param, END},
+	{Script_Global, END}, {Script_Local, END}, {Script_Temp, END}, {Script_Param, END}
+};
+#undef END
+
+// TODO: script_adjust_opcode_formats should probably be part of the
+// constructor (?) of a VirtualMachine or a ScriptManager class.
+void script_adjust_opcode_formats() {
+	if (g_sci->_features->detectLofsType() != SCI_VERSION_0_EARLY) {
+		g_opcode_formats[op_lofsa][0] = Script_Offset;
+		g_opcode_formats[op_lofss][0] = Script_Offset;
+	}
+
+#ifdef ENABLE_SCI32
+	// In SCI32, some arguments are now words instead of bytes
+	if (getSciVersion() >= SCI_VERSION_2) {
+		g_opcode_formats[op_calle][2] = Script_Word;
+		g_opcode_formats[op_callk][1] = Script_Word;
+		g_opcode_formats[op_super][1] = Script_Word;
+		g_opcode_formats[op_send][0] = Script_Word;
+		g_opcode_formats[op_self][0] = Script_Word;
+		g_opcode_formats[op_call][1] = Script_Word;
+		g_opcode_formats[op_callb][1] = Script_Word;
+	}
+#endif
+}
+
 /**
  * Adds an entry to the top of the execution stack.
  *

Modified: scummvm/trunk/engines/sci/engine/vm.h
===================================================================
--- scummvm/trunk/engines/sci/engine/vm.h	2010-06-27 20:38:41 UTC (rev 50395)
+++ scummvm/trunk/engines/sci/engine/vm.h	2010-06-27 20:38:43 UTC (rev 50396)
@@ -118,7 +118,161 @@
 	GC_INTERVAL = 32768
 };
 
+// Opcode formats
+enum opcode_format {
+	Script_Invalid = -1,
+	Script_None = 0,
+	Script_Byte,
+	Script_SByte,
+	Script_Word,
+	Script_SWord,
+	Script_Variable,
+	Script_SVariable,
+	Script_SRelative,
+	Script_Property,
+	Script_Global,
+	Script_Local,
+	Script_Temp,
+	Script_Param,
+	Script_Offset,
+	Script_End
+};
 
+enum sci_opcodes {
+	op_bnot     = 0x00,	// 000
+	op_add      = 0x01,	// 001
+	op_sub      = 0x02,	// 002
+	op_mul      = 0x03,	// 003
+	op_div      = 0x04,	// 004
+	op_mod      = 0x05,	// 005
+	op_shr      = 0x06,	// 006
+	op_shl      = 0x07,	// 007
+	op_xor      = 0x08,	// 008
+	op_and      = 0x09,	// 009
+	op_or       = 0x0a,	// 010
+	op_neg      = 0x0b,	// 011
+	op_not      = 0x0c,	// 012
+	op_eq_      = 0x0d,	// 013
+	op_ne_      = 0x0e,	// 014
+	op_gt_      = 0x0f,	// 015
+	op_ge_      = 0x10,	// 016
+	op_lt_      = 0x11,	// 017
+	op_le_      = 0x12,	// 018
+	op_ugt_     = 0x13,	// 019
+	op_uge_     = 0x14,	// 020
+	op_ult_     = 0x15,	// 021
+	op_ule_     = 0x16,	// 022
+	op_bt       = 0x17,	// 023
+	op_bnt      = 0x18,	// 024
+	op_jmp      = 0x19,	// 025
+	op_ldi      = 0x1a,	// 026
+	op_push     = 0x1b,	// 027
+	op_pushi    = 0x1c,	// 028
+	op_toss     = 0x1d,	// 029
+	op_dup      = 0x1e,	// 030
+	op_link     = 0x1f,	// 031
+	op_call     = 0x20,	// 032
+	op_callk    = 0x21,	// 033
+	op_callb    = 0x22,	// 034
+	op_calle    = 0x23,	// 035
+	op_ret      = 0x24,	// 036
+	op_send     = 0x25,	// 037
+	// dummy      0x26,	// 038
+	// dummy      0x27,	// 039
+	op_class    = 0x28,	// 040
+	// dummy      0x29,	// 041
+	op_self     = 0x2a,	// 042
+	op_super    = 0x2b,	// 043
+	op_rest     = 0x2c,	// 044
+	op_lea      = 0x2d,	// 045
+	op_selfID   = 0x2e,	// 046
+	// dummy      0x2f	// 047
+	op_pprev    = 0x30,	// 048
+	op_pToa     = 0x31,	// 049
+	op_aTop     = 0x32,	// 050
+	op_pTos     = 0x33,	// 051
+	op_sTop     = 0x34,	// 052
+	op_ipToa    = 0x35,	// 053
+	op_dpToa    = 0x36,	// 054
+	op_ipTos    = 0x37,	// 055
+	op_dpTos    = 0x38,	// 056
+	op_lofsa    = 0x39,	// 057
+	op_lofss    = 0x3a,	// 058
+	op_push0    = 0x3b,	// 059
+	op_push1    = 0x3c,	// 060
+	op_push2    = 0x3d,	// 061
+	op_pushSelf = 0x3e,	// 062
+	op_line     = 0x3f,	// 063
+	op_lag      = 0x40,	// 064
+	op_lal      = 0x41,	// 065
+	op_lat      = 0x42,	// 066
+	op_lap      = 0x43,	// 067
+	op_lsg      = 0x44,	// 068
+	op_lsl      = 0x45,	// 069
+	op_lst      = 0x46,	// 070
+	op_lsp      = 0x47,	// 071
+	op_lagi     = 0x48,	// 072
+	op_lali     = 0x49,	// 073
+	op_lati     = 0x4a,	// 074
+	op_lapi     = 0x4b,	// 075
+	op_lsgi     = 0x4c,	// 076
+	op_lsli     = 0x4d,	// 077
+	op_lsti     = 0x4e,	// 078
+	op_lspi     = 0x4f,	// 079
+	op_sag      = 0x50,	// 080
+	op_sal      = 0x51,	// 081
+	op_sat      = 0x52,	// 082
+	op_sap      = 0x53,	// 083
+	op_ssg      = 0x54,	// 084
+	op_ssl      = 0x55,	// 085
+	op_sst      = 0x56,	// 086
+	op_ssp      = 0x57,	// 087
+	op_sagi     = 0x58,	// 088
+	op_sali     = 0x59,	// 089
+	op_sati     = 0x5a,	// 090
+	op_sapi     = 0x5b,	// 091
+	op_ssgi     = 0x5c,	// 092
+	op_ssli     = 0x5d,	// 093
+	op_ssti     = 0x5e,	// 094
+	op_sspi     = 0x5f,	// 095
+	op_plusag   = 0x60,	// 096
+	op_plusal   = 0x61,	// 097
+	op_plusat   = 0x62,	// 098
+	op_plusap   = 0x63,	// 099
+	op_plussg   = 0x64,	// 100
+	op_plussl   = 0x65,	// 101
+	op_plusst   = 0x66,	// 102
+	op_plussp   = 0x67,	// 103
+	op_plusagi  = 0x68,	// 104
+	op_plusali  = 0x69,	// 105
+	op_plusati  = 0x6a,	// 106
+	op_plusapi  = 0x6b,	// 107
+	op_plussgi  = 0x6c,	// 108
+	op_plussli  = 0x6d,	// 109
+	op_plussti  = 0x6e,	// 110
+	op_plusspi  = 0x6f,	// 111
+	op_minusag  = 0x70,	// 112
+	op_minusal  = 0x71,	// 113
+	op_minusat  = 0x72,	// 114
+	op_minusap  = 0x73,	// 115
+	op_minussg  = 0x74,	// 116
+	op_minussl  = 0x75,	// 117
+	op_minusst  = 0x76,	// 118
+	op_minussp  = 0x77,	// 119
+	op_minusagi = 0x78,	// 120
+	op_minusali = 0x79,	// 121
+	op_minusati = 0x7a,	// 122
+	op_minusapi = 0x7b,	// 123
+	op_minussgi = 0x7c,	// 124
+	op_minussli = 0x7d,	// 125
+	op_minussti = 0x7e,	// 126
+	op_minusspi = 0x7f	// 127
+};
+
+extern opcode_format g_opcode_formats[128][4];
+
+void script_adjust_opcode_formats();
+
 /**
  * Executes function pubfunct of the specified script.
  * @param[in] s				The state which is to be executed with
@@ -195,30 +349,6 @@
 		ObjVarRef *varp, reg_t *fptr);
 
 /**
- * Makes sure that a script and its superclasses get loaded to the heap.
- * If the script already has been loaded, only the number of lockers is
- * increased. All scripts containing superclasses of this script are loaded
- * recursively as well, unless 'recursive' is set to zero. The
- * complementary function is "script_uninstantiate()" below.
- * @param[in] resMan		The resource manager
- * @param[in] segMan	The segment manager
- * @param[in] script_nr		The script number to load
- * @return					The script's segment ID or 0 if out of heap
- */
-int script_instantiate(ResourceManager *resMan, SegManager *segMan, int script_nr);
-
-/**
- * Decreases the numer of lockers of a script and unloads it if that number
- * reaches zero.
- * This function will recursively unload scripts containing its
- * superclasses, if those aren't locked by other scripts as well.
- * @param[in] segMan	The segment manager
- * @param[in] version		The SCI version to use
- * @param[in] script_nr	The script number that is requestet to be unloaded
- */
-void script_uninstantiate(SegManager *segMan, int script_nr);
-
-/**
  * Read a PMachine instruction from a memory buffer and return its length.
  *
  * @param[in] src		address from which to start parsing


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