Fix block scope for local declarations
Build / AerScript (push) Successful in 40s

This commit is contained in:
2026-10-25 19:22:50 +01:00
parent 3e3b795626
commit 8a2d7d8bd3
4 changed files with 277 additions and 52 deletions
+39 -2
View File
@@ -1595,6 +1595,35 @@ static sxi32 PH7_GenStateNextChunk(ph7_gen_state *pGen) {
pGen->pRawIn++;
return SXRET_OK;
}
/* Attach lexical ancestry after compilation, so nested bytecode containers
* (closures, initializers and handlers) never inherit the caller's scopes. */
static void GenStateCloseScope(ph7_gen_state *pGen, sxu32 nFirst) {
VmScopeInfo *pScope;
VmInstr *pInstr;
sxu32 n, nEnd = PH7_VmInstrLength(pGen->pVm);
pScope = (VmScopeInfo *)SyMemBackendAlloc(&pGen->pVm->sAllocator, sizeof(VmScopeInfo));
if(pScope == 0) {
PH7_VmMemoryError(pGen->pVm);
}
pScope->pParent = 0;
for(n = nFirst; n < nEnd; n++) {
VmScopeInfo *pChild;
pInstr = PH7_VmGetInstr(pGen->pVm, n);
if(pInstr->pScope == 0) {
pInstr->pScope = pScope;
} else {
pChild = pInstr->pScope;
while(pChild->pParent && pChild->pParent != pScope) {
pChild = pChild->pParent;
}
if(pChild != pScope) {
pChild->pParent = pScope;
}
}
}
/* A real target outside the scope, including for empty blocks. */
PH7_VmEmitInstr(pGen->pVm, 0, PH7_OP_NOOP, 0, 0, 0, 0);
}
/*
* Compile an AerScript block.
* A block is simply one or more Aer statements and expressions to compile
@@ -1609,6 +1638,8 @@ static sxi32 PH7_CompileBlock(
sxi32 rc;
if(pGen->pIn->nType & PH7_TK_OCB /* '{' */) {
sxu32 nLine = pGen->pIn->nLine;
sxu32 nScope = PH7_VmInstrLength(pGen->pVm);
PH7_VmEmitInstr(pGen->pVm, nLine, PH7_OP_NOOP, 0, 0, 0, 0);
rc = PH7_GenStateEnterBlock(&(*pGen), GEN_BLOCK_STD, PH7_VmInstrLength(pGen->pVm), 0, 0);
if(rc != SXRET_OK) {
return SXERR_ABORT;
@@ -1637,6 +1668,7 @@ static sxi32 PH7_CompileBlock(
return SXERR_ABORT;
}
}
GenStateCloseScope(pGen, nScope);
PH7_GenStateLeaveBlock(&(*pGen), 0);
} else {
/* Compile a single statement */
@@ -1867,6 +1899,7 @@ static sxi32 PH7_CompileDoWhile(ph7_gen_state *pGen) {
* of using the for truth expression.
*/
static sxi32 PH7_CompileFor(ph7_gen_state *pGen) {
sxu32 nScope = PH7_VmInstrLength(pGen->pVm);
SyToken *pTmp, *pPostStart, *pEnd = 0;
GenBlock *pForBlock = 0;
sxu32 nFalseJump;
@@ -1993,6 +2026,7 @@ static sxi32 PH7_CompileFor(ph7_gen_state *pGen) {
PH7_GenStateFixJumps(pForBlock, -1, PH7_VmInstrLength(pGen->pVm));
/* Release the loop block */
PH7_GenStateLeaveBlock(pGen, 0);
GenStateCloseScope(pGen, nScope);
/* Statement successfully compiled */
return SXRET_OK;
}
@@ -2028,6 +2062,7 @@ static sxi32 GenStateForEachNodeValidator(ph7_gen_state *pGen, ph7_expr_node *pR
* first element of the array. This means that you do not need to call reset() before a foreach loop.
*/
static sxi32 PH7_CompileForeach(ph7_gen_state *pGen) {
sxu32 nScope = PH7_VmInstrLength(pGen->pVm);
SyToken *pCur, *pTmp, *pEnd = 0;
GenBlock *pForeachBlock = 0;
ph7_foreach_info *pInfo;
@@ -2193,6 +2228,7 @@ static sxi32 PH7_CompileForeach(ph7_gen_state *pGen) {
PH7_GenStateFixJumps(pForeachBlock, -1, PH7_VmInstrLength(pGen->pVm));
/* Release the loop block */
PH7_GenStateLeaveBlock(pGen, 0);
GenStateCloseScope(pGen, nScope);
/* Statement successfully compiled */
return SXRET_OK;
}
@@ -2450,8 +2486,6 @@ static sxi32 PH7_CompileVar(ph7_gen_state *pGen) {
if(pGen->pIn < pGen->pEnd && (pGen->pIn->nType & (PH7_TK_COMMA/*','*/ | PH7_TK_SEMI/*';'*/ | PH7_TK_EQUAL/*'='*/)) == 0) {
PH7_GenCompileError(&(*pGen), E_ERROR, pGen->pIn->nLine, "Unexpected token '%z'", &pGen->pIn->sData);
}
/* TODO: Check if static variable exists to avoid redeclaration */
/* Initialize the structure describing the static variable */
SySetInit(&sStatic.aByteCode, &pGen->pVm->sAllocator, sizeof(VmInstr));
sStatic.nIdx = SXU32_HIGH; /* Not yet created */
@@ -2488,6 +2522,9 @@ static sxi32 PH7_CompileVar(ph7_gen_state *pGen) {
sStatic.iFlags = nType;
/* Finally save the compiled static variable in the appropriate container */
SySetPut(&pFunc->aStatic, (const void *)&sStatic);
/* Storage belongs to the declaration; visibility starts here. */
PH7_VmEmitInstr(pGen->pVm, pGen->pIn->nLine, PH7_OP_DECLARE, 2,
SySetUsed(&pFunc->aStatic) - 1, pFunc, 0);
} else {
zDup = SyMemBackendStrDup(&pGen->pVm->sAllocator, pName->zString, pName->nByte);
if(zDup == 0) {
+224 -48
View File
@@ -54,6 +54,7 @@ struct SyhttpHeader {
#define HTTP_PROTO_10 1 /* HTTP/1.0 */
#define HTTP_PROTO_11 2 /* HTTP/1.1 */
#define HTTP_PROTO_20 3 /* HTTP/2.0 */
static void VmScopeRecord(ph7_vm *pVm, const SyString *pName, sxi32 bConst);
/*
* Register a constant and it's associated expansion callback so that
* it can be expanded from the target PHP program.
@@ -82,7 +83,11 @@ PH7_PRIVATE sxi32 PH7_VmRegisterConstant(
if(bGlobal) {
pCollection = &pVm->hConstant;
} else {
pCollection = &pVm->pFrame->hConst;
VmFrame *pFrame = pVm->pFrame;
while(pFrame->pParent && (pFrame->iFlags & VM_FRAME_EXCEPTION)) {
pFrame = pFrame->pParent;
}
pCollection = &pFrame->hConst;
}
pEntry = SyHashGet(pCollection, (const void *)pName->zString, pName->nByte);
if(pEntry) {
@@ -107,6 +112,9 @@ PH7_PRIVATE sxi32 PH7_VmRegisterConstant(
if(rc != SXRET_OK) {
PH7_VmMemoryError(&(*pVm));
}
if(!bGlobal) {
VmScopeRecord(pVm, &pCons->sName, TRUE);
}
/* All done,constant can be invoked from PHP code */
return SXRET_OK;
}
@@ -310,6 +318,7 @@ PH7_PRIVATE sxi32 PH7_VmEmitInstr(
}
/* Fill the VM instruction */
sInstr.iOp = (sxu8)iOp;
sInstr.pScope = 0;
sInstr.iP1 = iP1;
sInstr.iP2 = iP2;
sInstr.p3 = p3;
@@ -386,6 +395,103 @@ PH7_PRIVATE VmInstr *PH7_VmPeekNextInstr(ph7_vm *pVm) {
aInstr = (VmInstr *)SySetBasePtr(pVm->pByteContainer);
return &aInstr[n - 2];
}
/* Names belong to lexical scopes, storage and references to their existing
* owner frame. The execution tag keeps borrowed include/handler frames from
* turning nested bytecode execution into a new variable-visibility boundary. */
typedef struct VmScopeBinding VmScopeBinding;
struct VmScopeBinding {
SyString sName;
sxi32 bConst;
};
struct VmScope {
VmScope *pParent;
VmScopeInfo *pInfo;
VmFrame *pFrame;
void *pExec; /* Execution boundary: includes and handlers borrow their owner */
SySet aBinding;
};
static void VmScopeRecord(ph7_vm *pVm, const SyString *pName, sxi32 bConst) {
VmScope *pScope;
VmFrame *pFrame = pVm->pFrame;
VmScopeBinding sBinding;
while(pFrame->pParent && (pFrame->iFlags & VM_FRAME_EXCEPTION)) {
pFrame = pFrame->pParent;
}
for(pScope = pVm->pScope; pScope; pScope = pScope->pParent) {
if(pScope->pFrame == pFrame) {
sBinding.sName = *pName;
sBinding.bConst = bConst;
if(SySetPut(&pScope->aBinding, &sBinding) != SXRET_OK) {
PH7_VmMemoryError(pVm);
}
break;
}
}
}
static void VmScopeLeave(ph7_vm *pVm) {
VmScope *pScope = pVm->pScope;
VmScopeBinding *aBinding = (VmScopeBinding *)SySetBasePtr(&pScope->aBinding);
sxu32 n;
for(n = 0; n < SySetUsed(&pScope->aBinding); n++) {
VmScopeBinding *pBinding = &aBinding[n];
SyHash *pHash = pBinding->bConst ? &pScope->pFrame->hConst : &pScope->pFrame->hVar;
SyHashEntry *pEntry = SyHashGet(pHash, pBinding->sName.zString, pBinding->sName.nByte);
if(pEntry) {
if(!pBinding->bConst) {
sxu32 nIdx = (sxu32)SX_PTR_TO_INT(pEntry->pUserData);
VmSlot *aRef = (VmSlot *)SySetBasePtr(&pScope->pFrame->sRef);
sxu32 i;
PH7_VmRefObjRemove(pVm, nIdx, pEntry, 0);
for(i = 0; i < SySetUsed(&pScope->pFrame->sRef); i++) {
if(aRef[i].pUserData == pEntry) {
aRef[i].pUserData = 0;
}
}
}
SyHashDeleteEntry2(pEntry);
}
}
/* Values stay in sLocal until frame cleanup. Escaping references and closure
* copies must not be recycled just because their names became invisible. */
pVm->pScope = pScope->pParent;
SySetRelease(&pScope->aBinding);
SyMemBackendPoolFree(&pVm->sAllocator, pScope);
}
static sxi32 VmScopeContains(VmScopeInfo *pScope, VmScopeInfo *pTarget) {
while(pTarget) {
if(pTarget == pScope) {
return TRUE;
}
pTarget = pTarget->pParent;
}
return FALSE;
}
static void VmScopeEnter(ph7_vm *pVm, VmScopeInfo *pInfo, void *pExec) {
VmScope *pScope;
if(pInfo == 0 || (pVm->pScope && pVm->pScope->pExec == pExec && pVm->pScope->pInfo == pInfo)) {
return;
}
VmScopeEnter(pVm, pInfo->pParent, pExec);
pScope = (VmScope *)SyMemBackendPoolAlloc(&pVm->sAllocator, sizeof(VmScope));
if(pScope == 0) {
PH7_VmMemoryError(pVm);
}
pScope->pParent = pVm->pScope;
pScope->pInfo = pInfo;
pScope->pFrame = pVm->pFrame;
while(pScope->pFrame->pParent && (pScope->pFrame->iFlags & VM_FRAME_EXCEPTION)) {
pScope->pFrame = pScope->pFrame->pParent;
}
pScope->pExec = pExec;
SySetInit(&pScope->aBinding, &pVm->sAllocator, sizeof(VmScopeBinding));
pVm->pScope = pScope;
}
static void VmScopeSync(ph7_vm *pVm, VmScopeInfo *pTarget, void *pExec) {
while(pVm->pScope && pVm->pScope->pExec == pExec && !VmScopeContains(pVm->pScope->pInfo, pTarget)) {
VmScopeLeave(pVm);
}
VmScopeEnter(pVm, pTarget, pExec);
}
/*
* Allocate a new virtual machine frame.
*/
@@ -411,6 +517,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 *));
return pFrame;
}
/*
@@ -443,6 +550,9 @@ static sxi32 VmEnterFrame(
static void VmLeaveFrame(ph7_vm *pVm) {
VmFrame *pFrame = pVm->pFrame;
if(pFrame) {
while(pVm->pScope && pVm->pScope->pFrame == pFrame) {
VmScopeLeave(pVm);
}
/* Unlink from the list of active VM frame */
pVm->pFrame = pFrame->pParent;
if(pFrame->pParent && (pFrame->iFlags & VM_FRAME_EXCEPTION) == 0) {
@@ -466,6 +576,7 @@ static void VmLeaveFrame(ph7_vm *pVm) {
SySetRelease(&pFrame->sArg);
SySetRelease(&pFrame->sLocal);
SySetRelease(&pFrame->sRef);
SySetRelease(&pFrame->sConstDecl);
/* Release the whole structure */
SyMemBackendPoolFree(&pVm->sAllocator, pFrame);
}
@@ -1888,8 +1999,12 @@ static ph7_value *VmCreateMemObj(
sxu32 nIdx;
sxi32 rc;
SyHashEntry *pEntry;
VmFrame *pFrame = pVm->pFrame;
while(pFrame->pParent && (pFrame->iFlags & VM_FRAME_EXCEPTION)) {
pFrame = pFrame->pParent;
}
/* Query the top active frame */
pEntry = SyHashGet(&pVm->pFrame->hVar, (const void *)pName->zString, pName->nByte);
pEntry = SyHashGet(&pFrame->hVar, (const void *)pName->zString, pName->nByte);
if(pEntry) {
/* Variable already exists */
return 0;
@@ -1911,15 +2026,16 @@ static ph7_value *VmCreateMemObj(
}
}
/* Link to the top active VM frame */
rc = SyHashInsert(&pVm->pFrame->hVar, zName, pName->nByte, SX_INT_TO_PTR(nIdx));
rc = SyHashInsert(&pFrame->hVar, zName, pName->nByte, SX_INT_TO_PTR(nIdx));
if(rc != SXRET_OK) {
PH7_VmMemoryError(&(*pVm));
}
/* Register local variable */
sLocal.nIdx = nIdx;
SySetPut(&pVm->pFrame->sLocal, (const void *)&sLocal);
SySetPut(&pFrame->sLocal, (const void *)&sLocal);
/* Install in the reference table */
PH7_VmRefObjInstall(&(*pVm), nIdx, SyHashLastEntry(&pVm->pFrame->hVar), 0, 0);
PH7_VmRefObjInstall(&(*pVm), nIdx, SyHashLastEntry(&pFrame->hVar), 0, 0);
VmScopeRecord(pVm, pName, FALSE);
/* Save object index */
pObj->nIdx = nIdx;
return pObj;
@@ -2462,6 +2578,7 @@ static sxi32 VmByteCodeExec(
sxi32 pc;
sxi32 rc;
sxi32 bReturning = FALSE;
sxbool bScopeStopped = FALSE;
VmFrame *pEntryFrame = pVm->pFrame;
/* Argument container */
SySetInit(&aArg, &pVm->sAllocator, sizeof(ph7_value *));
@@ -2480,6 +2597,13 @@ Resume:
}
/* Fetch the instruction to execute */
pInstr = &aInstr[pc];
/* LF_STOP's following transfer must not recreate the released iteration
* scope. Other jumps also reconcile their source, including jump chains
* that leave and immediately reenter a block without executing its end. */
if(pInstr->iOp != PH7_OP_LF_STOP && !(bScopeStopped && pInstr->iOp == PH7_OP_JMP)) {
VmScopeSync(pVm, pInstr->pScope, &aArg);
}
bScopeStopped = FALSE;
pInstr->bExec = TRUE;
/* Record executed instruction in global container */
SySetPut(&pVm->aInstrSet, (void *)pInstr);
@@ -2518,7 +2642,8 @@ Resume:
VmLeaveFrame(&(*pVm));
}
} else if(!pInstr->p3 && (iExecFlags & VM_EXEC_INCLUDE) == 0 && (pVm->pFrame->iFlags & VM_FRAME_LOOP)) {
while(pVm->pFrame->pParent && (pVm->pFrame->iFlags & (VM_FRAME_ACTIVE | VM_FRAME_CATCH | VM_FRAME_FINALLY)) == 0) {
/* An initializer can borrow an existing iteration frame. */
while(pVm->pFrame != pEntryFrame && pVm->pFrame->pParent && (pVm->pFrame->iFlags & (VM_FRAME_ACTIVE | VM_FRAME_CATCH | VM_FRAME_FINALLY)) == 0) {
VmLeaveFrame(&(*pVm));
}
}
@@ -2607,6 +2732,7 @@ Resume:
pResult->x.iVal = pInstr->iP2;
MemObjSetType(pResult, MEMOBJ_INT);
}
VmScopeSync(pVm, 0, &aArg);
SySetRelease(&aArg);
return VM_INCLUDE_JUMP;
}
@@ -2688,6 +2814,7 @@ Resume:
/* Leave the jump loop frame */
if(pVm->pFrame->iFlags & VM_FRAME_LOOP) {
VmLeaveFrame(&(*pVm));
bScopeStopped = TRUE;
}
break;
}
@@ -2889,13 +3016,75 @@ Resume:
/*
* DECLARE: P1 P2 P3
*
* Create a constant if P1 is set, or variable otherwise. It takes the constant/variable name
* from the the P3 operand. P2 operand is used to provide a variable type.
* P1=0 declares a variable named by P3, with type P2; P1=1 declares
* a constant described by P3. P1=2 binds the static declaration P2
* in the function pointed to by P3.
*/
case PH7_OP_DECLARE: {
if(pInstr->iP1) {
if(pInstr->iP1 == 2) {
ph7_vm_func *pFunc = (ph7_vm_func *)pInstr->p3;
ph7_vm_func_static_var *pStatic = (ph7_vm_func_static_var *)SySetAt(&pFunc->aStatic, pInstr->iP2);
VmFrame *pFrame = pVm->pFrame;
while(pFrame->pParent && (pFrame->iFlags & VM_FRAME_EXCEPTION)) {
pFrame = pFrame->pParent;
}
if(SyHashGet(&pFrame->hVar, pStatic->sName.zString, pStatic->sName.nByte)) {
PH7_VmThrowError(pVm, PH7_CTX_ERR, "Redeclaration of ‘$%z’ variable", &pStatic->sName);
}
if(pStatic->nIdx == SXU32_HIGH) {
ph7_value *pObj = VmReserveMemObj(pVm, &pStatic->nIdx);
ph7_value sValue;
if(pObj == 0) {
PH7_VmMemoryError(pVm);
}
MemObjSetType(pObj, pStatic->iFlags);
if(SySetUsed(&pStatic->aByteCode) > 0) {
PH7_MemObjInit(pVm, &sValue);
rc = VmLocalExec(pVm, &pStatic->aByteCode, &sValue);
pObj = (ph7_value *)SySetAt(&pVm->aMemObj, pStatic->nIdx);
if(rc == SXRET_OK) {
rc = PH7_MemObjSafeStore(&sValue, pObj);
if(rc != SXRET_OK) {
PH7_VmThrowError(pVm, PH7_CTX_ERR, "Cannot assign a value of incompatible type to variable '$%z'", &pStatic->sName);
}
}
PH7_MemObjRelease(&sValue);
if(rc == PH7_ABORT) {
goto Abort;
} else if(rc == PH7_EXCEPTION) {
goto Exception;
}
} else if(pObj->nType & MEMOBJ_HASHMAP) {
pObj->x.pOther = PH7_NewHashmap(pVm, 0, 0);
if(pObj->x.pOther == 0) {
PH7_VmMemoryError(pVm);
}
}
pObj->nIdx = pStatic->nIdx;
}
if(SyHashInsert(&pFrame->hVar, pStatic->sName.zString, pStatic->sName.nByte,
SX_INT_TO_PTR(pStatic->nIdx)) != SXRET_OK) {
PH7_VmMemoryError(pVm);
}
VmScopeRecord(pVm, &pStatic->sName, FALSE);
} else if(pInstr->iP1) {
/* Constant declaration */
ph7_constant_info *pConstInfo = (ph7_constant_info *) pInstr->p3;
VmFrame *pOwner = pVm->pFrame;
void **apDecl;
sxu32 n;
while(pOwner->pParent && (pOwner->iFlags & VM_FRAME_ACTIVE) == 0) {
pOwner = pOwner->pParent;
}
apDecl = (void **)SySetBasePtr(&pOwner->sConstDecl);
for(n = 0; n < SySetUsed(&pOwner->sConstDecl); n++) {
if(apDecl[n] == pConstInfo) {
PH7_VmThrowError(pVm, PH7_CTX_ERR, "Redeclaration of ‘%z’ constant", &pConstInfo->pName);
}
}
if(SySetPut(&pOwner->sConstDecl, &pConstInfo) != SXRET_OK) {
PH7_VmMemoryError(pVm);
}
rc = PH7_VmRegisterConstant(&(*pVm), &pConstInfo->pName, PH7_VmExpandConstantValue, pConstInfo->pConsCode, FALSE);
if(rc == SXERR_EXISTS) {
PH7_VmThrowError(&(*pVm), PH7_CTX_ERR,
@@ -4425,6 +4614,8 @@ Resume:
ph7_exception *pException = (ph7_exception *)pInstr->p3;
VmFrame *pFrame = 0;
SySetPut(&pVm->aException, (const void *)&pException);
pException->pScope = pVm->pScope ? pVm->pScope->pInfo : 0;
pException->pScopeExec = pVm->pScope ? pVm->pScope->pExec : 0;
/* Create the exception frame */
rc = VmEnterFrame(&(*pVm), 0, 0, &pFrame);
if(rc != SXRET_OK) {
@@ -5220,9 +5411,9 @@ Resume:
ph7_value *pArg = &pTos[-pInstr->iP1];
SyHashEntry *pEntry;
SyString sName;
VmInstr *bInstr = &aInstr[pc - 1];
/* Extract function name */
if(pTos->nType & MEMOBJ_STRING && bInstr->iOp == PH7_OP_LOADV) {
/* Synthetic calls have no preceding instruction at pc == 0. */
if(pTos->nType & MEMOBJ_STRING && pc > 0 && aInstr[pc - 1].iOp == PH7_OP_LOADV) {
PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Calling a non-callable object");
} else if((pTos->nType & (MEMOBJ_CALL | MEMOBJ_STRING)) == 0) {
if(pTos->nType & MEMOBJ_HASHMAP) {
@@ -5357,43 +5548,6 @@ Resume:
MemObjSetType(pObj, MEMOBJ_OBJ);
}
}
if(SySetUsed(&pVmFunc->aStatic) > 0) {
ph7_vm_func_static_var *pStatic, *aStatic;
/* Install static variables */
aStatic = (ph7_vm_func_static_var *)SySetBasePtr(&pVmFunc->aStatic);
for(n = 0 ; n < SySetUsed(&pVmFunc->aStatic) ; ++n) {
pStatic = &aStatic[n];
if(pStatic->nIdx == SXU32_HIGH) {
ph7_value *pVal;
/* Initialize the static variables */
pObj = VmReserveMemObj(&(*pVm), &pStatic->nIdx);
pVal = PH7_ReserveMemObj(&(*pVm));
if(pObj == 0 || pVal == 0) {
PH7_VmMemoryError(&(*pVm));
}
MemObjSetType(pObj, pStatic->iFlags);
if(SySetUsed(&pStatic->aByteCode) > 0) {
/* Evaluate initialization expression (Any complex expression) */
VmLocalExec(&(*pVm), &pStatic->aByteCode, pVal);
rc = PH7_MemObjSafeStore(pVal, pObj);
if(rc != SXRET_OK) {
PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Cannot assign a value of incompatible type to variable '$%z'", &pStatic->sName);
}
} else if(pObj->nType & MEMOBJ_HASHMAP) {
ph7_hashmap *pMap;
pMap = PH7_NewHashmap(&(*pVm), 0, 0);
if(pMap == 0) {
PH7_VmMemoryError(&(*pVm));
}
pObj->x.pOther = pMap;
}
pObj->nIdx = pStatic->nIdx;
}
/* Install in the current frame */
SyHashInsert(&pFrame->hVar, SyStringData(&pStatic->sName), SyStringLength(&pStatic->sName),
SX_INT_TO_PTR(pStatic->nIdx));
}
}
/* Push arguments in the local frame */
n = 0;
while(pArg < pTos) {
@@ -5715,6 +5869,7 @@ IncludeException:
VmFrame *pFrame = pVm->pFrame;
while(pFrame->pParent) {
if((iExecFlags & VM_EXEC_INCLUDE) && pFrame == pEntryFrame) {
VmScopeSync(pVm, 0, &aArg);
SySetRelease(&aArg);
while(pTos >= pStack) {
PH7_MemObjRelease(pTos);
@@ -5750,9 +5905,11 @@ IncludeReturn:
}
}
Done:
VmScopeSync(pVm, 0, &aArg);
SySetRelease(&aArg);
return bReturning && (iExecFlags & VM_EXEC_INCLUDE) ? VM_INCLUDE_RETURN : SXRET_OK;
Abort:
VmScopeSync(pVm, 0, &aArg);
SySetRelease(&aArg);
while(pTos >= pStack) {
PH7_MemObjRelease(pTos);
@@ -5760,6 +5917,7 @@ Abort:
}
return PH7_ABORT;
Exception:
VmScopeSync(pVm, 0, &aArg);
SySetRelease(&aArg);
while(pTos >= pStack) {
PH7_MemObjRelease(pTos);
@@ -7007,6 +7165,7 @@ static sxi32 VmCallClassMethod(
static const SyString sFileName = { "[MEMORY]", sizeof("[MEMORY]") - 1};
/* Emit the CALL instruction */
aInstr[0].iOp = PH7_OP_CALL;
aInstr[0].pScope = 0;
aInstr[0].iP1 = nArg; /* Total number of given arguments */
aInstr[0].iP2 = iEntry;
aInstr[0].p3 = 0;
@@ -7015,6 +7174,7 @@ static sxi32 VmCallClassMethod(
aInstr[0].pFile = (SyString *)&sFileName;
/* Emit the DONE instruction */
aInstr[1].iOp = PH7_OP_DONE;
aInstr[1].pScope = 0;
aInstr[1].iP1 = 1; /* Extract method return value */
aInstr[1].iP2 = 1;
aInstr[1].p3 = 0;
@@ -7077,6 +7237,7 @@ PH7_PRIVATE sxi32 PH7_VmCallUserFunction(
static const SyString sFileName = { "[MEMORY]", sizeof("[MEMORY]") - 1};
/* Emit the CALL instruction */
aInstr[0].iOp = PH7_OP_CALL;
aInstr[0].pScope = 0;
aInstr[0].iP1 = nArg; /* Total number of given arguments */
aInstr[0].iP2 = 0;
aInstr[0].p3 = 0;
@@ -7085,6 +7246,7 @@ PH7_PRIVATE sxi32 PH7_VmCallUserFunction(
aInstr[0].pFile = (SyString *)&sFileName;
/* Emit the DONE instruction */
aInstr[1].iOp = PH7_OP_DONE;
aInstr[1].pScope = 0;
aInstr[1].iP1 = 1; /* Extract function return value if available */
aInstr[1].iP2 = 1;
aInstr[1].p3 = 0;
@@ -8581,6 +8743,7 @@ static sxi32 VmExecExceptionBlock(ph7_vm *pVm, ph7_exception *pException,
VmFrame *pSavedFrame = pVm->pFrame;
VmFrame *pOwner = pException->pFrame;
VmFrame *pFrame;
VmScope *pScope;
SySet sSelf, sSavedSelf;
sxu32 nSelf = SySetUsed(&pVm->aSelf), i;
sxi32 rc;
@@ -8599,6 +8762,19 @@ static sxi32 VmExecExceptionBlock(ph7_vm *pVm, ph7_exception *pException,
}
sSavedSelf = pVm->aSelf;
pVm->aSelf = sSelf;
/* Handlers run before the throwing bytecode resumes its unwind. Remove
* exited names now, without releasing owner values or enclosing scopes.
* A context already unwound by an earlier exit must not be recreated. */
for(pScope = pVm->pScope; pScope; pScope = pScope->pParent) {
if(pScope->pInfo == pException->pScope && pScope->pExec == pException->pScopeExec) {
break;
}
}
if(pScope || pException->pScope == 0) {
while(pVm->pScope != pScope) {
VmScopeLeave(pVm);
}
}
pVm->pFrame = pOwner;
rc = VmEnterFrame(pVm, 0, 0, &pFrame);
if(rc == SXRET_OK) {
+10
View File
@@ -1121,7 +1121,13 @@ struct ph7_class_instance {
* is stored in an instance of the following structure.
*/
typedef struct VmInstr VmInstr;
typedef struct VmScopeInfo VmScopeInfo;
typedef struct VmScope VmScope;
struct VmScopeInfo {
VmScopeInfo *pParent; /* Lexical parent in the same bytecode container */
};
struct VmInstr {
VmScopeInfo *pScope; /* Lexical scope at this instruction */
sxu8 iOp; /* Operation to preform */
sxi32 iP1; /* First operand */
sxu32 iP2; /* Second operand (Often the jump destination) */
@@ -1161,6 +1167,8 @@ struct ph7_exception {
*/
SySet sFinally; /* Compiled 'finally' instructions block (VmInstr) */
VmFrame *pFrame; /* Frame that trigger the exception */
VmScopeInfo *pScope; /* Enclosing lexical context at try entry */
void *pScopeExec; /* Execution owning that context */
};
/* Forward reference */
typedef struct ph7_case_expr ph7_case_expr;
@@ -1244,6 +1252,7 @@ struct ph7_vm {
SySet aSelf; /* 'self' stack used for static member access [i.e: self::MyConstant] */
sxi32 iExitStatus; /* Script exit status */
ph7_gen_state sCodeGen; /* Code generator module */
VmScope *pScope; /* Active lexical scopes (not call frames) */
ph7_vm *pNext, *pPrev; /* List of active VMs */
sxu32 nMagic; /* Sanity check against misuse */
};
@@ -1261,6 +1270,7 @@ struct VmFrame {
SyHash hVar; /* Variable hashtable for fast lookup */
SySet sArg; /* Function arguments container */
SySet sRef; /* Local reference table (VmSlot instance) */
SySet sConstDecl; /* Constants already declared during this invocation */
sxi32 iFlags; /* Frame configuration flags (See below) */
sxu32 iExceptionJump; /* Exception jump destination */
};
+4 -2
View File
@@ -18,7 +18,8 @@ class Base32 {
if(!$input) return '';
char[] $aInput = str_split($input);
string $binaryString = '';
for(int $i = 0; $i < sizeof($aInput); $i++) {
int $i;
for($i = 0; $i < sizeof($aInput); $i++) {
$binaryString += str_pad(base_convert(ord($aInput[$i]), 10, 2), 8, '0', STR_PAD_LEFT);
}
string[] $fiveBitBinaryArray = str_split($binaryString, 5);
@@ -43,7 +44,8 @@ class Base32 {
int $paddingCharCount = substr_count($input, Base32::$map[32]);
int[] $allowedValues = {6, 4, 3, 1, 0};
if(!in_array($paddingCharCount, $allowedValues)) return '';
for(int $i = 0; $i < 4; $i++) {
int $i;
for($i = 0; $i < 4; $i++) {
if($paddingCharCount == $allowedValues[$i] && substr($input, -($allowedValues[$i])) != str_repeat(Base32::$map[32], $allowedValues[$i]))
return '';
}