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; int iFileDir, rc;
char *pFileDir, fFilePath[PATH_MAX + 1]; char *pFileDir, fFilePath[PATH_MAX + 1];
char pFilePath[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 */ /* Install local import path which is the current directory */
rc = ph7_vm_config(pVm, PH7_VM_CONFIG_IMPORT_PATH, "./"); rc = ph7_vm_config(pVm, PH7_VM_CONFIG_IMPORT_PATH, "./");
if(rc != PH7_OK) { if(rc != PH7_OK) {
@@ -488,26 +491,16 @@ static sxi32 ProcessSourceFile(
} }
/* Compile the script */ /* Compile the script */
PH7_CompileAerScript(pVm, &(*pScript), PH7_AERSCRIPT_CODE); 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 */ /* Prepare the virtual machine for bytecode execution */
rc = PH7_VmMakeReady(pVm); rc = PH7_VmMakeReady(pVm);
if(rc != PH7_OK) { if(rc != PH7_OK) {
goto Release; 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 */ /* Ready to execute PH7 bytecode */
return PH7_OK; return PH7_OK;
Release: Release:
MACRO_LD_REMOVE(pEngine->pVms, pVm);
pEngine->iVm--;
SyMemBackendRelease(&pVm->sAllocator); SyMemBackendRelease(&pVm->sAllocator);
SyMemBackendPoolFree(&pEngine->sAllocator, pVm); SyMemBackendPoolFree(&pEngine->sAllocator, pVm);
*ppVm = 0; *ppVm = 0;
+49 -26
View File
@@ -14,6 +14,13 @@
#include "ph7int.h" #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) { static void *SyOSHeapAlloc(sxu32 nBytes) {
void *pNew; void *pNew;
#if defined(__WINNT__) #if defined(__WINNT__)
@@ -77,35 +84,41 @@ PH7_PRIVATE sxu32 SyMemcpy(const void *pSrc, void *pDest, sxu32 nLen) {
} }
static void *MemOSAlloc(sxu32 nBytes) { static void *MemOSAlloc(sxu32 nBytes) {
sxu32 *pChunk; 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) { if(pChunk == 0) {
return 0; return 0;
} }
pChunk[0] = nBytes; pChunk[0] = nBytes;
return (void *)&pChunk[1]; return (void *)((char *)pChunk + SXMEM_PREFIX_SIZE);
} }
static void *MemOSRealloc(void *pOld, sxu32 nBytes) { static void *MemOSRealloc(void *pOld, sxu32 nBytes) {
sxu32 *pOldChunk; sxu32 *pOldChunk;
sxu32 *pChunk; sxu32 *pChunk;
pOldChunk = (sxu32 *)(((char *)pOld) - sizeof(sxu32)); pOldChunk = (sxu32 *)((char *)pOld - SXMEM_PREFIX_SIZE);
if(pOldChunk[0] >= nBytes) { if(pOldChunk[0] >= nBytes) {
return pOld; 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) { if(pChunk == 0) {
return 0; return 0;
} }
pChunk[0] = nBytes; pChunk[0] = nBytes;
return (void *)&pChunk[1]; return (void *)((char *)pChunk + SXMEM_PREFIX_SIZE);
} }
static void MemOSFree(void *pBlock) { static void MemOSFree(void *pBlock) {
void *pChunk; void *pChunk;
pChunk = (void *)(((char *)pBlock) - sizeof(sxu32)); pChunk = (void *)((char *)pBlock - SXMEM_PREFIX_SIZE);
SyOSHeapFree(pChunk); SyOSHeapFree(pChunk);
} }
static sxu32 MemOSChunkSize(void *pBlock) { static sxu32 MemOSChunkSize(void *pBlock) {
sxu32 *pChunk; sxu32 *pChunk;
pChunk = (sxu32 *)(((char *)pBlock) - sizeof(sxu32)); pChunk = (sxu32 *)((char *)pBlock - SXMEM_PREFIX_SIZE);
return pChunk[0]; return pChunk[0];
} }
/* Export OS allocation methods */ /* 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 /* Append an extra block so we can tracks allocated chunks and avoid memory
* leaks. * leaks.
*/ */
nBytes += sizeof(SyMemBlock); if(nBytes > SXU32_HIGH - SXMEM_BLOCK_SIZE) {
return 0;
}
nBytes += SXMEM_BLOCK_SIZE;
/* Calculate memory usage */ /* Calculate memory usage */
if(MemBackendCalculate(pBackend, nBytes) != SXRET_OK) { if(MemBackendCalculate(pBackend, nBytes) != SXRET_OK) {
return 0; return 0;
@@ -158,7 +174,7 @@ static void *MemBackendAlloc(SyMemBackend *pBackend, sxu32 nBytes) {
MACRO_LD_PUSH(pBackend->pBlocks, pBlock); MACRO_LD_PUSH(pBackend->pBlocks, pBlock);
pBlock->nGuard = SXMEM_BACKEND_MAGIC; pBlock->nGuard = SXMEM_BACKEND_MAGIC;
pBackend->nBlock++; pBackend->nBlock++;
return (void *)&pBlock[1]; return (void *)((char *)pBlock + SXMEM_BLOCK_SIZE);
} }
PH7_PRIVATE void *SyMemBackendAlloc(SyMemBackend *pBackend, sxu32 nBytes) { PH7_PRIVATE void *SyMemBackendAlloc(SyMemBackend *pBackend, sxu32 nBytes) {
void *pChunk; void *pChunk;
@@ -181,11 +197,14 @@ static void *MemBackendRealloc(SyMemBackend *pBackend, void *pOld, sxu32 nBytes)
if(pOld == 0) { if(pOld == 0) {
return MemBackendAlloc(&(*pBackend), nBytes); return MemBackendAlloc(&(*pBackend), nBytes);
} }
pBlock = (SyMemBlock *)(((char *)pOld) - sizeof(SyMemBlock)); pBlock = (SyMemBlock *)(((char *)pOld) - SXMEM_BLOCK_SIZE);
if(pBlock->nGuard != SXMEM_BACKEND_MAGIC) { if(pBlock->nGuard != SXMEM_BACKEND_MAGIC) {
return 0; return 0;
} }
nBytes += sizeof(SyMemBlock); if(nBytes > SXU32_HIGH - SXMEM_BLOCK_SIZE) {
return 0;
}
nBytes += SXMEM_BLOCK_SIZE;
pPrev = pBlock->pPrev; pPrev = pBlock->pPrev;
pNext = pBlock->pNext; pNext = pBlock->pNext;
nChunkSize = MemOSChunkSize(pBlock); nChunkSize = MemOSChunkSize(pBlock);
@@ -219,7 +238,7 @@ static void *MemBackendRealloc(SyMemBackend *pBackend, void *pOld, sxu32 nBytes)
} else { } else {
pNew = pBlock; pNew = pBlock;
} }
return (void *)&pNew[1]; return (void *)((char *)pNew + SXMEM_BLOCK_SIZE);
} }
PH7_PRIVATE void *SyMemBackendRealloc(SyMemBackend *pBackend, void *pOld, sxu32 nBytes) { PH7_PRIVATE void *SyMemBackendRealloc(SyMemBackend *pBackend, void *pOld, sxu32 nBytes) {
void *pChunk; void *pChunk;
@@ -237,8 +256,7 @@ PH7_PRIVATE void *SyMemBackendRealloc(SyMemBackend *pBackend, void *pOld, sxu32
} }
static sxi32 MemBackendFree(SyMemBackend *pBackend, void *pChunk) { static sxi32 MemBackendFree(SyMemBackend *pBackend, void *pChunk) {
SyMemBlock *pBlock; SyMemBlock *pBlock;
sxu32 *pChunkSize; pBlock = (SyMemBlock *)(((char *)pChunk) - SXMEM_BLOCK_SIZE);
pBlock = (SyMemBlock *)(((char *)pChunk) - sizeof(SyMemBlock));
if(pBlock->nGuard != SXMEM_BACKEND_MAGIC) { if(pBlock->nGuard != SXMEM_BACKEND_MAGIC) {
return SXERR_CORRUPT; return SXERR_CORRUPT;
} }
@@ -250,8 +268,7 @@ static sxi32 MemBackendFree(SyMemBackend *pBackend, void *pChunk) {
MACRO_LD_REMOVE(pBackend->pBlocks, pBlock); MACRO_LD_REMOVE(pBackend->pBlocks, pBlock);
pBackend->nBlock--; pBackend->nBlock--;
/* Release the heap */ /* Release the heap */
pChunkSize = (sxu32 *)(((char *)pBlock) - sizeof(sxu32)); pBackend->pHeap->nSize -= MemOSChunkSize(pBlock);
pBackend->pHeap->nSize -= pChunkSize[0];
pBackend->pMethods->xFree(pBlock); pBackend->pMethods->xFree(pBlock);
} }
return SXRET_OK; return SXRET_OK;
@@ -308,20 +325,23 @@ static void *MemBackendPoolAlloc(SyMemBackend *pBackend, sxu32 nBytes) {
SyMemHeader *pBucket, *pNext; SyMemHeader *pBucket, *pNext;
sxu32 nBucketSize; sxu32 nBucketSize;
sxu32 nBucket; 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 */ /* Allocate a big chunk directly */
pBucket = (SyMemHeader *)MemBackendAlloc(&(*pBackend), nBytes + sizeof(SyMemHeader)); pBucket = (SyMemHeader *)MemBackendAlloc(&(*pBackend), nBytes + SXMEM_PREFIX_SIZE);
if(pBucket == 0) { if(pBucket == 0) {
return 0; return 0;
} }
/* Record as big block */ /* Record as big block */
pBucket->nBucket = (sxu32)(SXMEM_POOL_MAGIC << 16) | SXU16_HIGH; pBucket->nBucket = ((sxu32)SXMEM_POOL_MAGIC << 16) | SXU16_HIGH;
return (void *)(pBucket + 1); return (void *)((char *)pBucket + SXMEM_PREFIX_SIZE);
} }
/* Locate the appropriate bucket */ /* Locate the appropriate bucket */
nBucket = 0; nBucket = 0;
nBucketSize = SXMEM_POOL_MINALLOC; nBucketSize = SXMEM_POOL_MINALLOC;
while(nBytes + sizeof(SyMemHeader) > nBucketSize) { while(nBytes + SXMEM_PREFIX_SIZE > nBucketSize) {
nBucketSize <<= 1; nBucketSize <<= 1;
nBucket++; nBucket++;
} }
@@ -338,8 +358,8 @@ static void *MemBackendPoolAlloc(SyMemBackend *pBackend, sxu32 nBytes) {
pNext = pBucket->pNext; pNext = pBucket->pNext;
pBackend->apPool[nBucket] = pNext; pBackend->apPool[nBucket] = pNext;
/* Record bucket&magic number */ /* Record bucket&magic number */
pBucket->nBucket = (SXMEM_POOL_MAGIC << 16) | nBucket; pBucket->nBucket = ((sxu32)SXMEM_POOL_MAGIC << 16) | nBucket;
return (void *)&pBucket[1]; return (void *)((char *)pBucket + SXMEM_PREFIX_SIZE);
} }
PH7_PRIVATE void *SyMemBackendPoolAlloc(SyMemBackend *pBackend, sxu32 nBytes) { PH7_PRIVATE void *SyMemBackendPoolAlloc(SyMemBackend *pBackend, sxu32 nBytes) {
void *pChunk; void *pChunk;
@@ -359,7 +379,7 @@ static sxi32 MemBackendPoolFree(SyMemBackend *pBackend, void *pChunk) {
SyMemHeader *pHeader; SyMemHeader *pHeader;
sxu32 nBucket; sxu32 nBucket;
/* Get the corresponding bucket */ /* Get the corresponding bucket */
pHeader = (SyMemHeader *)(((char *)pChunk) - sizeof(SyMemHeader)); pHeader = (SyMemHeader *)(((char *)pChunk) - SXMEM_PREFIX_SIZE);
/* Sanity check to avoid misuse */ /* Sanity check to avoid misuse */
if((pHeader->nBucket >> 16) != SXMEM_POOL_MAGIC) { if((pHeader->nBucket >> 16) != SXMEM_POOL_MAGIC) {
return SXERR_CORRUPT; return SXERR_CORRUPT;
@@ -399,7 +419,7 @@ static void *MemBackendPoolRealloc(SyMemBackend *pBackend, void *pOld, sxu32 nBy
return pNew; return pNew;
} }
/* Get the corresponding bucket */ /* Get the corresponding bucket */
pHeader = (SyMemHeader *)(((char *)pOld) - sizeof(SyMemHeader)); pHeader = (SyMemHeader *)(((char *)pOld) - SXMEM_PREFIX_SIZE);
/* Sanity check to avoid misuse */ /* Sanity check to avoid misuse */
if((pHeader->nBucket >> 16) != SXMEM_POOL_MAGIC) { if((pHeader->nBucket >> 16) != SXMEM_POOL_MAGIC) {
return 0; return 0;
@@ -410,7 +430,10 @@ static void *MemBackendPoolRealloc(SyMemBackend *pBackend, void *pOld, sxu32 nBy
return MemBackendRealloc(&(*pBackend), pHeader, nByte); return MemBackendRealloc(&(*pBackend), pHeader, nByte);
} }
nBucketSize = 1 << (nBucket + SXMEM_POOL_INCR); 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 */ /* The old bucket can honor the requested size */
return pOld; 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++; ((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; pObj = (ph7_class_instance *)pDest->x.pOther;
} }
SyMemcpy((const void *) & (*pSrc), &(*pDest), sizeof(ph7_value) - (sizeof(ph7_vm *) + sizeof(SyBlob) + sizeof(sxu32))); 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; SyString sName;
/* Extract function name */ /* Extract function name */
/* Synthetic calls have no preceding instruction at pc == 0. */ /* 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"); PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Calling a non-callable object");
} else if((pTos->nType & (MEMOBJ_CALL | MEMOBJ_STRING)) == 0) { } else if((pTos->nType & (MEMOBJ_CALL | MEMOBJ_STRING)) == 0) {
if(pTos->nType & MEMOBJ_HASHMAP) { if(pTos->nType & MEMOBJ_HASHMAP) {
@@ -5585,14 +5602,8 @@ Resume:
PH7_MemObjStore(&sResult, pTos); PH7_MemObjStore(&sResult, pTos);
PH7_MemObjRelease(&sResult); PH7_MemObjRelease(&sResult);
} else { } else {
if(pTos->nType & MEMOBJ_OBJ) { /* Raise exception: Invalid function name */
ph7_class_instance *pThis = (ph7_class_instance *)pTos->x.pOther; PH7_VmThrowError(&(*pVm), PH7_CTX_WARNING, "Invalid function name");
/* 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");
}
/* Pop given arguments */ /* Pop given arguments */
if(pInstr->iP1 > 0) { if(pInstr->iP1 > 0) {
VmPopOperand(&pTos, pInstr->iP1); VmPopOperand(&pTos, pInstr->iP1);