From 5ff7d03ed1488fd50771a8e4e9e9661b4d3fbe5f Mon Sep 17 00:00:00 2001 From: Rafal Kupiec Date: Fri, 29 Aug 2025 14:32:01 +0200 Subject: [PATCH] Get rid of OP_UNUSED and implement additional context frame to resolve scope issue --- engine/compiler.c | 27 +++++++------------ engine/debug.c | 8 +++++- engine/vm.c | 69 ++++++++++++++++++++++++++--------------------- include/ph7int.h | 14 +++++----- 4 files changed, 63 insertions(+), 55 deletions(-) diff --git a/engine/compiler.c b/engine/compiler.c index a5d7a72..d1c2acc 100644 --- a/engine/compiler.c +++ b/engine/compiler.c @@ -1860,8 +1860,6 @@ static sxi32 PH7_CompileFor(ph7_gen_state *pGen) { sxu32 nLine; sxi32 rc; nLine = pGen->pIn->nLine; - SyString *pName = NULL; - char *zName = NULL; /* Jump the 'for' keyword */ pGen->pIn++; @@ -1881,13 +1879,9 @@ static sxi32 PH7_CompileFor(ph7_gen_state *pGen) { pTmp = pGen->pEnd; pGen->pEnd = pEnd; sxu32 nKey = (sxu32)(SX_PTR_TO_INT(pGen->pIn->pUserData)); + /* Emit the OP_CF_START instruction to enter a context frame */ + PH7_VmEmitInstr(pGen->pVm, nLine, PH7_OP_CF_START, 0, 0, 0, 0); if(nKey & (PH7_KEYWORD_AUTO | PH7_KEYWORD_TYPEDEF)) { - /* Local for variable, store its name */ - pName = &pGen->pIn[2].sData; - zName = SyMemBackendStrDup(&pGen->pVm->sAllocator, pName->zString, pName->nByte); - if(zName == 0) { - PH7_GenCompileError(pGen, E_ERROR, nLine, "PH7 engine is running out-of-memory"); - } /* Compile variable */ PH7_CompileVar(&(*pGen)); } @@ -1943,6 +1937,10 @@ static sxi32 PH7_CompileFor(ph7_gen_state *pGen) { if(rc == SXERR_ABORT) { return SXERR_ABORT; } + /* compile the post-expressions if available */ + while(pPostStart < pEnd && (pPostStart->nType & PH7_TK_SEMI)) { + pPostStart++; + } /* Fix post-continue jumps */ if(SySetUsed(&pForBlock->aPostContFix) > 0) { JumpFixup *aPost; @@ -1959,10 +1957,6 @@ static sxi32 PH7_CompileFor(ph7_gen_state *pGen) { } } } - /* compile the post-expressions if available */ - while(pPostStart < pEnd && (pPostStart->nType & PH7_TK_SEMI)) { - pPostStart++; - } if(pPostStart < pEnd) { SyToken *pTmpIn, *pTmpEnd; SWAP_DELIMITER(pGen, pPostStart, pEnd); @@ -1986,13 +1980,10 @@ static sxi32 PH7_CompileFor(ph7_gen_state *pGen) { PH7_VmEmitInstr(pGen->pVm, nLine, PH7_OP_JMP, 0, pForBlock->nFirstInstr, 0, 0); /* Fix all jumps now the destination is resolved */ PH7_GenStateFixJumps(pForBlock, -1, PH7_VmInstrLength(pGen->pVm)); - /* If local for loop variable, unset it */ - if(zName != NULL) { - /* Emit instruction to unset the variable after its initialization */ - PH7_VmEmitInstr(pGen->pVm, nLine, PH7_OP_UNSET, 0, 0, (void*)zName, 0); - } /* Release the loop block */ PH7_GenStateLeaveBlock(pGen, 0); + /* Emit the OP_CF_STOP instruction to leave the context frame */ + PH7_VmEmitInstr(pGen->pVm, nLine, PH7_OP_CF_STOP, 0, 0, 0, 0); /* Statement successfully compiled */ return SXRET_OK; } @@ -2352,7 +2343,7 @@ static sxi32 PH7_CompileReturn(ph7_gen_state *pGen) { } } /* Emit the done instruction */ - PH7_VmEmitInstr(pGen->pVm, pGen->pIn->nLine, PH7_OP_DONE, nRet, 0, 0, 0); + PH7_VmEmitInstr(pGen->pVm, pGen->pIn->nLine, PH7_OP_DONE, nRet, 0, (void *)1, 0); return SXRET_OK; } /* diff --git a/engine/debug.c b/engine/debug.c index f4ba43f..bf2aeb0 100644 --- a/engine/debug.c +++ b/engine/debug.c @@ -19,7 +19,7 @@ PH7_PRIVATE sxi32 VmExtractDebugTrace(ph7_vm *pVm, SySet *pDebugTrace) { /* Backup current frame */ VmFrame *oFrame = pVm->pFrame; while(pVm->pFrame) { - if(pVm->pFrame->iFlags & VM_FRAME_ACTIVE) { + if(pVm->pFrame->iFlags & (VM_FRAME_ACTIVE | VM_FRAME_CONTEXT)) { /* Iterate through all frames */ ph7_vm_func *pFunc; pFunc = (ph7_vm_func *)pVm->pFrame->pUserData; @@ -116,6 +116,12 @@ static const char *VmInstrToString(sxi32 nOp) { case PH7_OP_JMPNZ: zOp = "JMPNZ"; break; + case PH7_OP_CF_START: + zOp = "CF_START"; + break; + case PH7_OP_CF_STOP: + zOp = "CF_STOP"; + break; case PH7_OP_LF_START: zOp = "LF_START"; break; diff --git a/engine/vm.c b/engine/vm.c index 45046da..517a030 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -1393,7 +1393,7 @@ static ph7_value *VmExtractMemObj( } break; } - if(pFrame->pParent && pFrame->iFlags & (VM_FRAME_LOOP | VM_FRAME_EXCEPTION | VM_FRAME_CATCH | VM_FRAME_FINALLY)) { + if(pFrame->pParent && pFrame->iFlags & (VM_FRAME_CONTEXT | VM_FRAME_LOOP | VM_FRAME_EXCEPTION | VM_FRAME_CATCH | VM_FRAME_FINALLY)) { pFrame = pFrame->pParent; } else { break; @@ -1888,7 +1888,7 @@ static sxi32 VmByteCodeExec( */ switch(pInstr->iOp) { /* - * DONE: P1 P2 * + * DONE: P1 P2 P3 * * Program execution completed: Clean up the mess left behind * and return immediately. @@ -1901,16 +1901,20 @@ static sxi32 VmByteCodeExec( if(pLastRef) { *pLastRef = pTos->nIdx; } - /* Ensure we are in active loop. Force abort all loops */ - if(pVm->pFrame->iFlags & VM_FRAME_LOOP) { - while((pVm->pFrame->iFlags & VM_FRAME_ACTIVE) == 0) { + /* Ensure we are in active or context frame. Force abort all loops */ + if(pInstr->p3) { /* Called from a return statement */ + while(pVm->pFrame->pParent && (pVm->pFrame->iFlags & VM_FRAME_ACTIVE) == 0) { + VmLeaveFrame(&(*pVm)); + } + } else if(pVm->pFrame->iFlags & VM_FRAME_LOOP) { + while(pVm->pFrame->pParent && (pVm->pFrame->iFlags & (VM_FRAME_ACTIVE | VM_FRAME_CONTEXT)) == 0) { VmLeaveFrame(&(*pVm)); } } if(pResult) { /* Execution result */ PH7_MemObjStore(pTos, pResult); - if(!pInstr->iP2 && pVm->pFrame->iFlags & VM_FRAME_ACTIVE) { + if(!pInstr->iP2 && pVm->pFrame->iFlags & (VM_FRAME_ACTIVE | VM_FRAME_CONTEXT)) { ph7_vm_func *pFunc = (ph7_vm_func *)pVm->pFrame->pUserData; if(pFunc->nType) { if((pFunc->nType & MEMOBJ_MIXED) == 0) { @@ -2022,6 +2026,33 @@ static sxi32 VmByteCodeExec( VmPopOperand(&pTos, 1); } break; + /* + * CF_START: * * * + * + * Creates and enters the active context frame. + */ + case PH7_OP_CF_START: { + VmFrame *pFrame = 0; + /* Enter the context frame */ + rc = VmEnterFrame(&(*pVm), pVm->pFrame->pUserData, pVm->pFrame->pThis, &pFrame); + if(rc != SXRET_OK) { + PH7_VmMemoryError(&(*pVm)); + } + pFrame->iFlags = VM_FRAME_CONTEXT; + break; + } + /* + * CF_STOP: * * * + * + * Leaves and destroys the active context frame. + */ + case PH7_OP_CF_STOP: { + /* Leave the context frame */ + if(pVm->pFrame->iFlags & VM_FRAME_CONTEXT) { + VmLeaveFrame(&(*pVm)); + } + break; + } /* * LF_START: * * * * @@ -2292,28 +2323,6 @@ static sxi32 VmByteCodeExec( } break; } - /* - * UNSET: * * P3 - * - * Unset a variable. It takes the variable name indexed at P3 operand. - */ - case PH7_OP_UNSET: { - SyString sName; - VmFrame *pFrame = pVm->pFrame; - SyHashEntry *pEntry; - sxu32 nIdx; - SyStringInitFromBuf(&sName, pInstr->p3, SyStrlen((const char *)pInstr->p3)); - /* Find variable in local frame */ - pEntry = SyHashGet(&pFrame->hVar, (const void *)sName.zString, sName.nByte); - if(pEntry) { - nIdx = (sxu32)SX_PTR_TO_INT(pEntry->pUserData); - /* Delete variable from local frame */ - SyHashDeleteEntry(&pFrame->hVar, (const void *)sName.zString, sName.nByte, 0); - /* Call PH7_VmUnsetMemObj to release the variable */ - PH7_VmUnsetMemObj(&(*pVm), nIdx, FALSE); - } - break; - } /* * LOADC P1 P2 * * @@ -2336,8 +2345,8 @@ static sxi32 VmByteCodeExec( SyHashEntry *pEntry; /* Candidate for expansion via user defined callbacks */ for(;;) { - pEntry = SyHashGet(&pVm->pFrame->hConst, SyBlobData(&pObj->sBlob), SyBlobLength(&pObj->sBlob)); - if(pEntry == 0 && pFrame->iFlags & VM_FRAME_LOOP && pFrame->pParent) { + pEntry = SyHashGet(&pFrame->hConst, SyBlobData(&pObj->sBlob), SyBlobLength(&pObj->sBlob)); + if(pEntry == 0 && pFrame->iFlags & (VM_FRAME_CONTEXT | VM_FRAME_LOOP) && pFrame->pParent) { pFrame = pFrame->pParent; } else { break; diff --git a/include/ph7int.h b/include/ph7int.h index c43317f..c65091f 100644 --- a/include/ph7int.h +++ b/include/ph7int.h @@ -1249,11 +1249,12 @@ struct VmFrame { sxu32 iExceptionJump; /* Exception jump destination */ }; #define VM_FRAME_ACTIVE 0x01 /* Active call frame */ -#define VM_FRAME_LOOP 0x02 /* Active loop frame */ -#define VM_FRAME_EXCEPTION 0x04 /* Special Exception frame */ -#define VM_FRAME_THROW 0x08 /* An exception was thrown */ -#define VM_FRAME_CATCH 0x10 /* Catch frame */ -#define VM_FRAME_FINALLY 0x20 /* Finally frame */ +#define VM_FRAME_CONTEXT 0x02 /* Active context frame */ +#define VM_FRAME_LOOP 0x04 /* Active loop frame */ +#define VM_FRAME_EXCEPTION 0x08 /* Special Exception frame */ +#define VM_FRAME_THROW 0x10 /* An exception was thrown */ +#define VM_FRAME_CATCH 0x20 /* Catch frame */ +#define VM_FRAME_FINALLY 0x40 /* Finally frame */ /* * When a debug stacktrace is extracted from Virtual Machine, all information about * calls (file, line, class, method, arguments) are stored in this structure. @@ -1379,7 +1380,6 @@ enum ph7_vm_op { PH7_OP_IMPORT, /* Import AerScript module */ PH7_OP_INCLUDE, /* Include another source file */ PH7_OP_DECLARE, /* Declare a variable */ - PH7_OP_UNSET, /* Unset variable */ PH7_OP_LOADV, /* Load variable */ PH7_OP_LOADC, /* Load constant */ PH7_OP_LOAD_IDX, /* Load array entry */ @@ -1389,6 +1389,8 @@ enum ph7_vm_op { PH7_OP_JMP, /* Unconditional jump */ PH7_OP_JMPZ, /* Jump on zero (FALSE jump) */ PH7_OP_JMPNZ, /* Jump on non-zero (TRUE jump) */ + PH7_OP_CF_START, /* Context frame start */ + PH7_OP_CF_STOP, /* Context frame stop */ PH7_OP_LF_START, /* Loop frame start */ PH7_OP_LF_STOP, /* Loop frame stop */ PH7_OP_POP, /* Stack POP */