Implement __invoke dispatch and fix VM cleanup and allocator alignment

This commit is contained in:
2026-10-26 15:10:47 +01:00
parent 4fe0f4dcd9
commit 7ae2412a88
4 changed files with 75 additions and 48 deletions
+5 -12
View File
@@ -463,6 +463,9 @@ static sxi32 ProcessSourceFile(
int iFileDir, rc;
char *pFileDir, fFilePath[PATH_MAX + 1];
char pFilePath[PATH_MAX + 1];
/* Track the initialized VM before compilation can trigger library shutdown. */
MACRO_LD_PUSH(pEngine->pVms, pVm);
pEngine->iVm++;
/* Install local import path which is the current directory */
rc = ph7_vm_config(pVm, PH7_VM_CONFIG_IMPORT_PATH, "./");
if(rc != PH7_OK) {
@@ -488,26 +491,16 @@ static sxi32 ProcessSourceFile(
}
/* Compile the script */
PH7_CompileAerScript(pVm, &(*pScript), PH7_AERSCRIPT_CODE);
if(pVm == 0) {
/* Null ppVm pointer,release this VM */
SyMemBackendRelease(&pVm->sAllocator);
SyMemBackendPoolFree(&pEngine->sAllocator, pVm);
if(ppVm) {
*ppVm = 0;
}
return PH7_OK;
}
/* Prepare the virtual machine for bytecode execution */
rc = PH7_VmMakeReady(pVm);
if(rc != PH7_OK) {
goto Release;
}
/* Script successfully compiled,link to the list of active virtual machines */
MACRO_LD_PUSH(pEngine->pVms, pVm);
pEngine->iVm++;
/* Ready to execute PH7 bytecode */
return PH7_OK;
Release:
MACRO_LD_REMOVE(pEngine->pVms, pVm);
pEngine->iVm--;
SyMemBackendRelease(&pVm->sAllocator);
SyMemBackendPoolFree(&pEngine->sAllocator, pVm);
*ppVm = 0;
+49 -26
View File
@@ -14,6 +14,13 @@
#include "ph7int.h"
/* Reserve a scalar-sized prefix for OS sizes and pool metadata. The engine's
* heap scalars require at most this alignment on supported ABIs. Round the
* tracking prefix too: SyMemBlock is only 12 bytes on AAPCS32.
*/
#define SXMEM_PREFIX_SIZE sizeof(sxu64)
#define SXMEM_BLOCK_SIZE ((sizeof(SyMemBlock) + SXMEM_PREFIX_SIZE - 1) / SXMEM_PREFIX_SIZE * SXMEM_PREFIX_SIZE)
static void *SyOSHeapAlloc(sxu32 nBytes) {
void *pNew;
#if defined(__WINNT__)
@@ -77,35 +84,41 @@ PH7_PRIVATE sxu32 SyMemcpy(const void *pSrc, void *pDest, sxu32 nLen) {
}
static void *MemOSAlloc(sxu32 nBytes) {
sxu32 *pChunk;
pChunk = (sxu32 *)SyOSHeapAlloc(nBytes + sizeof(sxu32));
if(nBytes > SXU32_HIGH - SXMEM_PREFIX_SIZE) {
return 0;
}
pChunk = (sxu32 *)SyOSHeapAlloc(nBytes + SXMEM_PREFIX_SIZE);
if(pChunk == 0) {
return 0;
}
pChunk[0] = nBytes;
return (void *)&pChunk[1];
return (void *)((char *)pChunk + SXMEM_PREFIX_SIZE);
}
static void *MemOSRealloc(void *pOld, sxu32 nBytes) {
sxu32 *pOldChunk;
sxu32 *pChunk;
pOldChunk = (sxu32 *)(((char *)pOld) - sizeof(sxu32));
pOldChunk = (sxu32 *)((char *)pOld - SXMEM_PREFIX_SIZE);
if(pOldChunk[0] >= nBytes) {
return pOld;
}
pChunk = (sxu32 *)SyOSHeapRealloc(pOldChunk, nBytes + sizeof(sxu32));
if(nBytes > SXU32_HIGH - SXMEM_PREFIX_SIZE) {
return 0;
}
pChunk = (sxu32 *)SyOSHeapRealloc(pOldChunk, nBytes + SXMEM_PREFIX_SIZE);
if(pChunk == 0) {
return 0;
}
pChunk[0] = nBytes;
return (void *)&pChunk[1];
return (void *)((char *)pChunk + SXMEM_PREFIX_SIZE);
}
static void MemOSFree(void *pBlock) {
void *pChunk;
pChunk = (void *)(((char *)pBlock) - sizeof(sxu32));
pChunk = (void *)((char *)pBlock - SXMEM_PREFIX_SIZE);
SyOSHeapFree(pChunk);
}
static sxu32 MemOSChunkSize(void *pBlock) {
sxu32 *pChunk;
pChunk = (sxu32 *)(((char *)pBlock) - sizeof(sxu32));
pChunk = (sxu32 *)((char *)pBlock - SXMEM_PREFIX_SIZE);
return pChunk[0];
}
/* Export OS allocation methods */
@@ -137,7 +150,10 @@ static void *MemBackendAlloc(SyMemBackend *pBackend, sxu32 nBytes) {
/* Append an extra block so we can tracks allocated chunks and avoid memory
* leaks.
*/
nBytes += sizeof(SyMemBlock);
if(nBytes > SXU32_HIGH - SXMEM_BLOCK_SIZE) {
return 0;
}
nBytes += SXMEM_BLOCK_SIZE;
/* Calculate memory usage */
if(MemBackendCalculate(pBackend, nBytes) != SXRET_OK) {
return 0;
@@ -158,7 +174,7 @@ static void *MemBackendAlloc(SyMemBackend *pBackend, sxu32 nBytes) {
MACRO_LD_PUSH(pBackend->pBlocks, pBlock);
pBlock->nGuard = SXMEM_BACKEND_MAGIC;
pBackend->nBlock++;
return (void *)&pBlock[1];
return (void *)((char *)pBlock + SXMEM_BLOCK_SIZE);
}
PH7_PRIVATE void *SyMemBackendAlloc(SyMemBackend *pBackend, sxu32 nBytes) {
void *pChunk;
@@ -181,11 +197,14 @@ static void *MemBackendRealloc(SyMemBackend *pBackend, void *pOld, sxu32 nBytes)
if(pOld == 0) {
return MemBackendAlloc(&(*pBackend), nBytes);
}
pBlock = (SyMemBlock *)(((char *)pOld) - sizeof(SyMemBlock));
pBlock = (SyMemBlock *)(((char *)pOld) - SXMEM_BLOCK_SIZE);
if(pBlock->nGuard != SXMEM_BACKEND_MAGIC) {
return 0;
}
nBytes += sizeof(SyMemBlock);
if(nBytes > SXU32_HIGH - SXMEM_BLOCK_SIZE) {
return 0;
}
nBytes += SXMEM_BLOCK_SIZE;
pPrev = pBlock->pPrev;
pNext = pBlock->pNext;
nChunkSize = MemOSChunkSize(pBlock);
@@ -219,7 +238,7 @@ static void *MemBackendRealloc(SyMemBackend *pBackend, void *pOld, sxu32 nBytes)
} else {
pNew = pBlock;
}
return (void *)&pNew[1];
return (void *)((char *)pNew + SXMEM_BLOCK_SIZE);
}
PH7_PRIVATE void *SyMemBackendRealloc(SyMemBackend *pBackend, void *pOld, sxu32 nBytes) {
void *pChunk;
@@ -237,8 +256,7 @@ PH7_PRIVATE void *SyMemBackendRealloc(SyMemBackend *pBackend, void *pOld, sxu32
}
static sxi32 MemBackendFree(SyMemBackend *pBackend, void *pChunk) {
SyMemBlock *pBlock;
sxu32 *pChunkSize;
pBlock = (SyMemBlock *)(((char *)pChunk) - sizeof(SyMemBlock));
pBlock = (SyMemBlock *)(((char *)pChunk) - SXMEM_BLOCK_SIZE);
if(pBlock->nGuard != SXMEM_BACKEND_MAGIC) {
return SXERR_CORRUPT;
}
@@ -250,8 +268,7 @@ static sxi32 MemBackendFree(SyMemBackend *pBackend, void *pChunk) {
MACRO_LD_REMOVE(pBackend->pBlocks, pBlock);
pBackend->nBlock--;
/* Release the heap */
pChunkSize = (sxu32 *)(((char *)pBlock) - sizeof(sxu32));
pBackend->pHeap->nSize -= pChunkSize[0];
pBackend->pHeap->nSize -= MemOSChunkSize(pBlock);
pBackend->pMethods->xFree(pBlock);
}
return SXRET_OK;
@@ -308,20 +325,23 @@ static void *MemBackendPoolAlloc(SyMemBackend *pBackend, sxu32 nBytes) {
SyMemHeader *pBucket, *pNext;
sxu32 nBucketSize;
sxu32 nBucket;
if(nBytes + sizeof(SyMemHeader) >= SXMEM_POOL_MAXALLOC) {
if(nBytes > SXU32_HIGH - SXMEM_PREFIX_SIZE) {
return 0;
}
if(nBytes + SXMEM_PREFIX_SIZE >= SXMEM_POOL_MAXALLOC) {
/* Allocate a big chunk directly */
pBucket = (SyMemHeader *)MemBackendAlloc(&(*pBackend), nBytes + sizeof(SyMemHeader));
pBucket = (SyMemHeader *)MemBackendAlloc(&(*pBackend), nBytes + SXMEM_PREFIX_SIZE);
if(pBucket == 0) {
return 0;
}
/* Record as big block */
pBucket->nBucket = (sxu32)(SXMEM_POOL_MAGIC << 16) | SXU16_HIGH;
return (void *)(pBucket + 1);
pBucket->nBucket = ((sxu32)SXMEM_POOL_MAGIC << 16) | SXU16_HIGH;
return (void *)((char *)pBucket + SXMEM_PREFIX_SIZE);
}
/* Locate the appropriate bucket */
nBucket = 0;
nBucketSize = SXMEM_POOL_MINALLOC;
while(nBytes + sizeof(SyMemHeader) > nBucketSize) {
while(nBytes + SXMEM_PREFIX_SIZE > nBucketSize) {
nBucketSize <<= 1;
nBucket++;
}
@@ -338,8 +358,8 @@ static void *MemBackendPoolAlloc(SyMemBackend *pBackend, sxu32 nBytes) {
pNext = pBucket->pNext;
pBackend->apPool[nBucket] = pNext;
/* Record bucket&magic number */
pBucket->nBucket = (SXMEM_POOL_MAGIC << 16) | nBucket;
return (void *)&pBucket[1];
pBucket->nBucket = ((sxu32)SXMEM_POOL_MAGIC << 16) | nBucket;
return (void *)((char *)pBucket + SXMEM_PREFIX_SIZE);
}
PH7_PRIVATE void *SyMemBackendPoolAlloc(SyMemBackend *pBackend, sxu32 nBytes) {
void *pChunk;
@@ -359,7 +379,7 @@ static sxi32 MemBackendPoolFree(SyMemBackend *pBackend, void *pChunk) {
SyMemHeader *pHeader;
sxu32 nBucket;
/* Get the corresponding bucket */
pHeader = (SyMemHeader *)(((char *)pChunk) - sizeof(SyMemHeader));
pHeader = (SyMemHeader *)(((char *)pChunk) - SXMEM_PREFIX_SIZE);
/* Sanity check to avoid misuse */
if((pHeader->nBucket >> 16) != SXMEM_POOL_MAGIC) {
return SXERR_CORRUPT;
@@ -399,7 +419,7 @@ static void *MemBackendPoolRealloc(SyMemBackend *pBackend, void *pOld, sxu32 nBy
return pNew;
}
/* Get the corresponding bucket */
pHeader = (SyMemHeader *)(((char *)pOld) - sizeof(SyMemHeader));
pHeader = (SyMemHeader *)(((char *)pOld) - SXMEM_PREFIX_SIZE);
/* Sanity check to avoid misuse */
if((pHeader->nBucket >> 16) != SXMEM_POOL_MAGIC) {
return 0;
@@ -410,7 +430,10 @@ static void *MemBackendPoolRealloc(SyMemBackend *pBackend, void *pOld, sxu32 nBy
return MemBackendRealloc(&(*pBackend), pHeader, nByte);
}
nBucketSize = 1 << (nBucket + SXMEM_POOL_INCR);
if(nBucketSize >= nByte + sizeof(SyMemHeader)) {
if(nByte > SXU32_HIGH - SXMEM_PREFIX_SIZE) {
return 0;
}
if(nBucketSize >= nByte + SXMEM_PREFIX_SIZE) {
/* The old bucket can honor the requested size */
return pOld;
}
+1 -1
View File
@@ -942,7 +942,7 @@ PH7_PRIVATE sxi32 PH7_MemObjStore(ph7_value *pSrc, ph7_value *pDest) {
((ph7_class_instance *)pSrc->x.pOther)->iRef++;
}
}
if(pDest->nType & MEMOBJ_OBJ) {
if((pDest->nType & (MEMOBJ_OBJ | MEMOBJ_HASHMAP)) == MEMOBJ_OBJ) {
pObj = (ph7_class_instance *)pDest->x.pOther;
}
SyMemcpy((const void *) & (*pSrc), &(*pDest), sizeof(ph7_value) - (sizeof(ph7_vm *) + sizeof(SyBlob) + sizeof(sxu32)));
+20 -9
View File
@@ -5563,7 +5563,24 @@ Resume:
SyString sName;
/* Extract function name */
/* Synthetic calls have no preceding instruction at pc == 0. */
if(pTos->nType & MEMOBJ_STRING && pc > 0 && aInstr[pc - 1].iOp == PH7_OP_LOADV) {
if((pTos->nType & (MEMOBJ_OBJ | MEMOBJ_HASHMAP)) == MEMOBJ_OBJ) {
ph7_class_instance *pThis = (ph7_class_instance *)pTos->x.pOther;
ph7_class_method *pMeth;
if(pThis == 0) {
PH7_VmThrowError(pVm, PH7_CTX_ERR, "Call to non-instantiated object");
}
SyStringInitFromBuf(&sName, "__invoke", sizeof("__invoke") - 1);
pMeth = VmMethodSeed(pVm, pThis->pClass, &sName, 0, FALSE);
if(pMeth == 0) {
PH7_VmThrowError(pVm, PH7_CTX_ERR, "Call to undefined method '%z->%z()'",
&pThis->pClass->sName, &sName);
}
/* Keep arguments and receiver intact for ordinary method dispatch. */
pTos++;
SyBlobAppend(&pTos->sBlob, SyStringData(&pMeth->sVmName), SyStringLength(&pMeth->sVmName));
MemObjSetType(pTos, MEMOBJ_STRING);
pTos->nIdx = SXU32_HIGH;
} else 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) {
@@ -5585,14 +5602,8 @@ Resume:
PH7_MemObjStore(&sResult, pTos);
PH7_MemObjRelease(&sResult);
} else {
if(pTos->nType & MEMOBJ_OBJ) {
ph7_class_instance *pThis = (ph7_class_instance *)pTos->x.pOther;
/* Call the magic method '__invoke' if available */
PH7_ClassInstanceCallMagicMethod(&(*pVm), pThis->pClass, pThis, "__invoke", sizeof("__invoke") - 1, 0);
} else {
/* Raise exception: Invalid function name */
PH7_VmThrowError(&(*pVm), PH7_CTX_WARNING, "Invalid function name");
}
/* Raise exception: Invalid function name */
PH7_VmThrowError(&(*pVm), PH7_CTX_WARNING, "Invalid function name");
/* Pop given arguments */
if(pInstr->iP1 > 0) {
VmPopOperand(&pTos, pInstr->iP1);