This commit is contained in:
+224
-48
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user