diff --git a/engine/memobj.c b/engine/memobj.c index 46606a5..acf524d 100644 --- a/engine/memobj.c +++ b/engine/memobj.c @@ -401,7 +401,7 @@ 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) { - if(pDest->iFlags == 0 || pDest->iFlags == pSrc->iFlags) { + if(pDest->iFlags == 0 || ((pDest->iFlags | MEMOBJ_FIXEDVAL | MEMOBJ_PARENTOBJ) == (pSrc->iFlags | MEMOBJ_FIXEDVAL | MEMOBJ_PARENTOBJ))) { PH7_MemObjStore(pSrc, pDest); } else if(pDest->iFlags & MEMOBJ_MIXED) { if(pDest->iFlags & MEMOBJ_HASHMAP) { diff --git a/engine/vm.c b/engine/vm.c index 9e43460..653f7e0 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -2765,6 +2765,8 @@ static sxi32 VmByteCodeExec( if(pObj == 0) { PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Variable '$%z' undeclared (first use in this method/closure)", &sName); + } else if(pObj->iFlags & MEMOBJ_FIXEDVAL) { + PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Cannot re-assign a value of '$%z' statement", &sName); } if(!pInstr->p3) { PH7_MemObjRelease(&pTos[1]); @@ -4152,6 +4154,13 @@ static sxi32 VmByteCodeExec( pThis = (ph7_class_instance *)pNos->x.pOther; /* Point to the instantiated class */ pClass = pThis->pClass; + if(pNos->iFlags & MEMOBJ_PARENTOBJ) { + if(pClass->pBase == 0) { + PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, + "Attempt to call parent class from non-inheritance instance of class '%z'", &pClass->sName); + } + pClass = pClass->pBase; + } /* Extract attribute name first */ SyStringInitFromBuf(&sName, (const char *)SyBlobData(&pTos->sBlob), SyBlobLength(&pTos->sBlob)); if(pInstr->iP2) { @@ -4552,7 +4561,7 @@ static sxi32 VmByteCodeExec( if(pTarget->iFlags & MEMOBJ_OBJ) { /* Instance already loaded */ pThis = (ph7_class_instance *)pTarget->x.pOther; - pThis->iRef++; + pThis->iRef += 2; pSelf = pThis->pClass; } if(pSelf == 0) { @@ -4565,20 +4574,6 @@ static sxi32 VmByteCodeExec( pSelf = (ph7_class *)pVmFunc->pUserData; } } - if(pThis == 0) { - VmFrame *pFrame = pVm->pFrame; - while(pFrame->pParent && (pFrame->iFlags & VM_FRAME_EXCEPTION)) { - /* Safely ignore the exception frame */ - pFrame = pFrame->pParent; - } - if(pFrame->pParent) { - /* TICKET-1433-52: Make sure the '$this' variable is available to the current scope */ - pThis = pFrame->pThis; - if(pThis) { - pThis->iRef++; - } - } - } VmPopOperand(&pTos, 1); PH7_MemObjRelease(pTos); /* Synchronize pointers */ @@ -4633,14 +4628,24 @@ static sxi32 VmByteCodeExec( /* Raise exception: Out of memory */ PH7_VmMemoryError(&(*pVm)); } - if((pVmFunc->iFlags & VM_FUNC_CLASS_METHOD) && pThis) { - /* Install the '$this' variable */ - static const SyString sThis = { "this", sizeof("this") - 1 }; - pObj = VmCreateMemObj(&(*pVm), &sThis, FALSE); + if(pVmFunc->iFlags & VM_FUNC_CLASS_METHOD) { + /* Install the '$parent' variable */ + static const SyString sParent = { "parent", sizeof("parent") - 1 }; + pObj = VmCreateMemObj(&(*pVm), &sParent, TRUE); if(pObj) { /* Reflect the change */ pObj->x.pOther = pThis; MemObjSetType(pObj, MEMOBJ_OBJ); + pObj->iFlags |= MEMOBJ_FIXEDVAL | MEMOBJ_PARENTOBJ; + } + /* Install the '$this' variable */ + static const SyString sThis = { "this", sizeof("this") - 1 }; + pObj = VmCreateMemObj(&(*pVm), &sThis, TRUE); + if(pObj) { + /* Reflect the change */ + pObj->x.pOther = pThis; + MemObjSetType(pObj, MEMOBJ_OBJ); + pObj->iFlags |= MEMOBJ_FIXEDVAL; } } if(SySetUsed(&pVmFunc->aStatic) > 0) { diff --git a/include/ph7int.h b/include/ph7int.h index 86f35e2..ac29894 100644 --- a/include/ph7int.h +++ b/include/ph7int.h @@ -643,6 +643,9 @@ struct ph7_value { #define MEMOBJ_MIXED 0x0200 /* Memory value is mixed */ #define MEMOBJ_HASHMAP 0x0400 /* Memory value is a hashmap aka 'array' in the PHP jargon */ #define MEMOBJ_NULL 0x0800 /* Memory value is NULL */ +/* Special purpose */ +#define MEMOBJ_FIXEDVAL 0x1000 /* Memory value is fixed and cannot be modified */ +#define MEMOBJ_PARENTOBJ 0x2000 /* Memory value is a parent object */ /* Mask of all known types */ #define MEMOBJ_ALL (MEMOBJ_STRING|MEMOBJ_INT|MEMOBJ_REAL|MEMOBJ_BOOL|MEMOBJ_NULL|MEMOBJ_HASHMAP|MEMOBJ_OBJ|MEMOBJ_RES|MEMOBJ_CALL|MEMOBJ_CHAR|MEMOBJ_VOID) /* Scalar variables