Implement explicit value and reference captures for closures
Build / AerScript (push) Successful in 40s
Build / AerScript (push) Successful in 40s
This commit is contained in:
@@ -3235,9 +3235,6 @@ static sxi32 PH7_GenStateCompileFunc(
|
||||
nLine = pGen->pIn->nLine;
|
||||
if(pGen->pIn->nType & PH7_TK_AMPER) {
|
||||
/* Pass by reference,record that */
|
||||
PH7_GenCompileError(pGen, E_WARNING, nLine,
|
||||
"Closure: Pass by reference is disabled in the current release of the PH7 engine,PH7 is switching to pass by value"
|
||||
);
|
||||
iFlags = VM_FUNC_ARG_BY_REF;
|
||||
pGen->pIn++;
|
||||
}
|
||||
|
||||
+20
-9
@@ -1108,15 +1108,31 @@ PH7_PRIVATE ph7_class_instance *PH7_CloneClassInstance(ph7_class_instance *pSrc)
|
||||
return pClone;
|
||||
}
|
||||
#define CLASS_INSTANCE_DESTROYED 0x001 /* Instance is released */
|
||||
#define CLASS_INSTANCE_FINALIZED 0x002 /* Destructor has already been invoked */
|
||||
/* Run user finalization separately from storage release so VM teardown can
|
||||
* keep every closure environment valid until destructors have finished. */
|
||||
PH7_PRIVATE sxi32 PH7_ClassInstanceFinalize(ph7_class_instance *pThis) {
|
||||
ph7_class_method *pDestr;
|
||||
if(pThis == 0 || (pThis->iFlags & CLASS_INSTANCE_FINALIZED)) {
|
||||
return 0;
|
||||
}
|
||||
pThis->iFlags |= CLASS_INSTANCE_FINALIZED;
|
||||
pDestr = PH7_ClassExtractMethod(pThis->pClass, "__destruct", sizeof("__destruct") - 1);
|
||||
if(pDestr) {
|
||||
/* A destructor may remove its own last ordinary reference. */
|
||||
pThis->iRef++;
|
||||
PH7_VmCallClassMethod(pThis->pVm, pThis, pDestr, 0, 0, 0);
|
||||
PH7_ClassInstanceUnref(pThis);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
/*
|
||||
* Release a class instance [i.e: Object in the PHP jargon] and invoke any defined destructor.
|
||||
* This routine is invoked as soon as there are no other references to a particular
|
||||
* class instance.
|
||||
*/
|
||||
static void PH7_ClassInstanceRelease(ph7_class_instance *pThis) {
|
||||
ph7_class_method *pDestr;
|
||||
SyHashEntry *pEntry;
|
||||
ph7_class *pClass;
|
||||
ph7_vm *pVm;
|
||||
if(pThis->iFlags & CLASS_INSTANCE_DESTROYED) {
|
||||
/*
|
||||
@@ -1129,13 +1145,8 @@ static void PH7_ClassInstanceRelease(ph7_class_instance *pThis) {
|
||||
pThis->iFlags |= CLASS_INSTANCE_DESTROYED;
|
||||
/* Invoke any defined destructor if available */
|
||||
pVm = pThis->pVm;
|
||||
pClass = pThis->pClass;
|
||||
pDestr = PH7_ClassExtractMethod(pClass, "__destruct", sizeof("__destruct") - 1);
|
||||
if(pDestr) {
|
||||
/* Invoke the destructor */
|
||||
pThis->iRef = 2; /* Prevent garbage collection */
|
||||
PH7_VmCallClassMethod(pVm, pThis, pDestr, 0, 0, 0);
|
||||
}
|
||||
pThis->iRef = 1; /* Finalization adds its temporary reference */
|
||||
PH7_ClassInstanceFinalize(pThis);
|
||||
/* Release non-static attributes */
|
||||
SyHashResetLoopCursor(&pThis->hAttr);
|
||||
while((pEntry = SyHashGetNextEntry(&pThis->hAttr)) != 0) {
|
||||
|
||||
+191
-15
@@ -1421,6 +1421,23 @@ PH7_PRIVATE sxi32 PH7_VmCreateClassInstanceFrame(
|
||||
/* Forward declaration */
|
||||
static VmRefObj *VmRefObjExtract(ph7_vm *pVm, sxu32 nObjIdx);
|
||||
static sxi32 VmRefObjUnlink(ph7_vm *pVm, VmRefObj *pRef);
|
||||
/* Runtime closures own snapshots or pin indexed bindings, never pointers into
|
||||
* aMemObj (which may move). Templates do not own captured storage. */
|
||||
static void VmClosureEnvRelease(ph7_vm *pVm, ph7_vm_func *pClosure) {
|
||||
ph7_vm_func_closure_env *aEnv = (ph7_vm_func_closure_env *)SySetBasePtr(&pClosure->aClosureEnv);
|
||||
sxu32 n;
|
||||
for(n = 0; n < SySetUsed(&pClosure->aClosureEnv); n++) {
|
||||
if(aEnv[n].nIdx != SXU32_HIGH) {
|
||||
VmRefObj *pRef = VmRefObjExtract(pVm, aEnv[n].nIdx);
|
||||
if(pRef && --pRef->nCapture == 0 && (pRef->iFlags & VM_REF_CAPTURE_RETIRED)) {
|
||||
PH7_VmUnsetMemObj(pVm, aEnv[n].nIdx, FALSE);
|
||||
}
|
||||
} else {
|
||||
PH7_MemObjRelease(&aEnv[n].sValue);
|
||||
}
|
||||
}
|
||||
SySetRelease(&pClosure->aClosureEnv);
|
||||
}
|
||||
/*
|
||||
* Dummy read-only buffer used for slot reservation.
|
||||
*/
|
||||
@@ -1768,7 +1785,7 @@ static ph7_class *VmMethodClass(ph7_vm *pVm) {
|
||||
pFrame = pFrame->pParent;
|
||||
}
|
||||
pVmFunc = (ph7_vm_func *)pFrame->pUserData;
|
||||
if(pVmFunc == 0 || (pVmFunc->iFlags & VM_FUNC_CLASS_METHOD) == 0) {
|
||||
if(pVmFunc == 0 || (pVmFunc->iFlags & (VM_FUNC_CLASS_METHOD | VM_FUNC_CLOSURE)) == 0) {
|
||||
return 0;
|
||||
}
|
||||
return (ph7_class *)pVmFunc->pUserData;
|
||||
@@ -1850,12 +1867,77 @@ PH7_PRIVATE sxi32 PH7_VmReset(ph7_vm *pVm) {
|
||||
pVm->nMagic = PH7_VM_RUN;
|
||||
return SXRET_OK;
|
||||
}
|
||||
/* Finalize without invalidating storage: destructors and shutdown callbacks
|
||||
* can still invoke closures and read their captured objects/arrays. */
|
||||
static void VmFinalizeObjects(ph7_vm *pVm) {
|
||||
SyHashEntry *pFuncEntry;
|
||||
ph7_value *pObj;
|
||||
sxi32 nFinalized;
|
||||
/* Destructors may call any still-reachable closure. Drain user finalizers
|
||||
* before invalidating any environments, including objects held only by a
|
||||
* snapshot. Repeat for objects/closures created by a destructor. */
|
||||
do {
|
||||
sxu32 n;
|
||||
nFinalized = 0;
|
||||
SyHashResetLoopCursor(&pVm->hFunction);
|
||||
while((pFuncEntry = SyHashGetNextEntry(&pVm->hFunction)) != 0) {
|
||||
ph7_vm_func *pFunc;
|
||||
SyHashEntry_Pr *pNext = pVm->hFunction.pCurrent;
|
||||
for(pFunc = (ph7_vm_func *)pFuncEntry->pUserData; pFunc; pFunc = pFunc->pNextName) {
|
||||
if(pFunc->iFlags & VM_FUNC_CLOSURE) {
|
||||
ph7_vm_func_closure_env *aEnv = (ph7_vm_func_closure_env *)SySetBasePtr(&pFunc->aClosureEnv);
|
||||
for(n = 0; n < SySetUsed(&pFunc->aClosureEnv); n++) {
|
||||
if((aEnv[n].sValue.nType & (MEMOBJ_OBJ | MEMOBJ_HASHMAP)) == MEMOBJ_OBJ) {
|
||||
nFinalized |= PH7_ClassInstanceFinalize((ph7_class_instance *)aEnv[n].sValue.x.pOther);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* User code can traverse the function hash too. Entries/environments
|
||||
* stay installed; newly inserted closures are visited on the next pass. */
|
||||
pVm->hFunction.pCurrent = pNext;
|
||||
}
|
||||
/* Reacquire indexed values: a destructor may grow aMemObj. Arrays and
|
||||
* object attributes already store their contained values in this set.
|
||||
* Object-typed arrays carry MEMOBJ_OBJ too, but are not instances. */
|
||||
for(n = 0; n < SySetUsed(&pVm->aMemObj); n++) {
|
||||
pObj = (ph7_value *)SySetAt(&pVm->aMemObj, n);
|
||||
if((pObj->nType & (MEMOBJ_OBJ | MEMOBJ_HASHMAP)) == MEMOBJ_OBJ) {
|
||||
nFinalized |= PH7_ClassInstanceFinalize((ph7_class_instance *)pObj->x.pOther);
|
||||
}
|
||||
}
|
||||
} while(nFinalized);
|
||||
}
|
||||
/*
|
||||
* Release a Virtual Machine.
|
||||
* Every virtual machine must be destroyed in order to avoid memory leaks.
|
||||
*/
|
||||
PH7_PRIVATE sxi32 PH7_VmRelease(ph7_vm *pVm) {
|
||||
VmModule *pEntry;
|
||||
SyHashEntry *pFuncEntry;
|
||||
ph7_value *pObj;
|
||||
/* Also drain objects created by shutdown callbacks or after execution. */
|
||||
VmFinalizeObjects(pVm);
|
||||
/* No more user code can need reusable slots. Keep recycling enabled for
|
||||
* destructors above, but do not grow the free list during final reclaim. */
|
||||
pVm->nMagic = PH7_VM_STALE;
|
||||
/* Captures have the same lifetime as installed runtime closures. Release
|
||||
* them while indexed storage and reference bookkeeping are still valid. */
|
||||
SyHashResetLoopCursor(&pVm->hFunction);
|
||||
while((pFuncEntry = SyHashGetNextEntry(&pVm->hFunction)) != 0) {
|
||||
ph7_vm_func *pFunc;
|
||||
for(pFunc = (ph7_vm_func *)pFuncEntry->pUserData; pFunc; pFunc = pFunc->pNextName) {
|
||||
if(pFunc->iFlags & VM_FUNC_CLOSURE) {
|
||||
VmClosureEnvRelease(pVm, pFunc);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Sweep only after capture owners are released: object attributes and
|
||||
* array elements occupy separate slots and must survive with their roots. */
|
||||
SySetResetCursor(&pVm->aMemObj);
|
||||
while(SySetGetNextEntry(&pVm->aMemObj, (void **)&pObj) == SXRET_OK) {
|
||||
PH7_MemObjRelease(pObj);
|
||||
}
|
||||
/* Iterate through modules list */
|
||||
while(SySetGetNextEntry(&pVm->aModuleHandles, (void **)&pEntry) == SXRET_OK) {
|
||||
/* Unload the module */
|
||||
@@ -1868,8 +1950,6 @@ PH7_PRIVATE sxi32 PH7_VmRelease(ph7_vm *pVm) {
|
||||
/* Free up the heap */
|
||||
SySetRelease(&pVm->aModules);
|
||||
SySetRelease(&pVm->aModuleHandles);
|
||||
/* Set the stale magic number */
|
||||
pVm->nMagic = PH7_VM_STALE;
|
||||
/* Release the private memory subsystem */
|
||||
SyMemBackendRelease(&pVm->sAllocator);
|
||||
return SXRET_OK;
|
||||
@@ -3399,6 +3479,12 @@ Resume:
|
||||
/* Generate an unique closure name */
|
||||
zName = (char *)SyMemBackendAlloc(&pVm->sAllocator, sizeof("[closure_]") + 64);
|
||||
if(pClosure == 0 || zName == 0) {
|
||||
if(pClosure) {
|
||||
SyMemBackendPoolFree(&pVm->sAllocator, pClosure);
|
||||
}
|
||||
if(zName) {
|
||||
SyMemBackendFree(&pVm->sAllocator, zName);
|
||||
}
|
||||
PH7_VmMemoryError(pVm);
|
||||
}
|
||||
mLen = SyBufferFormat(zName, sizeof("[closure_]") + 64, "[closure_%d]", pVm->closure_cnt++);
|
||||
@@ -3412,12 +3498,10 @@ Resume:
|
||||
pClosure->aByteCode = pFunc->aByteCode;
|
||||
pClosure->aStatic = pFunc->aStatic;
|
||||
pClosure->iFlags = pFunc->iFlags;
|
||||
pClosure->pUserData = pFunc->pUserData;
|
||||
pClosure->pUserData = VmMethodClass(pVm);
|
||||
pClosure->sSignature = pFunc->sSignature;
|
||||
pClosure->nType = pFunc->nType;
|
||||
SyStringInitFromBuf(&pClosure->sName, zName, mLen);
|
||||
/* Register the closure */
|
||||
PH7_VmInstallUserFunction(pVm, pClosure, 0);
|
||||
/* Set up closure environment */
|
||||
SySetInit(&pClosure->aClosureEnv, &pVm->sAllocator, sizeof(ph7_vm_func_closure_env));
|
||||
aEnv = (ph7_vm_func_closure_env *)SySetBasePtr(&pFunc->aClosureEnv);
|
||||
@@ -3429,16 +3513,49 @@ Resume:
|
||||
sEnv.nIdx = SXU32_HIGH;
|
||||
PH7_MemObjInit(pVm, &sEnv.sValue);
|
||||
pValue = VmExtractMemObj(pVm, &sEnv.sName, FALSE);
|
||||
if(pValue) {
|
||||
if(sEnv.iFlags & VM_FUNC_ARG_BY_REF) {
|
||||
VmRefObj *pRef;
|
||||
if(pValue == 0) {
|
||||
pValue = VmCreateMemObj(pVm, &sEnv.sName, FALSE);
|
||||
}
|
||||
sEnv.nIdx = pValue->nIdx;
|
||||
pRef = VmRefObjExtract(pVm, sEnv.nIdx);
|
||||
if(pRef == 0) {
|
||||
rc = PH7_VmRefObjInstall(pVm, sEnv.nIdx, 0, 0, 0);
|
||||
if(rc != SXRET_OK) {
|
||||
goto ClosureError;
|
||||
}
|
||||
pRef = VmRefObjExtract(pVm, sEnv.nIdx);
|
||||
}
|
||||
pRef->nCapture++;
|
||||
} else if(pValue) {
|
||||
/* Copy imported value */
|
||||
PH7_MemObjStore(pValue, &sEnv.sValue);
|
||||
if(PH7_MemObjStore(pValue, &sEnv.sValue) != SXRET_OK) {
|
||||
PH7_MemObjRelease(&sEnv.sValue);
|
||||
goto ClosureError;
|
||||
}
|
||||
}
|
||||
/* Insert the imported variable */
|
||||
SySetPut(&pClosure->aClosureEnv, (const void *)&sEnv);
|
||||
if(SySetPut(&pClosure->aClosureEnv, (const void *)&sEnv) != SXRET_OK) {
|
||||
if(sEnv.nIdx != SXU32_HIGH) {
|
||||
VmRefObjExtract(pVm, sEnv.nIdx)->nCapture--;
|
||||
}
|
||||
PH7_MemObjRelease(&sEnv.sValue);
|
||||
goto ClosureError;
|
||||
}
|
||||
}
|
||||
if(PH7_VmInstallUserFunction(pVm, pClosure, 0) != SXRET_OK) {
|
||||
goto ClosureError;
|
||||
}
|
||||
/* Finally,load the closure name on the stack */
|
||||
pTos++;
|
||||
PH7_MemObjStringAppend(pTos, zName, mLen);
|
||||
break;
|
||||
ClosureError:
|
||||
VmClosureEnvRelease(pVm, pClosure);
|
||||
SyMemBackendPoolFree(&pVm->sAllocator, pClosure);
|
||||
SyMemBackendFree(&pVm->sAllocator, zName);
|
||||
PH7_VmMemoryError(pVm);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -5553,6 +5670,9 @@ Resume:
|
||||
if(pThis && (pVmFunc->iFlags & VM_FUNC_CLASS_METHOD)) {
|
||||
pSelf = pVmFunc->pClass;
|
||||
}
|
||||
if(pVmFunc->iFlags & VM_FUNC_CLOSURE) {
|
||||
pSelf = (ph7_class *)pVmFunc->pUserData;
|
||||
}
|
||||
/* Extract the formal argument set */
|
||||
aFormalArg = (ph7_vm_func_arg *)SySetBasePtr(&pVmFunc->aArgs);
|
||||
/* Create a new VM frame */
|
||||
@@ -5685,6 +5805,43 @@ Resume:
|
||||
aEnv = (ph7_vm_func_closure_env *)SySetBasePtr(&pVmFunc->aClosureEnv);
|
||||
for(n = 0 ; n < SySetUsed(&pVmFunc->aClosureEnv) ; ++n) {
|
||||
pEnv = &aEnv[n];
|
||||
if(pEnv->iFlags & VM_FUNC_ARG_BY_REF) {
|
||||
SyHashEntry *pBinding;
|
||||
VmRefObj *pRef = VmRefObjExtract(pVm, pEnv->nIdx);
|
||||
SyHashEntry **apBinding;
|
||||
sxu32 i;
|
||||
VmSlot sRef;
|
||||
if(SyHashGet(&pFrame->hVar, pEnv->sName.zString, pEnv->sName.nByte)) {
|
||||
continue;
|
||||
}
|
||||
if(SyHashInsert(&pFrame->hVar, pEnv->sName.zString, pEnv->sName.nByte,
|
||||
SX_INT_TO_PTR(pEnv->nIdx)) != SXRET_OK) {
|
||||
PH7_VmMemoryError(pVm);
|
||||
}
|
||||
pBinding = SyHashLastEntry(&pFrame->hVar);
|
||||
sRef.nIdx = pEnv->nIdx;
|
||||
sRef.pUserData = pBinding;
|
||||
/* Borrow the binding, not storage ownership in sLocal. */
|
||||
if(SySetPut(&pFrame->sRef, &sRef) != SXRET_OK) {
|
||||
SyHashDeleteEntry2(pBinding);
|
||||
PH7_VmMemoryError(pVm);
|
||||
}
|
||||
/* Reuse inactive aliases; recursive calls still need
|
||||
* distinct entries until their frames leave. */
|
||||
apBinding = (SyHashEntry **)SySetBasePtr(&pRef->aReference);
|
||||
for(i = 0; i < SySetUsed(&pRef->aReference); i++) {
|
||||
if(apBinding[i] == 0) {
|
||||
apBinding[i] = pBinding;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(i == SySetUsed(&pRef->aReference) && SySetPut(&pRef->aReference, &pBinding) != SXRET_OK) {
|
||||
SySetPop(&pFrame->sRef);
|
||||
SyHashDeleteEntry2(pBinding);
|
||||
PH7_VmMemoryError(pVm);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if((pEnv->iFlags & VM_FUNC_ARG_IGNORE) && (pEnv->sValue.nType & MEMOBJ_NULL)) {
|
||||
/* Do not install null value */
|
||||
continue;
|
||||
@@ -6033,7 +6190,7 @@ PH7_PRIVATE sxi32 PH7_VmByteCodeExec(ph7_vm *pVm) {
|
||||
ph7_class *pClass;
|
||||
ph7_class_instance *pInstance;
|
||||
ph7_class_method *pMethod;
|
||||
ph7_value *pArgs, *sArgv, *pObj;
|
||||
ph7_value *pArgs, *sArgv;
|
||||
ph7_value pResult;
|
||||
char *zDup, *zParam;
|
||||
sxu32 nByte;
|
||||
@@ -6099,10 +6256,9 @@ PH7_PRIVATE sxi32 PH7_VmByteCodeExec(ph7_vm *pVm) {
|
||||
pVm->iExitStatus = 0;
|
||||
}
|
||||
}
|
||||
/* Garbage collector over all elements in object allocation table */
|
||||
while(SySetGetNextEntry(&pVm->aMemObj, (void **)&pObj) == SXRET_OK) {
|
||||
PH7_MemObjRelease(pObj);
|
||||
}
|
||||
/* Preserve end-of-execution finalization before shutdown, but keep capture
|
||||
* environments and their indexed contents alive until VM release. */
|
||||
VmFinalizeObjects(pVm);
|
||||
/* Invoke any shutdown callbacks */
|
||||
VmInvokeShutdownCallbacks(&(*pVm));
|
||||
/*
|
||||
@@ -8139,6 +8295,11 @@ static int vm_builtin_exit(ph7_context *pCtx, int nArg, ph7_value **apArg) {
|
||||
PH7_PRIVATE sxi32 PH7_VmUnsetMemObj(ph7_vm *pVm, sxu32 nObjIdx, int bForce) {
|
||||
ph7_value *pObj;
|
||||
VmRefObj *pRef;
|
||||
pRef = VmRefObjExtract(pVm, nObjIdx);
|
||||
if(pRef && pRef->nCapture) {
|
||||
VmRefObjUnlink(pVm, pRef);
|
||||
return SXRET_OK;
|
||||
}
|
||||
pObj = (ph7_value *)SySetAt(&pVm->aMemObj, nObjIdx);
|
||||
if(pObj) {
|
||||
/* Release the object */
|
||||
@@ -8150,7 +8311,7 @@ PH7_PRIVATE sxi32 PH7_VmUnsetMemObj(ph7_vm *pVm, sxu32 nObjIdx, int bForce) {
|
||||
sxi32 iFlags = pRef->iFlags;
|
||||
/* Unlink from the reference table */
|
||||
VmRefObjUnlink(&(*pVm), pRef);
|
||||
if((bForce == TRUE) || (iFlags & VM_REF_IDX_KEEP) == 0) {
|
||||
if(pVm->nMagic != PH7_VM_STALE && ((bForce == TRUE) || (iFlags & VM_REF_IDX_KEEP) == 0)) {
|
||||
VmSlot sFree;
|
||||
/* Restore to the free list */
|
||||
sFree.nIdx = nObjIdx;
|
||||
@@ -8168,6 +8329,11 @@ PH7_PRIVATE sxi32 PH7_VmUnsetMemObj(ph7_vm *pVm, sxu32 nObjIdx, int bForce) {
|
||||
PH7_PRIVATE sxi32 PH7_VmDestroyMemObj(ph7_vm *pVm, ph7_value *pObj) {
|
||||
VmRefObj *pRef;
|
||||
if(pObj) {
|
||||
pRef = VmRefObjExtract(pVm, pObj->nIdx);
|
||||
if(pRef && pRef->nCapture) {
|
||||
VmRefObjUnlink(pVm, pRef);
|
||||
return SXRET_OK;
|
||||
}
|
||||
/* Release the object */
|
||||
PH7_MemObjRelease(pObj);
|
||||
/* Remove old reference links if available */
|
||||
@@ -8176,12 +8342,14 @@ PH7_PRIVATE sxi32 PH7_VmDestroyMemObj(ph7_vm *pVm, ph7_value *pObj) {
|
||||
/* Unlink from the reference table */
|
||||
VmRefObjUnlink(&(*pVm), pRef);
|
||||
}
|
||||
if(pVm->nMagic != PH7_VM_STALE) {
|
||||
VmSlot sFree;
|
||||
/* Restore to the free list */
|
||||
sFree.nIdx = pObj->nIdx;
|
||||
sFree.pUserData = 0;
|
||||
SySetPut(&pVm->aFreeObj, (const void *)&sFree);
|
||||
}
|
||||
}
|
||||
return SXRET_OK;
|
||||
}
|
||||
/*
|
||||
@@ -10831,6 +10999,14 @@ static sxi32 VmRefObjUnlink(ph7_vm *pVm, VmRefObj *pRef) {
|
||||
PH7_HashmapUnlinkNode(apNode[n], FALSE);
|
||||
}
|
||||
}
|
||||
if(pRef->nCapture) {
|
||||
/* Names can disappear (including explicit unset), but captures still
|
||||
* own the binding's contents and prevent reuse of its index. */
|
||||
SySetReset(&pRef->aReference);
|
||||
SySetReset(&pRef->aArrEntries);
|
||||
pRef->iFlags |= VM_REF_CAPTURE_RETIRED;
|
||||
return SXRET_OK;
|
||||
}
|
||||
if(pRef->pPrevCollide) {
|
||||
pRef->pPrevCollide->pNextCollide = pRef->pNextCollide;
|
||||
} else {
|
||||
|
||||
@@ -1318,11 +1318,13 @@ struct VmRefObj {
|
||||
SySet aReference; /* Table of references to this memory object */
|
||||
SySet aArrEntries; /* Foreign hashmap entries [i.e: array(&$a) ] */
|
||||
sxu32 nIdx; /* Referenced object index */
|
||||
sxu32 nCapture; /* Closure owners: keep contents and index alive */
|
||||
sxi32 iFlags; /* Configuration flags */
|
||||
VmRefObj *pNextCollide, *pPrevCollide; /* Collision link */
|
||||
VmRefObj *pNext, *pPrev; /* List of all referenced objects */
|
||||
};
|
||||
#define VM_REF_IDX_KEEP 0x001 /* Do not restore the memory object to the free list */
|
||||
#define VM_REF_CAPTURE_RETIRED 0x002 /* Storage owner has left while captured */
|
||||
/*
|
||||
* Output control buffer entry.
|
||||
* Refer to the implementation of [ob_start()] for more information.
|
||||
@@ -1804,6 +1806,7 @@ PH7_PRIVATE ph7_class_instance *PH7_NewClassInstance(ph7_vm *pVm, ph7_class *pCl
|
||||
PH7_PRIVATE ph7_class_instance *PH7_CloneClassInstance(ph7_class_instance *pSrc);
|
||||
PH7_PRIVATE sxi32 PH7_ClassInstanceCmp(ph7_class_instance *pLeft, ph7_class_instance *pRight, int bStrict, int iNest);
|
||||
PH7_PRIVATE void PH7_ClassInstanceUnref(ph7_class_instance *pThis);
|
||||
PH7_PRIVATE sxi32 PH7_ClassInstanceFinalize(ph7_class_instance *pThis);
|
||||
PH7_PRIVATE sxi32 PH7_ClassInstanceDump(SyBlob *pOut, ph7_class_instance *pThis, int ShowType, int nTab, int nDepth);
|
||||
PH7_PRIVATE sxi32 PH7_ClassInstanceCallMagicMethod(ph7_vm *pVm, ph7_class *pClass, ph7_class_instance *pThis, const char *zMethod,
|
||||
sxu32 nByte, const SyString *pAttrName);
|
||||
|
||||
Reference in New Issue
Block a user