diff --git a/engine/vm.c b/engine/vm.c index 3e57b4c..280967e 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -1832,6 +1832,7 @@ static sxi32 VmByteCodeDump( } /* Forward declaration */ static int VmObConsumer(const void *pData, unsigned int nDataLen, void *pUserData); +static sxi32 VmExecFinallyBlock(ph7_vm *pVm, ph7_exception *pException); static sxi32 VmUncaughtException(ph7_vm *pVm, ph7_class_instance *pThis); static sxi32 VmThrowException(ph7_vm *pVm, ph7_class_instance *pThis); /* @@ -8081,6 +8082,30 @@ static int vm_builtin_debug_backtrace(ph7_context *pCtx, int nArg, ph7_value **a */ return PH7_OK; } +static sxi32 VmExecFinallyBlock( + ph7_vm *pVm, /* Target VM */ + ph7_exception *pException /* Exception thrown */ +) { + sxi32 rc; + VmFrame *pFrame = pVm->pFrame; + while(pFrame->pParent && (pFrame->iFlags & VM_FRAME_EXCEPTION)) { + /* Safely ignore the exception frame */ + pFrame = pFrame->pParent; + } + /* Create a private frame first */ + rc = VmEnterFrame(&(*pVm), 0, 0, &pFrame); + if(rc == SXRET_OK) { + /* Mark as 'finally' frame */ + pFrame->iFlags |= VM_FRAME_FINALLY; + /* Execute the block */ + rc = VmLocalExec(&(*pVm), &pException->sFinally, 0); + /* Release the bytecode container */ + SySetRelease(&pException->sFinally); + /* Leave the frame */ + VmLeaveFrame(&(*pVm)); + } + return rc; +} /* * The following routine is invoked by the engine when an uncaught * exception is triggered.