VM will no longer block cooperative multitasking.
This commit is contained in:
parent
eb5e4e567e
commit
626befa664
1 changed files with 56 additions and 57 deletions
|
|
@ -20,6 +20,11 @@
|
|||
// Prototypes
|
||||
// ============================================================
|
||||
|
||||
// Steps to execute between doEvents yields during subroutine calls.
|
||||
// This keeps the GUI responsive without excessive overhead from
|
||||
// calling doEvents on every instruction.
|
||||
#define SUB_YIELD_INTERVAL 500
|
||||
|
||||
static BasCallFrameT *currentFrame(BasVmT *vm);
|
||||
static void defaultPrint(void *ctx, const char *text, bool newline);
|
||||
static BasVmResultE execArith(BasVmT *vm, uint8_t op);
|
||||
|
|
@ -37,6 +42,51 @@ static uint16_t readUint16(BasVmT *vm);
|
|||
static void runtimeError(BasVmT *vm, int32_t errNum, const char *msg);
|
||||
|
||||
|
||||
// ============================================================
|
||||
// runSubLoop -- shared inner loop for basVmCallSub variants
|
||||
// ============================================================
|
||||
//
|
||||
// Executes instructions until callDepth drops back to savedCallDepth
|
||||
// (meaning the subroutine returned). Periodically yields via the
|
||||
// doEvents callback to keep the GUI responsive during long-running
|
||||
// event handlers.
|
||||
|
||||
static bool runSubLoop(BasVmT *vm, int32_t savedPc, int32_t savedCallDepth, bool savedRunning) {
|
||||
int32_t stepsSinceYield = 0;
|
||||
|
||||
while (vm->running && vm->callDepth > savedCallDepth) {
|
||||
BasVmResultE result = basVmStep(vm);
|
||||
|
||||
if (result == BAS_VM_HALTED) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (result != BAS_VM_OK) {
|
||||
vm->pc = savedPc;
|
||||
vm->callDepth = savedCallDepth;
|
||||
vm->running = savedRunning;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Yield periodically to keep the GUI responsive
|
||||
if (++stepsSinceYield >= SUB_YIELD_INTERVAL) {
|
||||
stepsSinceYield = 0;
|
||||
|
||||
if (vm->doEventsFn) {
|
||||
if (!vm->doEventsFn(vm->doEventsCtx)) {
|
||||
vm->running = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vm->pc = savedPc;
|
||||
vm->running = savedRunning;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// ============================================================
|
||||
// basVmCallSub
|
||||
// ============================================================
|
||||
|
|
@ -70,26 +120,7 @@ bool basVmCallSub(BasVmT *vm, int32_t codeAddr) {
|
|||
vm->pc = codeAddr;
|
||||
vm->running = true;
|
||||
|
||||
// Run until the SUB returns (callDepth drops back).
|
||||
// No step limit -- event handlers must run to completion.
|
||||
while (vm->running && vm->callDepth > savedCallDepth) {
|
||||
BasVmResultE result = basVmStep(vm);
|
||||
|
||||
if (result == BAS_VM_HALTED) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (result != BAS_VM_OK) {
|
||||
vm->pc = savedPc;
|
||||
vm->callDepth = savedCallDepth;
|
||||
vm->running = savedRunning;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
vm->pc = savedPc;
|
||||
vm->running = savedRunning;
|
||||
return true;
|
||||
return runSubLoop(vm, savedPc, savedCallDepth, savedRunning);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -127,24 +158,7 @@ bool basVmCallSubWithArgs(BasVmT *vm, int32_t codeAddr, const BasValueT *args, i
|
|||
vm->pc = codeAddr;
|
||||
vm->running = true;
|
||||
|
||||
while (vm->running && vm->callDepth > savedCallDepth) {
|
||||
BasVmResultE result = basVmStep(vm);
|
||||
|
||||
if (result == BAS_VM_HALTED) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (result != BAS_VM_OK) {
|
||||
vm->pc = savedPc;
|
||||
vm->callDepth = savedCallDepth;
|
||||
vm->running = savedRunning;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
vm->pc = savedPc;
|
||||
vm->running = savedRunning;
|
||||
return true;
|
||||
return runSubLoop(vm, savedPc, savedCallDepth, savedRunning);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -181,25 +195,12 @@ bool basVmCallSubWithArgsOut(BasVmT *vm, int32_t codeAddr, const BasValueT *args
|
|||
vm->pc = codeAddr;
|
||||
vm->running = true;
|
||||
|
||||
while (vm->running && vm->callDepth > savedCallDepth) {
|
||||
BasVmResultE result = basVmStep(vm);
|
||||
bool ok = runSubLoop(vm, savedPc, savedCallDepth, savedRunning);
|
||||
|
||||
if (result == BAS_VM_HALTED) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (result != BAS_VM_OK) {
|
||||
vm->pc = savedPc;
|
||||
vm->callDepth = savedCallDepth;
|
||||
vm->running = savedRunning;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Read back modified locals before restoring state.
|
||||
// Read back modified locals before the frame is reused.
|
||||
// The frame at savedCallDepth still has the data even
|
||||
// though callDepth was decremented by RET.
|
||||
if (outArgs && outCount > 0) {
|
||||
if (ok && outArgs && outCount > 0) {
|
||||
BasCallFrameT *doneFrame = &vm->callStack[savedCallDepth];
|
||||
|
||||
for (int32_t i = 0; i < outCount && i < BAS_VM_MAX_LOCALS; i++) {
|
||||
|
|
@ -207,9 +208,7 @@ bool basVmCallSubWithArgsOut(BasVmT *vm, int32_t codeAddr, const BasValueT *args
|
|||
}
|
||||
}
|
||||
|
||||
vm->pc = savedPc;
|
||||
vm->running = savedRunning;
|
||||
return true;
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue