diff --git a/engine/hashmap.c b/engine/hashmap.c index 8504d7b..3e1ee05 100644 --- a/engine/hashmap.c +++ b/engine/hashmap.c @@ -261,6 +261,8 @@ static sxi32 HashmapGrowBucket(ph7_hashmap *pMap) { */ static sxi32 HashmapInsertIntKey(ph7_hashmap *pMap, sxi64 iKey, ph7_value *pValue, sxu32 nRefIdx) { ph7_hashmap_node *pNode; + sxu32 nValue = pValue ? pValue->nIdx : SXU32_HIGH; + sxi32 bArena = pValue && SySetAt(&pMap->pVm->aMemObj, nValue) == pValue; sxu32 nIdx; sxu32 nHash; sxi32 rc; @@ -271,11 +273,15 @@ static sxi32 HashmapInsertIntKey(ph7_hashmap *pMap, sxi64 iKey, ph7_value *pValu if(pObj == 0) { return SXERR_MEM; } + nIdx = pObj->nIdx; if(pValue) { + /* Reserve may move the source slot as well as the new destination. */ + if(bArena) { + pValue = (ph7_value *)SySetAt(&pMap->pVm->aMemObj, nValue); + } /* Duplicate the value */ PH7_MemObjStore(pValue, pObj); } - nIdx = pObj->nIdx; /* Hash the key */ nHash = pMap->xIntHash(iKey); /* Allocate a new int node */ @@ -302,6 +308,8 @@ static sxi32 HashmapInsertIntKey(ph7_hashmap *pMap, sxi64 iKey, ph7_value *pValu */ static sxi32 HashmapInsertBlobKey(ph7_hashmap *pMap, const void *pKey, sxu32 nKeyLen, ph7_value *pValue, sxu32 nRefIdx) { ph7_hashmap_node *pNode; + sxu32 nValue = pValue ? pValue->nIdx : SXU32_HIGH; + sxi32 bArena = pValue && SySetAt(&pMap->pVm->aMemObj, nValue) == pValue; sxu32 nHash; sxu32 nIdx; sxi32 rc; @@ -312,11 +320,15 @@ static sxi32 HashmapInsertBlobKey(ph7_hashmap *pMap, const void *pKey, sxu32 nKe if(pObj == 0) { return SXERR_MEM; } + nIdx = pObj->nIdx; if(pValue) { + /* Reserve may move the source slot as well as the new destination. */ + if(bArena) { + pValue = (ph7_value *)SySetAt(&pMap->pVm->aMemObj, nValue); + } /* Duplicate the value */ PH7_MemObjStore(pValue, pObj); } - nIdx = pObj->nIdx; /* Hash the key */ nHash = pMap->xBlobHash(pKey, nKeyLen); /* Allocate a new blob node */ diff --git a/engine/memobj.c b/engine/memobj.c index fd44dd8..543ea47 100644 --- a/engine/memobj.c +++ b/engine/memobj.c @@ -399,13 +399,22 @@ PH7_PRIVATE sxi32 PH7_CheckVarCompat(ph7_value *pObj, int nType) { * destination are of the compatible data types. */ PH7_PRIVATE sxi32 PH7_MemObjSafeStore(ph7_value *pSrc, ph7_value *pDest) { + /* Scalar destinations need not have initialized arena metadata. */ + ph7_vm *pVm = (pSrc->nType & MEMOBJ_HASHMAP) ? pDest->pVm : 0; + sxu32 nDest = pVm ? pDest->nIdx : SXU32_HIGH; + sxi32 bArena = pVm && SySetAt(&pVm->aMemObj, nDest) == pDest; if(pDest->nType == 0 || pDest->nType == MEMOBJ_NULL || pDest->nType == pSrc->nType) { + sxu32 nType = pSrc->nType; PH7_MemObjStore(pSrc, pDest); + /* Array copies can move both source and destination arena slots. */ + if(bArena) { + pDest = (ph7_value *)SySetAt(&pVm->aMemObj, nDest); + } if(pDest->nType == 0 || pDest->nType == MEMOBJ_NULL) { - if(pSrc->nType == MEMOBJ_NULL) { + if(nType == MEMOBJ_NULL) { pDest->nType = MEMOBJ_VOID; } else { - pDest->nType = pSrc->nType; + pDest->nType = nType; } } } else if(pDest->nType & MEMOBJ_MIXED) { @@ -413,6 +422,9 @@ PH7_PRIVATE sxi32 PH7_MemObjSafeStore(ph7_value *pSrc, ph7_value *pDest) { /* mixed[] */ if(pSrc->nType & MEMOBJ_HASHMAP) { PH7_MemObjStore(pSrc, pDest); + if(bArena) { + pDest = (ph7_value *)SySetAt(&pVm->aMemObj, nDest); + } pDest->nType |= MEMOBJ_MIXED; } else if(pSrc->nType & MEMOBJ_NULL) { PH7_MemObjToHashmap(pSrc); @@ -946,12 +958,6 @@ PH7_PRIVATE sxi32 PH7_MemObjStore(ph7_value *pSrc, ph7_value *pDest) { pObj = (ph7_class_instance *)pDest->x.pOther; } SyMemcpy((const void *) & (*pSrc), &(*pDest), sizeof(ph7_value) - (sizeof(ph7_vm *) + sizeof(SyBlob) + sizeof(sxu32))); - if(pSrcMap) { - ph7_hashmap *pMap; - pMap = PH7_NewHashmap(&(*pDest->pVm), 0, 0); - PH7_HashmapDup(pSrcMap, pMap); - pDest->x.pOther = pMap; - } rc = SXRET_OK; if(SyBlobLength(&pSrc->sBlob) > 0) { SyBlobReset(&pDest->sBlob); @@ -961,6 +967,20 @@ PH7_PRIVATE sxi32 PH7_MemObjStore(ph7_value *pSrc, ph7_value *pDest) { SyBlobRelease(&pDest->sBlob); } } + if(pSrcMap) { + ph7_vm *pVm = pDest->pVm; + sxu32 nDest = pDest->nIdx; + sxi32 bArena = SySetAt(&pVm->aMemObj, nDest) == pDest; + ph7_hashmap *pMap; + /* Finish reading the source before recursive copies relocate aMemObj. + * Stack destinations have no arena slot and must not be rebound. */ + pMap = PH7_NewHashmap(pVm, 0, 0); + PH7_HashmapDup(pSrcMap, pMap); + if(bArena) { + pDest = (ph7_value *)SySetAt(&pVm->aMemObj, nDest); + } + pDest->x.pOther = pMap; + } if(pObj) { PH7_ClassInstanceUnref(pObj); }