Preserve pending completions through finally and restore operand stack on unwind
Build / AerScript (push) Successful in 38s

This commit is contained in:
2026-10-26 20:43:57 +01:00
parent d912ddf4df
commit 3c83579fb6
4 changed files with 479 additions and 351 deletions
+48 -21
View File
@@ -1450,6 +1450,33 @@ static sxi32 PH7_CompileBreak(ph7_gen_state *pGen) {
/* Statement successfully compiled */
return SXRET_OK;
}
/* Out-of-stream handlers and includes share the ordinary loop cleanup and
* fixups through small bridges in their immediately enclosing bytecode. */
static void GenStateCompileLoopBridge(ph7_gen_state *pGen, ph7_include *pBridge,
GenBlock *pLoop, sxu32 nLine) {
sxu32 nSkip;
SyToken sToken;
SyToken *pSavedIn = pGen->pIn, *pSavedEnd = pGen->pEnd;
pBridge->nBreak = pBridge->nContinue = SXU32_HIGH;
if(pLoop == 0) {
return;
}
PH7_VmEmitInstr(pGen->pVm, 0, PH7_OP_JMP, 0, 0, 0, &nSkip);
pBridge->nBreak = PH7_VmInstrLength(pGen->pVm);
SyZero(&sToken, sizeof(sToken));
sToken.nLine = nLine;
pGen->pIn = &sToken;
pGen->pEnd = &sToken + 1;
PH7_CompileBreak(pGen);
if((pLoop->iFlags & GEN_BLOCK_SWITCH) == 0) {
pBridge->nContinue = PH7_VmInstrLength(pGen->pVm);
pGen->pIn = &sToken;
PH7_CompileContinue(pGen);
}
pGen->pIn = pSavedIn;
pGen->pEnd = pSavedEnd;
PH7_VmGetInstr(pGen->pVm, nSkip)->iP2 = PH7_VmInstrLength(pGen->pVm);
}
/*
* Compile or record a label.
* A label is a target point that is specified by an identifier followed by a colon.
@@ -2784,7 +2811,6 @@ static sxi32 PH7_CompileInclude(ph7_gen_state *pGen) {
ph7_include *pInclude = (ph7_include *)SyMemBackendAlloc(&pGen->pVm->sAllocator, sizeof(ph7_include));
GenBlock *pBlock = pGen->pCurrent;
GenBlock *pLoop = PH7_GenStateFetchBlock(pBlock, GEN_BLOCK_LOOP, 0);
sxu32 nSkip;
if(pInclude == 0) {
PH7_GenCompileError(pGen, E_ERROR, nLine, "PH7 is running out-of-memory");
}
@@ -2800,26 +2826,7 @@ static sxi32 PH7_CompileInclude(ph7_gen_state *pGen) {
}
pInclude->pFunc = pBlock ? (ph7_vm_func *)pBlock->pUserData : 0;
PH7_VmEmitInstr(pGen->pVm, nLine, PH7_OP_INCLUDE, 0, 1, pInclude, 0);
if(pLoop) {
PH7_VmEmitInstr(pGen->pVm, 0, PH7_OP_JMP, 0, 0, 0, &nSkip);
pInclude->nBreak = PH7_VmInstrLength(pGen->pVm);
/* Reuse the ordinary compiler's loop cleanup and forward fixups. */
SyToken sToken;
SyToken *pSavedIn = pGen->pIn, *pSavedEnd = pGen->pEnd;
SyZero(&sToken, sizeof(sToken));
sToken.nLine = nLine;
pGen->pIn = &sToken;
pGen->pEnd = &sToken + 1;
PH7_CompileBreak(pGen);
if((pLoop->iFlags & GEN_BLOCK_SWITCH) == 0) {
pInclude->nContinue = PH7_VmInstrLength(pGen->pVm);
pGen->pIn = &sToken;
PH7_CompileContinue(pGen);
}
pGen->pIn = pSavedIn;
pGen->pEnd = pSavedEnd;
PH7_VmGetInstr(pGen->pVm, nSkip)->iP2 = PH7_VmInstrLength(pGen->pVm);
}
GenStateCompileLoopBridge(pGen, pInclude, pLoop, nLine);
}
return SXRET_OK;
}
@@ -4275,6 +4282,8 @@ static sxi32 PH7_CompileThrow(ph7_gen_state *pGen) {
*/
static sxi32 PH7_CompileCatch(ph7_gen_state *pGen, ph7_exception *pException) {
ph7_exception_block sCatch;
ph7_include sLoopBridge;
GenBlock *pLoop = PH7_GenStateFetchBlock(pGen->pCurrent, GEN_BLOCK_LOOP, 0);
SySet *pInstrContainer;
GenBlock *pCatch;
SyToken *pToken;
@@ -4337,6 +4346,7 @@ static sxi32 PH7_CompileCatch(ph7_gen_state *pGen, ph7_exception *pException) {
/* Compile the block */
pGen->pIn++; /* Jump the right parenthesis */
/* Create the catch block */
GenStateCompileLoopBridge(pGen, &sLoopBridge, pLoop, pGen->pIn->nLine);
rc = PH7_GenStateEnterBlock(&(*pGen), GEN_BLOCK_EXCEPTION, PH7_VmInstrLength(pGen->pVm), 0, &pCatch);
if(rc != SXRET_OK) {
return SXERR_ABORT;
@@ -4344,8 +4354,15 @@ static sxi32 PH7_CompileCatch(ph7_gen_state *pGen, ph7_exception *pException) {
/* Swap bytecode container */
pInstrContainer = PH7_VmGetByteCodeContainer(pGen->pVm);
PH7_VmSetByteCodeContainer(pGen->pVm, &sCatch.sByteCode);
if(pLoop) {
PH7_GenStateEnterBlock(pGen, GEN_BLOCK_LOOP | GEN_BLOCK_INCLUDE |
(pLoop->iFlags & GEN_BLOCK_SWITCH), 0, &sLoopBridge, 0);
}
/* Compile the block */
PH7_CompileBlock(&(*pGen));
if(pLoop) {
PH7_GenStateLeaveBlock(pGen, 0);
}
/* Fix forward jumps now the destination is resolved */
PH7_GenStateFixJumps(pCatch, -1, PH7_VmInstrLength(pGen->pVm));
/* Emit the DONE instruction */
@@ -4371,8 +4388,11 @@ static sxi32 PH7_CompileCatch(ph7_gen_state *pGen, ph7_exception *pException) {
static sxi32 PH7_CompileFinally(ph7_gen_state *pGen, ph7_exception *pException) {
SySet *pInstrContainer;
GenBlock *pFinally;
ph7_include sLoopBridge;
GenBlock *pLoop = PH7_GenStateFetchBlock(pGen->pCurrent, GEN_BLOCK_LOOP, 0);
sxi32 rc;
pGen->pIn++; /* Jump the 'finally' keyword */
GenStateCompileLoopBridge(pGen, &sLoopBridge, pLoop, pGen->pIn->nLine);
rc = PH7_GenStateEnterBlock(&(*pGen), GEN_BLOCK_EXCEPTION, PH7_VmInstrLength(pGen->pVm), 0, &pFinally);
if(rc != SXRET_OK) {
return SXERR_ABORT;
@@ -4380,8 +4400,15 @@ static sxi32 PH7_CompileFinally(ph7_gen_state *pGen, ph7_exception *pException)
/* Swap bytecode container */
pInstrContainer = PH7_VmGetByteCodeContainer(pGen->pVm);
PH7_VmSetByteCodeContainer(pGen->pVm, &pException->sFinally);
if(pLoop) {
PH7_GenStateEnterBlock(pGen, GEN_BLOCK_LOOP | GEN_BLOCK_INCLUDE |
(pLoop->iFlags & GEN_BLOCK_SWITCH), 0, &sLoopBridge, 0);
}
/* Compile the block */
PH7_CompileBlock(&(*pGen));
if(pLoop) {
PH7_GenStateLeaveBlock(pGen, 0);
}
/* Fix forward jumps now the destination is resolved */
PH7_GenStateFixJumps(pFinally, -1, PH7_VmInstrLength(pGen->pVm));
/* Emit the DONE instruction */