diff options
-rw-r--r-- | engines/sci/engine/kscripts.cpp | 2 | ||||
-rw-r--r-- | engines/sci/engine/script.cpp | 105 | ||||
-rw-r--r-- | engines/sci/engine/script.h | 24 | ||||
-rw-r--r-- | engines/sci/engine/seg_manager.cpp | 108 | ||||
-rw-r--r-- | engines/sci/engine/seg_manager.h | 24 | ||||
-rw-r--r-- | engines/sci/engine/vm.cpp | 2 | ||||
-rw-r--r-- | engines/sci/sci.cpp | 2 |
7 files changed, 134 insertions, 133 deletions
diff --git a/engines/sci/engine/kscripts.cpp b/engines/sci/engine/kscripts.cpp index 8ea0ec2019..8f41fbad2e 100644 --- a/engines/sci/engine/kscripts.cpp +++ b/engines/sci/engine/kscripts.cpp @@ -239,7 +239,7 @@ reg_t kDisposeScript(EngineState *s, int argc, reg_t *argv) { scr->setLockers(1); } - script_uninstantiate(s->_segMan, script); + s->_segMan->uninstantiateScript(script); if (argc != 2) { return s->r_acc; diff --git a/engines/sci/engine/script.cpp b/engines/sci/engine/script.cpp index 18244c7906..2bb405372a 100644 --- a/engines/sci/engine/script.cpp +++ b/engines/sci/engine/script.cpp @@ -519,109 +519,4 @@ void Script::initialiseObjectsSci11(SegManager *segMan) { } } -int script_instantiate(ResourceManager *resMan, SegManager *segMan, int scriptNum) { - SegmentId segmentId = segMan->getScriptSegment(scriptNum); - Script *scr = segMan->getScriptIfLoaded(segmentId); - if (scr) { - if (!scr->isMarkedAsDeleted()) { - scr->incrementLockers(); - return segmentId; - } else { - scr->freeScript(); - } - } else { - scr = segMan->allocateScript(scriptNum, &segmentId); - } - - scr->init(scriptNum, resMan); - scr->load(resMan); - scr->initialiseLocals(segMan); - scr->initialiseClasses(segMan); - - if (getSciVersion() >= SCI_VERSION_1_1) { - scr->initialiseObjectsSci11(segMan); - scr->relocate(make_reg(segmentId, READ_SCI11ENDIAN_UINT16(scr->_heapStart))); - } else { - scr->initialiseObjectsSci0(segMan); - byte *relocationBlock = scr->findBlock(SCI_OBJ_POINTERS); - if (relocationBlock) - scr->relocate(make_reg(segmentId, relocationBlock - scr->_buf + 4)); - } - - return segmentId; -} - -void script_uninstantiate_sci0(SegManager *segMan, int script_nr, SegmentId seg) { - bool oldScriptHeader = (getSciVersion() == SCI_VERSION_0_EARLY); - reg_t reg = make_reg(seg, oldScriptHeader ? 2 : 0); - int objType, objLength = 0; - Script *scr = segMan->getScript(seg); - - // Make a pass over the object in order uninstantiate all superclasses - - do { - reg.offset += objLength; // Step over the last checked object - - objType = READ_SCI11ENDIAN_UINT16(scr->_buf + reg.offset); - if (!objType) - break; - objLength = READ_SCI11ENDIAN_UINT16(scr->_buf + reg.offset + 2); - - reg.offset += 4; // Step over header - - if ((objType == SCI_OBJ_OBJECT) || (objType == SCI_OBJ_CLASS)) { // object or class? - reg.offset += 8; // magic offset (SCRIPT_OBJECT_MAGIC_OFFSET) - int16 superclass = READ_SCI11ENDIAN_UINT16(scr->_buf + reg.offset + 2); - - if (superclass >= 0) { - int superclass_script = segMan->getClass(superclass).script; - - if (superclass_script == script_nr) { - if (scr->getLockers()) - scr->decrementLockers(); // Decrease lockers if this is us ourselves - } else - script_uninstantiate(segMan, superclass_script); - // Recurse to assure that the superclass lockers number gets decreased - } - - reg.offset += SCRIPT_OBJECT_MAGIC_OFFSET; - } // if object or class - - reg.offset -= 4; // Step back on header - - } while (objType != 0); -} - -void script_uninstantiate(SegManager *segMan, int script_nr) { - SegmentId segment = segMan->getScriptSegment(script_nr); - Script *scr = segMan->getScriptIfLoaded(segment); - - if (!scr) { // Is it already loaded? - //warning("unloading script 0x%x requested although not loaded", script_nr); - // This is perfectly valid SCI behaviour - return; - } - - scr->decrementLockers(); // One less locker - - if (scr->getLockers() > 0) - return; - - // Free all classtable references to this script - for (uint i = 0; i < segMan->classTableSize(); i++) - if (segMan->getClass(i).reg.segment == segment) - segMan->setClassOffset(i, NULL_REG); - - if (getSciVersion() < SCI_VERSION_1_1) - script_uninstantiate_sci0(segMan, script_nr, segment); - // FIXME: Add proper script uninstantiation for SCI 1.1 - - if (!scr->getLockers()) { - // The actual script deletion seems to be done by SCI scripts themselves - scr->markDeleted(); - debugC(kDebugLevelScripts, "Unloaded script 0x%x.", script_nr); - } -} - - } // End of namespace Sci diff --git a/engines/sci/engine/script.h b/engines/sci/engine/script.h index cc3c0263e8..5396a7432e 100644 --- a/engines/sci/engine/script.h +++ b/engines/sci/engine/script.h @@ -250,30 +250,6 @@ public: byte *findBlock(int type); }; -/** - * 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); - } // End of namespace Sci #endif // SCI_ENGINE_SCRIPT_H diff --git a/engines/sci/engine/seg_manager.cpp b/engines/sci/engine/seg_manager.cpp index 35ac0a5f69..b56a539c63 100644 --- a/engines/sci/engine/seg_manager.cpp +++ b/engines/sci/engine/seg_manager.cpp @@ -361,7 +361,7 @@ SegmentId SegManager::getScriptSegment(int script_nr, ScriptLoadType load) { SegmentId segment; if ((load & SCRIPT_GET_LOAD) == SCRIPT_GET_LOAD) - script_instantiate(_resMan, this, script_nr); + instantiateScript(script_nr); segment = getScriptSegment(script_nr); @@ -991,4 +991,110 @@ reg_t SegManager::getClassAddress(int classnr, ScriptLoadType lock, reg_t caller return the_class->reg; } } + +int SegManager::instantiateScript(int scriptNum) { + SegmentId segmentId = getScriptSegment(scriptNum); + Script *scr = getScriptIfLoaded(segmentId); + if (scr) { + if (!scr->isMarkedAsDeleted()) { + scr->incrementLockers(); + return segmentId; + } else { + scr->freeScript(); + } + } else { + scr = allocateScript(scriptNum, &segmentId); + } + + scr->init(scriptNum, _resMan); + scr->load(_resMan); + scr->initialiseLocals(this); + scr->initialiseClasses(this); + + if (getSciVersion() >= SCI_VERSION_1_1) { + scr->initialiseObjectsSci11(this); + scr->relocate(make_reg(segmentId, READ_SCI11ENDIAN_UINT16(scr->_heapStart))); + } else { + scr->initialiseObjectsSci0(this); + byte *relocationBlock = scr->findBlock(SCI_OBJ_POINTERS); + if (relocationBlock) + scr->relocate(make_reg(segmentId, relocationBlock - scr->_buf + 4)); + } + + return segmentId; +} + +void SegManager::uninstantiateScript(int script_nr) { + SegmentId segmentId = getScriptSegment(script_nr); + Script *scr = getScriptIfLoaded(segmentId); + + if (!scr) { // Is it already unloaded? + //warning("unloading script 0x%x requested although not loaded", script_nr); + // This is perfectly valid SCI behaviour + return; + } + + scr->decrementLockers(); // One less locker + + if (scr->getLockers() > 0) + return; + + // Free all classtable references to this script + for (uint i = 0; i < classTableSize(); i++) + if (getClass(i).reg.segment == segmentId) + setClassOffset(i, NULL_REG); + + if (getSciVersion() < SCI_VERSION_1_1) + uninstantiateScriptSci0(script_nr); + // FIXME: Add proper script uninstantiation for SCI 1.1 + + if (!scr->getLockers()) { + // The actual script deletion seems to be done by SCI scripts themselves + scr->markDeleted(); + debugC(kDebugLevelScripts, "Unloaded script 0x%x.", script_nr); + } +} + +void SegManager::uninstantiateScriptSci0(int script_nr) { + bool oldScriptHeader = (getSciVersion() == SCI_VERSION_0_EARLY); + SegmentId segmentId = getScriptSegment(script_nr); + Script *scr = getScript(segmentId); + reg_t reg = make_reg(segmentId, oldScriptHeader ? 2 : 0); + int objType, objLength = 0; + + // Make a pass over the object in order uninstantiate all superclasses + + do { + reg.offset += objLength; // Step over the last checked object + + objType = READ_SCI11ENDIAN_UINT16(scr->_buf + reg.offset); + if (!objType) + break; + objLength = READ_SCI11ENDIAN_UINT16(scr->_buf + reg.offset + 2); + + reg.offset += 4; // Step over header + + if ((objType == SCI_OBJ_OBJECT) || (objType == SCI_OBJ_CLASS)) { // object or class? + reg.offset += 8; // magic offset (SCRIPT_OBJECT_MAGIC_OFFSET) + int16 superclass = READ_SCI11ENDIAN_UINT16(scr->_buf + reg.offset + 2); + + if (superclass >= 0) { + int superclass_script = getClass(superclass).script; + + if (superclass_script == script_nr) { + if (scr->getLockers()) + scr->decrementLockers(); // Decrease lockers if this is us ourselves + } else + uninstantiateScript(superclass_script); + // Recurse to assure that the superclass lockers number gets decreased + } + + reg.offset += SCRIPT_OBJECT_MAGIC_OFFSET; + } // if object or class + + reg.offset -= 4; // Step back on header + + } while (objType != 0); +} + } // End of namespace Sci diff --git a/engines/sci/engine/seg_manager.h b/engines/sci/engine/seg_manager.h index 324527400b..4af2965bc7 100644 --- a/engines/sci/engine/seg_manager.h +++ b/engines/sci/engine/seg_manager.h @@ -117,6 +117,30 @@ public: */ SegmentId getScriptSegment(int script_nr, ScriptLoadType load); + /** + * 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 "uninstantiateScript()" below. + * @param[in] script_nr The script number to load + * @return The script's segment ID or 0 if out of heap + */ + int instantiateScript(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] script_nr The script number that is requestet to be unloaded + */ + void uninstantiateScript(int script_nr); + +private: + void uninstantiateScriptSci0(int script_nr); + +public: // TODO: document this reg_t getClassAddress(int classnr, ScriptLoadType lock, reg_t caller); diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp index 9ab95c41bb..f59cf4a577 100644 --- a/engines/sci/engine/vm.cpp +++ b/engines/sci/engine/vm.cpp @@ -420,7 +420,7 @@ ExecStack *execute_method(EngineState *s, uint16 script, uint16 pubfunct, StackP Script *scr = s->_segMan->getScriptIfLoaded(seg); if (!scr || scr->isMarkedAsDeleted()) { // Script not present yet? - seg = script_instantiate(g_sci->getResMan(), s->_segMan, script); + seg = s->_segMan->instantiateScript(script); scr = s->_segMan->getScript(seg); } diff --git a/engines/sci/sci.cpp b/engines/sci/sci.cpp index 6decfc7c27..8a41d74b7f 100644 --- a/engines/sci/sci.cpp +++ b/engines/sci/sci.cpp @@ -373,7 +373,7 @@ bool SciEngine::initGame() { _gamestate->stack_base = stack->_entries; _gamestate->stack_top = stack->_entries + stack->_capacity; - if (!script_instantiate(_resMan, _gamestate->_segMan, 0)) { + if (!_gamestate->_segMan->instantiateScript(0)) { error("initGame(): Could not instantiate script 0"); return false; } |