Evaluate local constants once per declaration and invocation
Build / AerScript (push) Successful in 40s

This commit is contained in:
2026-10-25 19:57:49 +01:00
parent 8a2d7d8bd3
commit 85f59a2998
+42 -10
View File
@@ -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;