diff options
Diffstat (limited to 'engines')
-rw-r--r-- | engines/sci/engine/kscripts.cpp | 76 | ||||
-rw-r--r-- | engines/sci/engine/selector.cpp | 211 | ||||
-rw-r--r-- | engines/sci/engine/vm.cpp | 104 | ||||
-rw-r--r-- | engines/sci/module.mk | 1 |
4 files changed, 212 insertions, 180 deletions
diff --git a/engines/sci/engine/kscripts.cpp b/engines/sci/engine/kscripts.cpp index ce7656f47e..2978a2a2e2 100644 --- a/engines/sci/engine/kscripts.cpp +++ b/engines/sci/engine/kscripts.cpp @@ -31,82 +31,6 @@ namespace Sci { -reg_t read_selector(SegManager *segMan, reg_t object, Selector selector_id, const char *file, int line) { - ObjVarRef address; - - if (lookup_selector(segMan, object, selector_id, &address, NULL) != kSelectorVariable) - return NULL_REG; - else - return *address.getPointer(segMan); -} - -void write_selector(SegManager *segMan, reg_t object, Selector selector_id, reg_t value, const char *fname, int line) { - ObjVarRef address; - - if ((selector_id < 0) || (selector_id > (int)((SciEngine*)g_engine)->getKernel()->getSelectorNamesSize())) { - warning("Attempt to write to invalid selector %d of" - " object at %04x:%04x (%s L%d).", selector_id, PRINT_REG(object), fname, line); - return; - } - - if (lookup_selector(segMan, object, selector_id, &address, NULL) != kSelectorVariable) - warning("Selector '%s' of object at %04x:%04x could not be" - " written to (%s L%d)", ((SciEngine*)g_engine)->getKernel()->getSelectorName(selector_id).c_str(), PRINT_REG(object), fname, line); - else - *address.getPointer(segMan) = value; -} - -int invoke_selector(EngineState *s, reg_t object, int selector_id, SelectorInvocation noinvalid, int kfunct, - StackPtr k_argp, int k_argc, const char *fname, int line, int argc, ...) { - va_list argp; - int i; - int framesize = 2 + 1 * argc; - reg_t address; - int slc_type; - StackPtr stackframe = k_argp + k_argc; - - stackframe[0] = make_reg(0, selector_id); // The selector we want to call - stackframe[1] = make_reg(0, argc); // Argument count - - slc_type = lookup_selector(s->segMan, object, selector_id, NULL, &address); - - if (slc_type == kSelectorNone) { - warning("Selector '%s' of object at %04x:%04x could not be invoked (%s L%d)", - ((SciEngine*)g_engine)->getKernel()->getSelectorName(selector_id).c_str(), PRINT_REG(object), fname, line); - if (noinvalid == kStopOnInvalidSelector) - error("[Kernel] Not recoverable: VM was halted"); - return 1; - } - if (slc_type == kSelectorVariable) // Swallow silently - return 0; - - va_start(argp, argc); - for (i = 0; i < argc; i++) { - reg_t arg = va_arg(argp, reg_t); - stackframe[2 + i] = arg; // Write each argument - } - va_end(argp); - - // Write "kernel" call to the stack, for debugging: - ExecStack *xstack; - xstack = add_exec_stack_entry(s, NULL_REG, NULL, NULL_REG, k_argc, k_argp - 1, 0, NULL_REG, - s->_executionStack.size()-1, SCI_XS_CALLEE_LOCALS); - xstack->selector = -42 - kfunct; // Evil debugging hack to identify kernel function - xstack->type = EXEC_STACK_TYPE_KERNEL; - - // Now commit the actual function: - xstack = send_selector(s, object, object, stackframe, framesize, stackframe); - - xstack->sp += argc + 2; - xstack->fp += argc + 2; - - run_vm(s, 0); // Start a new vm - - s->_executionStack.pop_back(); // Get rid of the extra stack entry - - return 0; -} - // Loads arbitrary resources of type 'restype' with resource numbers 'resnrs' // This implementation ignores all resource numbers except the first one. reg_t kLoad(EngineState *s, int, int argc, reg_t *argv) { diff --git a/engines/sci/engine/selector.cpp b/engines/sci/engine/selector.cpp new file mode 100644 index 0000000000..2886bd0c77 --- /dev/null +++ b/engines/sci/engine/selector.cpp @@ -0,0 +1,211 @@ +/* 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 "sci/sci.h" +#include "sci/engine/state.h" + +namespace Sci { + +reg_t read_selector(SegManager *segMan, reg_t object, Selector selector_id, const char *file, int line) { + ObjVarRef address; + + if (lookup_selector(segMan, object, selector_id, &address, NULL) != kSelectorVariable) + return NULL_REG; + else + return *address.getPointer(segMan); +} + +void write_selector(SegManager *segMan, reg_t object, Selector selector_id, reg_t value, const char *fname, int line) { + ObjVarRef address; + + if ((selector_id < 0) || (selector_id > (int)((SciEngine*)g_engine)->getKernel()->getSelectorNamesSize())) { + warning("Attempt to write to invalid selector %d of" + " object at %04x:%04x (%s L%d).", selector_id, PRINT_REG(object), fname, line); + return; + } + + if (lookup_selector(segMan, object, selector_id, &address, NULL) != kSelectorVariable) + warning("Selector '%s' of object at %04x:%04x could not be" + " written to (%s L%d)", ((SciEngine*)g_engine)->getKernel()->getSelectorName(selector_id).c_str(), PRINT_REG(object), fname, line); + else + *address.getPointer(segMan) = value; +} + +int invoke_selector(EngineState *s, reg_t object, int selector_id, SelectorInvocation noinvalid, int kfunct, + StackPtr k_argp, int k_argc, const char *fname, int line, int argc, ...) { + va_list argp; + int i; + int framesize = 2 + 1 * argc; + reg_t address; + int slc_type; + StackPtr stackframe = k_argp + k_argc; + + stackframe[0] = make_reg(0, selector_id); // The selector we want to call + stackframe[1] = make_reg(0, argc); // Argument count + + slc_type = lookup_selector(s->segMan, object, selector_id, NULL, &address); + + if (slc_type == kSelectorNone) { + warning("Selector '%s' of object at %04x:%04x could not be invoked (%s L%d)", + ((SciEngine*)g_engine)->getKernel()->getSelectorName(selector_id).c_str(), PRINT_REG(object), fname, line); + if (noinvalid == kStopOnInvalidSelector) + error("[Kernel] Not recoverable: VM was halted"); + return 1; + } + if (slc_type == kSelectorVariable) // Swallow silently + return 0; + + va_start(argp, argc); + for (i = 0; i < argc; i++) { + reg_t arg = va_arg(argp, reg_t); + stackframe[2 + i] = arg; // Write each argument + } + va_end(argp); + + // Write "kernel" call to the stack, for debugging: + ExecStack *xstack; + xstack = add_exec_stack_entry(s, NULL_REG, NULL, NULL_REG, k_argc, k_argp - 1, 0, NULL_REG, + s->_executionStack.size()-1, SCI_XS_CALLEE_LOCALS); + xstack->selector = -42 - kfunct; // Evil debugging hack to identify kernel function + xstack->type = EXEC_STACK_TYPE_KERNEL; + + // Now commit the actual function: + xstack = send_selector(s, object, object, stackframe, framesize, stackframe); + + xstack->sp += argc + 2; + xstack->fp += argc + 2; + + run_vm(s, 0); // Start a new vm + + s->_executionStack.pop_back(); // Get rid of the extra stack entry + + return 0; +} + +static int _obj_locate_varselector(SegManager *segMan, Object *obj, Selector slc) { + // Determines if obj explicitly defines slc as a varselector + // Returns -1 if not found + byte *buf; + uint varnum; + + if (getSciVersion() < SCI_VERSION_1_1) { + varnum = obj->variable_names_nr; + int selector_name_offset = varnum * 2 + SCRIPT_SELECTOR_OFFSET; + buf = obj->base_obj + selector_name_offset; + } else { + if (!(obj->getInfoSelector().offset & SCRIPT_INFO_CLASS)) + obj = segMan->getObject(obj->getSuperClassSelector()); + + buf = (byte *)obj->base_vars; + varnum = obj->_variables[1].toUint16(); + } + + for (uint i = 0; i < varnum; i++) + if (READ_LE_UINT16(buf + (i << 1)) == slc) // Found it? + return i; // report success + + return -1; // Failed +} + +static int _class_locate_funcselector(Object *obj, Selector slc) { + // Determines if obj is a class and explicitly defines slc as a funcselector + // Does NOT say anything about obj's superclasses, i.e. failure may be + // returned even if one of the superclasses defines the funcselector. + int funcnum = obj->methods_nr; + int i; + + for (i = 0; i < funcnum; i++) + if (obj->getFuncSelector(i) == slc) // Found it? + return i; // report success + + return -1; // Failed +} + +static SelectorType _lookup_selector_function(SegManager *segMan, int seg_id, Object *obj, Selector selector_id, reg_t *fptr) { + int index; + + // "recursive" lookup + + while (obj) { + index = _class_locate_funcselector(obj, selector_id); + + if (index >= 0) { + if (fptr) { + *fptr = obj->getFunction(index); + } + + return kSelectorMethod; + } else { + seg_id = obj->getSuperClassSelector().segment; + obj = segMan->getObject(obj->getSuperClassSelector()); + } + } + + return kSelectorNone; +} + +SelectorType lookup_selector(SegManager *segMan, reg_t obj_location, Selector selector_id, ObjVarRef *varp, reg_t *fptr) { + Object *obj = segMan->getObject(obj_location); + Object *species; + int index; + bool oldScriptHeader = (getSciVersion() == SCI_VERSION_0_EARLY); + + // Early SCI versions used the LSB in the selector ID as a read/write + // toggle, meaning that we must remove it for selector lookup. + if (oldScriptHeader) + selector_id &= ~1; + + if (!obj) { + error("lookup_selector(): Attempt to send to non-object or invalid script. Address was %04x:%04x", + PRINT_REG(obj_location)); + } + + if (obj->isClass()) + species = obj; + else + species = segMan->getObject(obj->getSpeciesSelector()); + + + if (!obj) { + error("lookup_selector(): Error while looking up Species class.\nOriginal address was %04x:%04x. Species address was %04x:%04x", + PRINT_REG(obj_location), PRINT_REG(obj->getSpeciesSelector())); + return kSelectorNone; + } + + index = _obj_locate_varselector(segMan, obj, selector_id); + + if (index >= 0) { + // Found it as a variable + if (varp) { + varp->obj = obj_location; + varp->varindex = index; + } + return kSelectorVariable; + } + + return _lookup_selector_function(segMan, obj_location.segment, obj, selector_id, fptr); +} + +} // End of namespace Sci diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp index b114af1034..be09cd5de0 100644 --- a/engines/sci/engine/vm.cpp +++ b/engines/sci/engine/vm.cpp @@ -1393,110 +1393,6 @@ void run_vm(EngineState *s, int restoring) { } } -static int _obj_locate_varselector(SegManager *segMan, Object *obj, Selector slc) { - // Determines if obj explicitly defines slc as a varselector - // Returns -1 if not found - byte *buf; - uint varnum; - - if (getSciVersion() < SCI_VERSION_1_1) { - varnum = obj->variable_names_nr; - int selector_name_offset = varnum * 2 + SCRIPT_SELECTOR_OFFSET; - buf = obj->base_obj + selector_name_offset; - } else { - if (!(obj->getInfoSelector().offset & SCRIPT_INFO_CLASS)) - obj = segMan->getObject(obj->getSuperClassSelector()); - - buf = (byte *)obj->base_vars; - varnum = obj->_variables[1].toUint16(); - } - - for (uint i = 0; i < varnum; i++) - if (READ_LE_UINT16(buf + (i << 1)) == slc) // Found it? - return i; // report success - - return -1; // Failed -} - -static int _class_locate_funcselector(Object *obj, Selector slc) { - // Determines if obj is a class and explicitly defines slc as a funcselector - // Does NOT say anything about obj's superclasses, i.e. failure may be - // returned even if one of the superclasses defines the funcselector. - int funcnum = obj->methods_nr; - int i; - - for (i = 0; i < funcnum; i++) - if (obj->getFuncSelector(i) == slc) // Found it? - return i; // report success - - return -1; // Failed -} - -static SelectorType _lookup_selector_function(SegManager *segMan, int seg_id, Object *obj, Selector selector_id, reg_t *fptr) { - int index; - - // "recursive" lookup - - while (obj) { - index = _class_locate_funcselector(obj, selector_id); - - if (index >= 0) { - if (fptr) { - *fptr = obj->getFunction(index); - } - - return kSelectorMethod; - } else { - seg_id = obj->getSuperClassSelector().segment; - obj = segMan->getObject(obj->getSuperClassSelector()); - } - } - - return kSelectorNone; -} - -SelectorType lookup_selector(SegManager *segMan, reg_t obj_location, Selector selector_id, ObjVarRef *varp, reg_t *fptr) { - Object *obj = segMan->getObject(obj_location); - Object *species; - int index; - bool oldScriptHeader = (getSciVersion() == SCI_VERSION_0_EARLY); - - // Early SCI versions used the LSB in the selector ID as a read/write - // toggle, meaning that we must remove it for selector lookup. - if (oldScriptHeader) - selector_id &= ~1; - - if (!obj) { - error("lookup_selector(): Attempt to send to non-object or invalid script. Address was %04x:%04x", - PRINT_REG(obj_location)); - } - - if (obj->isClass()) - species = obj; - else - species = segMan->getObject(obj->getSpeciesSelector()); - - - if (!obj) { - error("lookup_selector(): Error while looking up Species class.\nOriginal address was %04x:%04x. Species address was %04x:%04x", - PRINT_REG(obj_location), PRINT_REG(obj->getSpeciesSelector())); - return kSelectorNone; - } - - index = _obj_locate_varselector(segMan, obj, selector_id); - - if (index >= 0) { - // Found it as a variable - if (varp) { - varp->obj = obj_location; - varp->varindex = index; - } - return kSelectorVariable; - } - - return _lookup_selector_function(segMan, obj_location.segment, obj, selector_id, fptr); -} - #define INST_LOOKUP_CLASS(id) ((id == 0xffff)? NULL_REG : segMan->getClassAddress(id, SCRIPT_GET_LOCK, reg)) int script_instantiate_common(ResourceManager *resMan, SegManager *segMan, int script_nr, Resource **script, Resource **heap, int *was_new) { diff --git a/engines/sci/module.mk b/engines/sci/module.mk index d8775e0e57..1c1a930e31 100644 --- a/engines/sci/module.mk +++ b/engines/sci/module.mk @@ -30,6 +30,7 @@ MODULE_OBJS = \ engine/savegame.o \ engine/script.o \ engine/scriptdebug.o \ + engine/selector.o \ engine/seg_manager.o \ engine/segment.o \ engine/static_selectors.o \ |