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:
parent
b2b08cc606
commit
b0c1cf52e0
12 changed files with 121 additions and 129 deletions
|
@ -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);
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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?
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue