From 85f59a299815815c970904aad689852556f191f0 Mon Sep 17 00:00:00 2001 From: Rafal Kupiec Date: Sun, 25 Oct 2026 19:57:49 +0100 Subject: [PATCH] Evaluate local constants once per declaration and invocation --- engine/vm.c | 52 ++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 42 insertions(+), 10 deletions(-) diff --git a/engine/vm.c b/engine/vm.c index 75b6b32..686509c 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -492,6 +492,17 @@ static void VmScopeSync(ph7_vm *pVm, VmScopeInfo *pTarget, void *pExec) { } VmScopeEnter(pVm, pTarget, pExec); } +/* Stable, invocation-owned storage: neither bytecode nor moving VM arrays own + * local constant values. Scope exit removes only their visible bindings. */ +typedef struct VmLocalConstant VmLocalConstant; +struct VmLocalConstant { + ph7_constant_info *pDecl; + ph7_value sValue; +}; +static void VmExpandLocalConstant(ph7_value *pVal, void *pUserData) { + VmLocalConstant *pConst = (VmLocalConstant *)pUserData; + PH7_MemObjLoad(&pConst->sValue, pVal); +} /* * Allocate a new virtual machine frame. */ @@ -517,7 +528,7 @@ static VmFrame *VmNewFrame( SySetInit(&pFrame->sArg, &pVm->sAllocator, sizeof(VmSlot)); SySetInit(&pFrame->sLocal, &pVm->sAllocator, sizeof(VmSlot)); SySetInit(&pFrame->sRef, &pVm->sAllocator, sizeof(VmSlot)); - SySetInit(&pFrame->sConstDecl, &pVm->sAllocator, sizeof(void *)); + SySetInit(&pFrame->sConstDecl, &pVm->sAllocator, sizeof(VmLocalConstant *)); return pFrame; } /* @@ -576,6 +587,14 @@ static void VmLeaveFrame(ph7_vm *pVm) { SySetRelease(&pFrame->sArg); SySetRelease(&pFrame->sLocal); SySetRelease(&pFrame->sRef); + { + VmLocalConstant **apConst = (VmLocalConstant **)SySetBasePtr(&pFrame->sConstDecl); + sxu32 n; + for(n = 0; n < SySetUsed(&pFrame->sConstDecl); n++) { + PH7_MemObjRelease(&apConst[n]->sValue); + SyMemBackendPoolFree(&pVm->sAllocator, apConst[n]); + } + } SySetRelease(&pFrame->sConstDecl); /* Release the whole structure */ SyMemBackendPoolFree(&pVm->sAllocator, pFrame); @@ -3071,25 +3090,39 @@ Resume: /* Constant declaration */ ph7_constant_info *pConstInfo = (ph7_constant_info *) pInstr->p3; VmFrame *pOwner = pVm->pFrame; - void **apDecl; + VmLocalConstant **apDecl, *pConst; sxu32 n; while(pOwner->pParent && (pOwner->iFlags & VM_FRAME_ACTIVE) == 0) { pOwner = pOwner->pParent; } - apDecl = (void **)SySetBasePtr(&pOwner->sConstDecl); + apDecl = (VmLocalConstant **)SySetBasePtr(&pOwner->sConstDecl); for(n = 0; n < SySetUsed(&pOwner->sConstDecl); n++) { - if(apDecl[n] == pConstInfo) { + if(apDecl[n]->pDecl == pConstInfo) { PH7_VmThrowError(pVm, PH7_CTX_ERR, "Redeclaration of ā€˜%z’ constant", &pConstInfo->pName); } } - if(SySetPut(&pOwner->sConstDecl, &pConstInfo) != SXRET_OK) { + pConst = (VmLocalConstant *)SyMemBackendPoolAlloc(&pVm->sAllocator, sizeof(VmLocalConstant)); + if(pConst == 0) { PH7_VmMemoryError(pVm); } - rc = PH7_VmRegisterConstant(&(*pVm), &pConstInfo->pName, PH7_VmExpandConstantValue, pConstInfo->pConsCode, FALSE); + pConst->pDecl = pConstInfo; + PH7_MemObjInit(pVm, &pConst->sValue); + if(SySetPut(&pOwner->sConstDecl, &pConst) != SXRET_OK) { + PH7_VmMemoryError(pVm); + } + rc = PH7_VmRegisterConstant(&(*pVm), &pConstInfo->pName, VmExpandLocalConstant, pConst, FALSE); if(rc == SXERR_EXISTS) { PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Redeclaration of ā€˜%z’ constant", &pConstInfo->pName); } + rc = VmLocalExec(pVm, pConstInfo->pConsCode, &pConst->sValue); + if(rc == SXERR_MEM) { + PH7_VmMemoryError(pVm); + } else if(rc == PH7_ABORT) { + goto Abort; + } else if(rc == PH7_EXCEPTION) { + goto Exception; + } } else { /* Variable declaration */ ph7_value *pObj; @@ -6123,10 +6156,9 @@ PH7_PRIVATE sxi32 PH7_VmOutputConsumeAp( return rc; } /* - * Default constant expansion callback used by the 'const' statement if used - * outside a class body [i.e: global or function scope]. - * Refer to the implementation of [PH7_CompileConstant()] defined - * in 'compile.c' for additional information. + * Constant expansion callback used by global constants declared with 'define'. + * Refer to the implementation of [PH7_CompileDefine()] defined + * in 'compiler.c' for additional information. */ PH7_PRIVATE void PH7_VmExpandConstantValue(ph7_value *pVal, void *pUserData) { SySet *pByteCode = (SySet *)pUserData;