SCI: Got rid of EngineState::execution_stack_pos; overally, the resulting code should be even stricter in detecting invalid VM stack access (and some bugs when loading saves might be fixed now...)

svn-id: r40694
This commit is contained in:
Max Horn 2009-05-18 18:15:45 +00:00
parent b2b08cc606
commit b0c1cf52e0
12 changed files with 121 additions and 129 deletions

View file

@ -430,7 +430,6 @@ int script_init_engine(EngineState *s, sci_version_t version) {
s->_executionStack.clear(); // Start without any execution stack s->_executionStack.clear(); // Start without any execution stack
s->execution_stack_base = -1; // No vm is running yet s->execution_stack_base = -1; // No vm is running yet
s->execution_stack_pos = -1; // Start at execution stack position 0
vocabulary_get_knames(s->resmgr, s->_kernelNames); vocabulary_get_knames(s->resmgr, s->_kernelNames);
script_map_kernel(s); script_map_kernel(s);

View file

@ -86,7 +86,7 @@ reg_t_hash_map *find_all_used_references(EngineState *s) {
// Init: Value Stack // Init: Value Stack
// We do this one by hand since the stack doesn't know the current execution stack // We do this one by hand since the stack doesn't know the current execution stack
{ {
ExecStack &xs = s->_executionStack[s->execution_stack_pos]; ExecStack &xs = s->_executionStack.back();
reg_t *pos; reg_t *pos;
for (pos = s->stack_base; pos < xs.sp; pos++) for (pos = s->stack_base; pos < xs.sp; pos++)
@ -97,7 +97,7 @@ reg_t_hash_map *find_all_used_references(EngineState *s) {
#endif #endif
// Init: Execution Stack // Init: Execution Stack
for (i = 0; (int)i <= s->execution_stack_pos; i++) { for (i = 0; i < s->_executionStack.size(); i++) {
ExecStack &es = s->_executionStack[i]; ExecStack &es = s->_executionStack[i];
if (es.type != EXEC_STACK_TYPE_KERNEL) { if (es.type != EXEC_STACK_TYPE_KERNEL) {

View file

@ -263,7 +263,7 @@ reg_t kRestartGame(EngineState *s, int funct_nr, int argc, reg_t *argv) {
old_save_dir = strdup(deref_save_dir); old_save_dir = strdup(deref_save_dir);
s->restarting_flags |= SCI_GAME_IS_RESTARTING_NOW; s->restarting_flags |= SCI_GAME_IS_RESTARTING_NOW;
s->restarting_flags &= ~SCI_GAME_WAS_RESTARTED_AT_LEAST_ONCE; // This appears to help s->restarting_flags &= ~SCI_GAME_WAS_RESTARTED_AT_LEAST_ONCE; // This appears to help
s->execution_stack_pos = s->execution_stack_base; s->_executionStack.resize(s->execution_stack_base + 1);
script_abort_flag = 1; // Force vm to abort ASAP script_abort_flag = 1; // Force vm to abort ASAP
return NULL_REG; return NULL_REG;
} }

View file

@ -652,7 +652,7 @@ reg_t kRestoreGame(EngineState *s, int funct_nr, int argc, reg_t *argv) {
if (newstate) { if (newstate) {
s->successor = newstate; s->successor = newstate;
script_abort_flag = SCRIPT_ABORT_WITH_REPLAY; // Abort current game script_abort_flag = SCRIPT_ABORT_WITH_REPLAY; // Abort current game
s->execution_stack_pos = s->execution_stack_base; s->_executionStack.resize(s->execution_stack_base + 1);
} else { } else {
s->r_acc = make_reg(0, 1); s->r_acc = make_reg(0, 1);
sciprintf("Restoring failed (game_id = '%s').\n", game_id); sciprintf("Restoring failed (game_id = '%s').\n", game_id);

View file

@ -92,7 +92,7 @@ int invoke_selector(EngineState *s, reg_t object, int selector_id, int noinvalid
// Write "kernel" call to the stack, for debugging: // Write "kernel" call to the stack, for debugging:
xstack = add_exec_stack_entry(s, NULL_REG, NULL, NULL_REG, k_argc, k_argp - 1, 0, NULL_REG, xstack = add_exec_stack_entry(s, NULL_REG, NULL, NULL_REG, k_argc, k_argp - 1, 0, NULL_REG,
s->execution_stack_pos, SCI_XS_CALLEE_LOCALS); s->_executionStack.size()-1, SCI_XS_CALLEE_LOCALS);
xstack->selector = -42 - kfunct; // Evil debugging hack to identify kernel function xstack->selector = -42 - kfunct; // Evil debugging hack to identify kernel function
xstack->type = EXEC_STACK_TYPE_KERNEL; xstack->type = EXEC_STACK_TYPE_KERNEL;
@ -104,7 +104,7 @@ int invoke_selector(EngineState *s, reg_t object, int selector_id, int noinvalid
run_vm(s, 0); // Start a new vm run_vm(s, 0); // Start a new vm
--(s->execution_stack_pos); // Get rid of the extra stack entry s->_executionStack.pop_back(); // Get rid of the extra stack entry
return 0; return 0;
} }
@ -269,7 +269,7 @@ reg_t kDisposeScript(EngineState *s, int funct_nr, int argc, reg_t *argv) {
int id = s->seg_manager->segGet(script); int id = s->seg_manager->segGet(script);
Script *scr = s->seg_manager->getScriptIfLoaded(id); Script *scr = s->seg_manager->getScriptIfLoaded(id);
if (scr) { if (scr) {
if (s->_executionStack[s->execution_stack_pos].addr.pc.segment != id) if (s->_executionStack.back().addr.pc.segment != id)
scr->setLockers(1); scr->setLockers(1);
} }

View file

@ -794,7 +794,7 @@ EngineState *gamestate_restore(EngineState *s, Common::SeekableReadStream *fh) {
// Set exec stack base to zero // Set exec stack base to zero
retval->execution_stack_base = 0; retval->execution_stack_base = 0;
retval->execution_stack_pos = 0; retval->_executionStack.clear();
// Now copy all current state information // Now copy all current state information
// Graphics and input state: // Graphics and input state:

View file

@ -221,10 +221,10 @@ int parse_reg_t(EngineState *s, const char *str, reg_t *dest) { // Returns 0 on
rel_offsetting = 1; rel_offsetting = 1;
if (!scumm_strnicmp(str + 1, "PC", 2)) { if (!scumm_strnicmp(str + 1, "PC", 2)) {
*dest = s->_executionStack[s->execution_stack_pos].addr.pc; *dest = s->_executionStack.back().addr.pc;
offsetting = str + 3; offsetting = str + 3;
} else if (!scumm_strnicmp(str + 1, "P", 1)) { } else if (!scumm_strnicmp(str + 1, "P", 1)) {
*dest = s->_executionStack[s->execution_stack_pos].addr.pc; *dest = s->_executionStack.back().addr.pc;
offsetting = str + 2; offsetting = str + 2;
} else if (!scumm_strnicmp(str + 1, "PREV", 4)) { } else if (!scumm_strnicmp(str + 1, "PREV", 4)) {
*dest = s->r_prev; *dest = s->r_prev;
@ -236,10 +236,10 @@ int parse_reg_t(EngineState *s, const char *str, reg_t *dest) { // Returns 0 on
*dest = s->r_acc; *dest = s->r_acc;
offsetting = str + 2; offsetting = str + 2;
} else if (!scumm_strnicmp(str + 1, "OBJ", 3)) { } else if (!scumm_strnicmp(str + 1, "OBJ", 3)) {
*dest = s->_executionStack[s->execution_stack_pos].objp; *dest = s->_executionStack.back().objp;
offsetting = str + 4; offsetting = str + 4;
} else if (!scumm_strnicmp(str + 1, "O", 1)) { } else if (!scumm_strnicmp(str + 1, "O", 1)) {
*dest = s->_executionStack[s->execution_stack_pos].objp; *dest = s->_executionStack.back().objp;
offsetting = str + 2; offsetting = str + 2;
} else } else
return 1; // No matching register return 1; // No matching register

View file

@ -692,7 +692,7 @@ int c_debuginfo(EngineState *s) {
sciprintf("acc="PREG" prev="PREG" &rest=%x\n", PRINT_REG(s->r_acc), PRINT_REG(s->r_prev), *p_restadjust); sciprintf("acc="PREG" prev="PREG" &rest=%x\n", PRINT_REG(s->r_acc), PRINT_REG(s->r_prev), *p_restadjust);
if (!s->_executionStack.empty() && s->execution_stack_pos >= 0) { if (!s->_executionStack.empty()) {
sciprintf("pc="PREG" obj="PREG" fp="PSTK" sp="PSTK"\n", PRINT_REG(*p_pc), PRINT_REG(*p_objp), PRINT_STK(*p_pp), PRINT_STK(*p_sp)); sciprintf("pc="PREG" obj="PREG" fp="PSTK" sp="PSTK"\n", PRINT_REG(*p_pc), PRINT_REG(*p_objp), PRINT_STK(*p_pp), PRINT_STK(*p_sp));
} else } else
sciprintf("<no execution stack: pc,obj,fp omitted>\n"); sciprintf("<no execution stack: pc,obj,fp omitted>\n");
@ -728,7 +728,7 @@ int c_stepover(EngineState *s, const Common::Array<cmd_param_t> &cmdParams) {
if (opnumber == 0x22 /* callb */ || opnumber == 0x23 /* calle */ || if (opnumber == 0x22 /* callb */ || opnumber == 0x23 /* calle */ ||
opnumber == 0x25 /* send */ || opnumber == 0x2a /* self */ || opnumber == 0x2b /* super */) { opnumber == 0x25 /* send */ || opnumber == 0x2a /* self */ || opnumber == 0x2b /* super */) {
_debug_seeking = _DEBUG_SEEK_SO; _debug_seeking = _DEBUG_SEEK_SO;
_debug_seek_level = s->execution_stack_pos; _debug_seek_level = s->_executionStack.size()-1;
// Store in _debug_seek_special the offset of the next command after send // Store in _debug_seek_special the offset of the next command after send
switch (opcode) { switch (opcode) {
case 0x46: // calle W case 0x46: // calle W
@ -1103,7 +1103,7 @@ int c_restore_game(EngineState *s, const Common::Array<cmd_param_t> &cmdParams)
script_abort_flag = SCRIPT_ABORT_WITH_REPLAY; // Abort current game script_abort_flag = SCRIPT_ABORT_WITH_REPLAY; // Abort current game
_debugstate_valid = 0; _debugstate_valid = 0;
s->execution_stack_pos = s->execution_stack_base; s->_executionStack.resize(s->execution_stack_base + 1);
return 0; return 0;
} else { } else {
sciprintf("Restoring gamestate '%s' failed.\n", cmdParams[0].str); sciprintf("Restoring gamestate '%s' failed.\n", cmdParams[0].str);
@ -1151,12 +1151,12 @@ int c_stack(EngineState *s, const Common::Array<cmd_param_t> &cmdParams) {
return 1; return 1;
} }
if (s->execution_stack_pos < 0) { if (s->_executionStack.empty()) {
sciprintf("No exec stack!"); sciprintf("No exec stack!");
return 1; return 1;
} }
ExecStack &xs = s->_executionStack[s->execution_stack_pos]; ExecStack &xs = s->_executionStack.back();
for (int i = cmdParams[0].val ; i > 0; i--) { for (int i = cmdParams[0].val ; i > 0; i--) {
if ((xs.sp - xs.fp - i) == 0) if ((xs.sp - xs.fp - i) == 0)
@ -1526,15 +1526,13 @@ int c_vmvars(EngineState *s, const Common::Array<cmd_param_t> &cmdParams) {
} }
static int c_backtrace(EngineState *s, const Common::Array<cmd_param_t> &cmdParams) { static int c_backtrace(EngineState *s, const Common::Array<cmd_param_t> &cmdParams) {
int i;
if (!_debugstate_valid) { if (!_debugstate_valid) {
sciprintf("Not in debug state\n"); sciprintf("Not in debug state\n");
return 1; return 1;
} }
sciprintf("Call stack (current base: 0x%x):\n", s->execution_stack_base); sciprintf("Call stack (current base: 0x%x):\n", s->execution_stack_base);
for (i = 0; i <= s->execution_stack_pos; i++) { for (uint i = 0; i < s->_executionStack.size(); i++) {
ExecStack &call = s->_executionStack[i]; ExecStack &call = s->_executionStack[i];
const char *objname = obj_get_name(s, call.sendp); const char *objname = obj_get_name(s, call.sendp);
int paramc, totalparamc; int paramc, totalparamc;
@ -2121,7 +2119,7 @@ static int c_snk(EngineState *s, const Common::Array<cmd_param_t> &cmdParams) {
static int c_sret(EngineState *s, const Common::Array<cmd_param_t> &cmdParams) { static int c_sret(EngineState *s, const Common::Array<cmd_param_t> &cmdParams) {
_debug_seeking = _DEBUG_SEEK_LEVEL_RET; _debug_seeking = _DEBUG_SEEK_LEVEL_RET;
_debug_seek_level = s->execution_stack_pos; _debug_seek_level = s->_executionStack.size()-1;
_debugstate_valid = 0; _debugstate_valid = 0;
return 0; return 0;
} }
@ -2176,7 +2174,7 @@ static int c_send(EngineState *s, const Common::Array<cmd_param_t> &cmdParams) {
stackframe[i] = cmdParams[i].reg; stackframe[i] = cmdParams[i].reg;
xstack = add_exec_stack_entry(s, fptr, s->_executionStack[0].sp + cmdParams.size(), object, cmdParams.size() - 2, xstack = add_exec_stack_entry(s, fptr, s->_executionStack[0].sp + cmdParams.size(), object, cmdParams.size() - 2,
s->_executionStack[0].sp - 1, 0, object, s->execution_stack_pos, SCI_XS_CALLEE_LOCALS); s->_executionStack[0].sp - 1, 0, object, s->_executionStack.size()-1, SCI_XS_CALLEE_LOCALS);
xstack->selector = selector_id; xstack->selector = selector_id;
xstack->type = selector_type == kSelectorVariable ? EXEC_STACK_TYPE_VARSELECTOR : EXEC_STACK_TYPE_CALL; xstack->type = selector_type == kSelectorVariable ? EXEC_STACK_TYPE_VARSELECTOR : EXEC_STACK_TYPE_CALL;
@ -2904,13 +2902,13 @@ void script_debug(EngineState *s, reg_t *pc, StackPtr *sp, StackPtr *pp, reg_t *
} }
case _DEBUG_SEEK_LEVEL_RET: { case _DEBUG_SEEK_LEVEL_RET: {
if ((op != op_ret) || (_debug_seek_level < s->execution_stack_pos)) if ((op != op_ret) || (_debug_seek_level < (int)s->_executionStack.size()-1))
return; return;
break; break;
} }
case _DEBUG_SEEK_SO: case _DEBUG_SEEK_SO:
if (!REG_EQ(*pc, _debug_seek_reg) || s->execution_stack_pos != _debug_seek_level) if (!REG_EQ(*pc, _debug_seek_reg) || (int)s->_executionStack.size()-1 != _debug_seek_level)
return; return;
break; break;
@ -2920,7 +2918,7 @@ void script_debug(EngineState *s, reg_t *pc, StackPtr *sp, StackPtr *pp, reg_t *
return; return;
if ((op & 0x3) > 1) if ((op & 0x3) > 1)
return; // param or temp return; // param or temp
if ((op & 0x3) && s->_executionStack[s->execution_stack_pos].local_segment > 0) if ((op & 0x3) && s->_executionStack.back().local_segment > 0)
return; // locals and not running in script.000 return; // locals and not running in script.000
if (paramf1 != _debug_seek_special) if (paramf1 != _debug_seek_special)
return; // CORRECT global? return; // CORRECT global?

View file

@ -104,7 +104,6 @@ EngineState::EngineState() : _dirseeker(this) {
kernel_opt_flags = 0; kernel_opt_flags = 0;
execution_stack_pos = 0;
execution_stack_base = 0; execution_stack_base = 0;
_executionStackPosChanged = false; _executionStackPosChanged = false;

View file

@ -208,7 +208,6 @@ public:
/* VM Information */ /* VM Information */
Common::Array<ExecStack> _executionStack; /**< The execution stack */ Common::Array<ExecStack> _executionStack; /**< The execution stack */
int execution_stack_pos; /**< Position on the execution stack */
/** /**
* When called from kernel functions, the vm is re-started recursively on * When called from kernel functions, the vm is re-started recursively on
* the same stack. This variable contains the stack base for the current vm. * the same stack. This variable contains the stack base for the current vm.

View file

@ -279,49 +279,43 @@ ExecStack *execute_method(EngineState *s, uint16 script, uint16 pubfunct, StackP
} }
} }
return add_exec_stack_entry(s, make_reg(seg, temp), sp, calling_obj, argc, argp, -1, calling_obj, s->execution_stack_pos, seg); return add_exec_stack_entry(s, make_reg(seg, temp), sp, calling_obj, argc, argp, -1, calling_obj, s->_executionStack.size()-1, seg);
} }
static void _exec_varselectors(EngineState *s) { static void _exec_varselectors(EngineState *s) {
// Executes all varselector read/write ops on the TOS // Executes all varselector read/write ops on the TOS
// Now check the TOS to execute all varselector entries // Now check the TOS to execute all varselector entries
if (s->execution_stack_pos >= 0) if (!s->_executionStack.empty())
while (s->_executionStack[s->execution_stack_pos].type == EXEC_STACK_TYPE_VARSELECTOR) { while (s->_executionStack.back().type == EXEC_STACK_TYPE_VARSELECTOR) {
// varselector access? // varselector access?
if (s->_executionStack[s->execution_stack_pos].argc) { // write? if (s->_executionStack.back().argc) { // write?
reg_t temp = s->_executionStack[s->execution_stack_pos].variables_argp[1]; reg_t temp = s->_executionStack.back().variables_argp[1];
*(s->_executionStack[s->execution_stack_pos].addr.varp) = temp; *(s->_executionStack.back().addr.varp) = temp;
} else // No, read } else // No, read
s->r_acc = *(s->_executionStack[s->execution_stack_pos].addr.varp); s->r_acc = *(s->_executionStack.back().addr.varp);
--(s->execution_stack_pos); s->_executionStack.pop_back();
} }
} }
ExecStack *send_selector(EngineState *s, reg_t send_obj, reg_t work_obj, StackPtr sp, int framesize, StackPtr argp) { ExecStack *send_selector(EngineState *s, reg_t send_obj, reg_t work_obj, StackPtr sp, int framesize, StackPtr argp) {
// send_obj and work_obj are equal for anything but 'super' // send_obj and work_obj are equal for anything but 'super'
// Returns a pointer to the TOS exec_stack element // Returns a pointer to the TOS exec_stack element
#ifdef VM_DEBUG_SEND assert(s);
int i;
#endif
reg_t *varp; reg_t *varp;
reg_t funcp; reg_t funcp;
int selector; int selector;
int argc; int argc;
int origin = s->execution_stack_pos; // Origin: Used for debugging int origin = s->_executionStack.size()-1; // Origin: Used for debugging
int print_send_action = 0; int print_send_action = 0;
// We return a pointer to the new active ExecStack // We return a pointer to the new active ExecStack
// The selector calls we catch are stored below: // The selector calls we catch are stored below:
Common::Stack<CallsStruct> sendCalls; Common::Stack<CallsStruct> sendCalls;
if (NULL == s) {
sciprintf("vm.c: ExecStack(): NULL passed for \"s\"\n");
return NULL;
}
while (framesize > 0) { while (framesize > 0) {
selector = validate_arithmetic(*argp++); selector = validate_arithmetic(*argp++);
argc = validate_arithmetic(*argp); argc = validate_arithmetic(*argp);
@ -423,7 +417,7 @@ ExecStack *send_selector(EngineState *s, reg_t send_obj, reg_t work_obj, StackPt
#ifdef VM_DEBUG_SEND #ifdef VM_DEBUG_SEND
sciprintf("Funcselector("); sciprintf("Funcselector(");
for (i = 0; i < argc; i++) { for (int i = 0; i < argc; i++) {
sciprintf(PREG, PRINT_REG(argp[i+1])); sciprintf(PREG, PRINT_REG(argp[i+1]));
if (i + 1 < argc) if (i + 1 < argc)
sciprintf(", "); sciprintf(", ");
@ -467,7 +461,9 @@ ExecStack *send_selector(EngineState *s, reg_t send_obj, reg_t work_obj, StackPt
_exec_varselectors(s); _exec_varselectors(s);
return &(s->_executionStack[s->execution_stack_pos]); if (s->_executionStack.empty())
return NULL;
return &(s->_executionStack.back());
} }
ExecStack *add_exec_stack_varselector(EngineState *s, reg_t objp, int argc, StackPtr argp, Selector selector, reg_t *address, int origin) { ExecStack *add_exec_stack_varselector(EngineState *s, reg_t objp, int argc, StackPtr argp, Selector selector, reg_t *address, int origin) {
@ -485,36 +481,34 @@ ExecStack *add_exec_stack_entry(EngineState *s, reg_t pc, StackPtr sp, reg_t obj
// Returns new TOS element for the execution stack // Returns new TOS element for the execution stack
// locals_segment may be -1 if derived from the called object // locals_segment may be -1 if derived from the called object
++s->execution_stack_pos;
if (s->execution_stack_pos >= (int)s->_executionStack.size()) // Out of stack space?
s->_executionStack.resize(s->execution_stack_pos+1);
//sciprintf("Exec stack: [%d/%d], origin %d, at %p\n", s->execution_stack_pos, s->_executionStack.size(), origin, s->execution_stack); //sciprintf("Exec stack: [%d/%d], origin %d, at %p\n", s->execution_stack_pos, s->_executionStack.size(), origin, s->execution_stack);
ExecStack *xstack = &(s->_executionStack[s->execution_stack_pos]); ExecStack xstack;
xstack->objp = objp; xstack.objp = objp;
if (locals_segment != SCI_XS_CALLEE_LOCALS) if (locals_segment != SCI_XS_CALLEE_LOCALS)
xstack->local_segment = locals_segment; xstack.local_segment = locals_segment;
else else
xstack->local_segment = pc.segment; xstack.local_segment = pc.segment;
xstack->sendp = sendp; xstack.sendp = sendp;
xstack->addr.pc = pc; xstack.addr.pc = pc;
xstack->fp = xstack->sp = sp; xstack.fp = xstack.sp = sp;
xstack->argc = argc; xstack.argc = argc;
xstack->variables_argp = argp; // Parameters xstack.variables_argp = argp; // Parameters
*argp = make_reg(0, argc); // SCI code relies on the zeroeth argument to equal argc *argp = make_reg(0, argc); // SCI code relies on the zeroeth argument to equal argc
// Additional debug information // Additional debug information
xstack->selector = selector; xstack.selector = selector;
xstack->origin = origin; xstack.origin = origin;
xstack->type = EXEC_STACK_TYPE_CALL; // Normal call xstack.type = EXEC_STACK_TYPE_CALL; // Normal call
return xstack; s->_executionStack.push_back(xstack);
return &(s->_executionStack.back());
} }
#ifdef DISABLE_VALIDATONS #ifdef DISABLE_VALIDATONS
@ -585,7 +579,7 @@ void run_vm(EngineState *s, int restoring) {
int restadjust = s->r_amp_rest; int restadjust = s->r_amp_rest;
// &rest adjusts the parameter count by this value // &rest adjusts the parameter count by this value
// Current execution data: // Current execution data:
ExecStack *xs = &(s->_executionStack[s->execution_stack_pos]); ExecStack *xs = &(s->_executionStack.back());
ExecStack *xs_new = NULL; ExecStack *xs_new = NULL;
Object *obj = obj_get(s, xs->objp); Object *obj = obj_get(s, xs->objp);
Script *local_script = script_locate_by_segment(s, xs->local_segment); Script *local_script = script_locate_by_segment(s, xs->local_segment);
@ -604,7 +598,7 @@ void run_vm(EngineState *s, int restoring) {
} }
if (!restoring) if (!restoring)
s->execution_stack_base = s->execution_stack_pos; s->execution_stack_base = s->_executionStack.size()-1;
#ifndef DISABLE_VALIDATIONS #ifndef DISABLE_VALIDATIONS
// Initialize maximum variable count // Initialize maximum variable count
@ -640,7 +634,7 @@ void run_vm(EngineState *s, int restoring) {
if (s->_executionStackPosChanged) { if (s->_executionStackPosChanged) {
Script *scr; Script *scr;
xs = &(s->_executionStack[s->execution_stack_pos]); xs = &(s->_executionStack.back());
s->_executionStackPosChanged = false; s->_executionStackPosChanged = false;
scr = script_locate_by_segment(s, xs->addr.pc.segment); scr = script_locate_by_segment(s, xs->addr.pc.segment);
@ -988,7 +982,7 @@ void run_vm(EngineState *s, int restoring) {
xs->sp[1].offset += restadjust; xs->sp[1].offset += restadjust;
xs_new = add_exec_stack_entry(s, make_reg(xs->addr.pc.segment, xs->addr.pc.offset + opparams[0]), xs_new = add_exec_stack_entry(s, make_reg(xs->addr.pc.segment, xs->addr.pc.offset + opparams[0]),
xs->sp, xs->objp, (validate_arithmetic(*call_base)) + restadjust, xs->sp, xs->objp, (validate_arithmetic(*call_base)) + restadjust,
call_base, NULL_SELECTOR, xs->objp, s->execution_stack_pos, xs->local_segment); call_base, NULL_SELECTOR, xs->objp, s->_executionStack.size()-1, xs->local_segment);
restadjust = 0; // Used up the &rest adjustment restadjust = 0; // Used up the &rest adjustment
xs->sp = call_base; xs->sp = call_base;
@ -1026,7 +1020,7 @@ void run_vm(EngineState *s, int restoring) {
// Calculate xs again: The kernel function might // Calculate xs again: The kernel function might
// have spawned a new VM // have spawned a new VM
xs_new = &(s->_executionStack[s->execution_stack_pos]); xs_new = &(s->_executionStack.back());
s->_executionStackPosChanged = true; s->_executionStackPosChanged = true;
if (!(s->flags & GF_SCI0_OLD)) if (!(s->flags & GF_SCI0_OLD))
@ -1064,12 +1058,12 @@ void run_vm(EngineState *s, int restoring) {
do { do {
StackPtr old_sp2 = xs->sp; StackPtr old_sp2 = xs->sp;
StackPtr old_fp = xs->fp; StackPtr old_fp = xs->fp;
ExecStack *old_xs = &(s->_executionStack[s->execution_stack_pos]); ExecStack *old_xs = &(s->_executionStack.back());
if (s->execution_stack_pos == s->execution_stack_base) { // Have we reached the base? if ((int)s->_executionStack.size()-1 == s->execution_stack_base) { // Have we reached the base?
s->execution_stack_base = old_execution_stack_base; // Restore stack base s->execution_stack_base = old_execution_stack_base; // Restore stack base
--(s->execution_stack_pos); s->_executionStack.pop_back();
s->_executionStackPosChanged = true; s->_executionStackPosChanged = true;
s->r_amp_rest = restadjust; // Update &rest s->r_amp_rest = restadjust; // Update &rest
@ -1085,10 +1079,10 @@ void run_vm(EngineState *s, int restoring) {
} }
// Not reached the base, so let's do a soft return // Not reached the base, so let's do a soft return
--(s->execution_stack_pos); s->_executionStack.pop_back();
xs = old_xs - 1; xs = old_xs - 1;
s->_executionStackPosChanged = true; s->_executionStackPosChanged = true;
xs = &(s->_executionStack[s->execution_stack_pos]); xs = &(s->_executionStack.back());
if (xs->sp == CALL_SP_CARRY // Used in sends to 'carry' the stack pointer if (xs->sp == CALL_SP_CARRY // Used in sends to 'carry' the stack pointer
|| xs->type != EXEC_STACK_TYPE_CALL) { || xs->type != EXEC_STACK_TYPE_CALL) {
@ -1452,8 +1446,8 @@ void run_vm(EngineState *s, int restoring) {
xs = xs_new; xs = xs_new;
#ifndef DISABLE_VALIDATIONS #ifndef DISABLE_VALIDATIONS
if (xs != &(s->_executionStack[s->execution_stack_pos])) { if (xs != &(s->_executionStack.back())) {
sciprintf("Error: xs is stale (%d vs %d); last command was %02x\n", (int)(xs - &s->_executionStack[0]), s->execution_stack_pos, opnumber); sciprintf("Error: xs is stale (%d vs %d); last command was %02x\n", (int)(xs - &s->_executionStack[0]), s->_executionStack.size()-1, opnumber);
} }
#endif #endif
if (script_error_flag) { if (script_error_flag) {
@ -1991,7 +1985,6 @@ static EngineState *_game_run(EngineState *s, int restoring) {
if (s->restarting_flags & SCI_GAME_IS_RESTARTING_NOW) { // Restart was requested? if (s->restarting_flags & SCI_GAME_IS_RESTARTING_NOW) { // Restart was requested?
successor = NULL; successor = NULL;
s->_executionStack.clear(); s->_executionStack.clear();
s->execution_stack_pos = -1;
s->_executionStackPosChanged = false; s->_executionStackPosChanged = false;
game_exit(s); game_exit(s);
@ -2017,7 +2010,7 @@ static EngineState *_game_run(EngineState *s, int restoring) {
if (script_abort_flag == SCRIPT_ABORT_WITH_REPLAY) { if (script_abort_flag == SCRIPT_ABORT_WITH_REPLAY) {
sciprintf("Restarting with replay()\n"); sciprintf("Restarting with replay()\n");
s->execution_stack_pos = -1; // Restart with replay s->_executionStack.clear(); // Restart with replay
_init_stack_base_with_selector(s, s->selector_map.replay); _init_stack_base_with_selector(s, s->selector_map.replay);

View file

@ -808,73 +808,77 @@ typedef int kernel_function(struct EngineState *s);
extern kernel_function* kfuncs[]; extern kernel_function* kfuncs[];
extern int max_instance; extern int max_instance;
/*inline*/ /**
* Executes function pubfunct of the specified script.
* Parameters: (EngineState *) s: The state which is to be executed with
* (uint16) script: The script which is called
* (uint16) pubfunct: The exported script function which is to be called
* (StackPtr) sp: Stack pointer position
* (reg_t) calling_obj: The heap address of the object which executed the call
* (uint16) argc: Number of arguments supplied
* (StackPtr) argp: Pointer to the first supplied argument
* Returns : (ExecStack *): A pointer to the new exec stack TOS entry
*/
ExecStack *execute_method(EngineState *s, uint16 script, uint16 pubfunct, StackPtr sp, reg_t calling_obj, ExecStack *execute_method(EngineState *s, uint16 script, uint16 pubfunct, StackPtr sp, reg_t calling_obj,
uint16 argc, StackPtr argp); uint16 argc, StackPtr argp);
/* Executes function pubfunct of the specified script.
** Parameters: (EngineState *) s: The state which is to be executed with
** (uint16) script: The script which is called
** (uint16) pubfunct: The exported script function which is to be called
** (StackPtr) sp: Stack pointer position
** (reg_t) calling_obj: The heap address of the object which executed the call
** (uint16) argc: Number of arguments supplied
** (StackPtr) argp: Pointer to the first supplied argument
** Returns : (ExecStack *): A pointer to the new exec stack TOS entry
*/
/**
* Executes a "send" or related operation to a selector.
* Parameters: (EngineState *) s: The EngineState to operate on
* (reg_t) send_obj: Heap address of the object to send to
* (reg_t) work_obj: Heap address of the object initiating the send
* (StackPtr) sp: Stack pointer position
* (int) framesize: Size of the send as determined by the "send" operation
* (StackPtr) argp: Pointer to the beginning of the heap block containing the
* data to be sent. This area is a succession of one or more
* sequences of [selector_number][argument_counter] and then
* "argument_counter" word entries with the parameter values.
* Returns : (ExecStack *): A pointer to the new execution stack TOS entry
*/
ExecStack *send_selector(EngineState *s, reg_t send_obj, reg_t work_obj, ExecStack *send_selector(EngineState *s, reg_t send_obj, reg_t work_obj,
StackPtr sp, int framesize, StackPtr argp); StackPtr sp, int framesize, StackPtr argp);
/* Executes a "send" or related operation to a selector
** Parameters: (EngineState *) s: The EngineState to operate on
** (reg_t) send_obj: Heap address of the object to send to
** (reg_t) work_obj: Heap address of the object initiating the send
** (StackPtr) sp: Stack pointer position
** (int) framesize: Size of the send as determined by the "send" operation
** (StackPtr) argp: Pointer to the beginning of the heap block containing the
** data to be send. This area is a succession of one or more
** sequences of [selector_number][argument_counter] and then
** "argument_counter" word entries with the parameter values.
** Returns : (ExecStack *): A pointer to the new execution stack TOS entry
*/
#define SCI_XS_CALLEE_LOCALS -1 #define SCI_XS_CALLEE_LOCALS -1
/**
* Adds an entry to the top of the execution stack.
*
* @param s The state with which to execute
* @param pc The initial program counter
* @param sp The initial stack pointer
* @param objp Pointer to the beginning of the current object
* @param argc Number of parameters to call with
* @param argp Heap pointer to the first parameter
* @param selector The selector by which it was called or
* NULL_SELECTOR if n.a. For debugging.
* @param sendp Pointer to the object which the message was sent to.
* Equal to objp for anything but super.
* @param origin Number of the execution stack element this entry was created by
* (usually the current TOS number, except for multiple sends).
* @param local_segment The segment to use for local variables,
* or SCI_XS_CALLEE_LOCALS to use obj's segment.
* @return a pointer to the new exec stack TOS entry
*/
ExecStack *add_exec_stack_entry(EngineState *s, reg_t pc, StackPtr sp, reg_t objp, int argc, ExecStack *add_exec_stack_entry(EngineState *s, reg_t pc, StackPtr sp, reg_t objp, int argc,
StackPtr argp, Selector selector, reg_t sendp, int origin, SegmentId local_segment); StackPtr argp, Selector selector, reg_t sendp, int origin, SegmentId local_segment);
/* Adds an entry to the top of the execution stack
** Parameters: (EngineState *) s: The state with which to execute
** (reg_t) pc: The initial program counter
** (StackPtr) sp: The initial stack pointer
** (reg_t) objp: Pointer to the beginning of the current object
** (int) argc: Number of parameters to call with
** (StackPtr) argp: Heap pointer to the first parameter
** (Selector) selector: The selector by which it was called or
** NULL_SELECTOR if n.a. For debugging.
** (reg_t) sendp: Pointer to the object which the message was sent to.
** Equal to objp for anything but super.
** (int) origin: Number of the execution stack element this entry was created by
** (usually the current TOS number, except for multiple sends).
** (SegmentId) local_segment: The segment to use for local variables,
** or SCI_XS_CALLEE_LOCALS to use obj's segment.
** Returns : (ExecStack *): A pointer to the new exec stack TOS entry
*/
/**
* Adds one varselector access to the execution stack.
* Parameters: (EngineState *) s: The EngineState to use
* (reg_t) objp: Pointer to the object owning the selector
* (int) argc: 1 for writing, 0 for reading
* (StackPtr) argp: Pointer to the address of the data to write -2
* (int) selector: Selector name
* (reg_t *) address: Heap address of the selector
* (int) origin: Stack frame which the access originated from
* Returns : (ExecStack *): Pointer to the new exec-TOS element
* This function is called from send_selector only.
*/
ExecStack *add_exec_stack_varselector(EngineState *s, reg_t objp, int argc, StackPtr argp, ExecStack *add_exec_stack_varselector(EngineState *s, reg_t objp, int argc, StackPtr argp,
Selector selector, reg_t *address, int origin); Selector selector, reg_t *address, int origin);
/* Adds one varselector access to the execution stack
** Parameters: (EngineState *) s: The EngineState to use
** (reg_t) objp: Pointer to the object owning the selector
** (int) argc: 1 for writing, 0 for reading
** (StackPtr) argp: Pointer to the address of the data to write -2
** (int) selector: Selector name
** (reg_t *) address: Heap address of the selector
** (int) origin: Stack frame which the access originated from
** Returns : (ExecStack *): Pointer to the new exec-TOS element
** This function is called from send_selector only.
*/
void run_vm(EngineState *s, int restoring); void run_vm(EngineState *s, int restoring);