Preserve runtime object identity and declaring-class scope in inherited method calls
Build / AerScript (push) Successful in 2m48s
Build / AerScript (push) Successful in 2m48s
This commit is contained in:
+46
-23
@@ -1391,6 +1391,19 @@ static ph7_value *VmNewOperandStack(
|
|||||||
/* Forward declaration */
|
/* Forward declaration */
|
||||||
static sxi32 VmRegisterSpecialFunction(ph7_vm *pVm);
|
static sxi32 VmRegisterSpecialFunction(ph7_vm *pVm);
|
||||||
static int VmClassMemberAccess(ph7_vm *pVm, ph7_class *pClass, sxi32 iProtection);
|
static int VmClassMemberAccess(ph7_vm *pVm, ph7_class *pClass, sxi32 iProtection);
|
||||||
|
/* Exception frames retain the enclosing method's lexical scope. */
|
||||||
|
static ph7_class *VmMethodClass(ph7_vm *pVm) {
|
||||||
|
VmFrame *pFrame = pVm->pFrame;
|
||||||
|
ph7_vm_func *pVmFunc;
|
||||||
|
while(pFrame->pParent && (pFrame->iFlags & (VM_FRAME_EXCEPTION | VM_FRAME_CATCH | VM_FRAME_FINALLY))) {
|
||||||
|
pFrame = pFrame->pParent;
|
||||||
|
}
|
||||||
|
pVmFunc = (ph7_vm_func *)pFrame->pUserData;
|
||||||
|
if(pVmFunc == 0 || (pVmFunc->iFlags & VM_FUNC_CLASS_METHOD) == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return (ph7_class *)pVmFunc->pUserData;
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* Prepare the Virtual Machine for byte-code execution.
|
* Prepare the Virtual Machine for byte-code execution.
|
||||||
* This routine gets called by the PH7 engine after
|
* This routine gets called by the PH7 engine after
|
||||||
@@ -4451,12 +4464,17 @@ static sxi32 VmByteCodeExec(
|
|||||||
if(!pNos->x.pOther) {
|
if(!pNos->x.pOther) {
|
||||||
PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Call to non-instantiated object '$%z'", &sName);
|
PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Call to non-instantiated object '$%z'", &sName);
|
||||||
}
|
}
|
||||||
ph7_class *pClass, *pDerived;
|
ph7_class *pClass, *pDerived, *pScope;
|
||||||
/* Class already instantiated */
|
/* Class already instantiated */
|
||||||
pThis = (ph7_class_instance *)pNos->x.pOther;
|
pThis = (ph7_class_instance *)pNos->x.pOther;
|
||||||
/* Point to the instantiated class */
|
/* Point to the instantiated class */
|
||||||
pClass = pThis->pClass;
|
pClass = pThis->pClass;
|
||||||
|
pScope = VmMethodClass(pVm);
|
||||||
if(pNos->iFlags == MEMOBJ_PARENTOBJ) {
|
if(pNos->iFlags == MEMOBJ_PARENTOBJ) {
|
||||||
|
/* Parent lookup starts at the declaring class, not the receiver. */
|
||||||
|
if(pScope) {
|
||||||
|
pClass = pScope;
|
||||||
|
}
|
||||||
if(pClass->pBase == 0) {
|
if(pClass->pBase == 0) {
|
||||||
PH7_VmThrowError(&(*pVm), PH7_CTX_ERR,
|
PH7_VmThrowError(&(*pVm), PH7_CTX_ERR,
|
||||||
"Attempt to call parent class from non-inheritance instance of class '%z'", &pClass->sName);
|
"Attempt to call parent class from non-inheritance instance of class '%z'", &pClass->sName);
|
||||||
@@ -4470,7 +4488,15 @@ static sxi32 VmByteCodeExec(
|
|||||||
if(sName.nByte > 0) {
|
if(sName.nByte > 0) {
|
||||||
/* Extract the target method */
|
/* Extract the target method */
|
||||||
if(pNos->iFlags != MEMOBJ_PARENTOBJ) {
|
if(pNos->iFlags != MEMOBJ_PARENTOBJ) {
|
||||||
pMeth = PH7_ClassExtractMethod(pClass, sName.zString, sName.nByte);
|
if(pScope && VmInstanceOf(pClass, pScope)) {
|
||||||
|
pMeth = PH7_ClassExtractMethod(pScope, sName.zString, sName.nByte);
|
||||||
|
if(pMeth && (pMeth->iProtection != PH7_CLASS_PROT_PRIVATE || pMeth->sFunc.pClass != pScope)) {
|
||||||
|
pMeth = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(pMeth == 0) {
|
||||||
|
pMeth = PH7_ClassExtractMethod(pClass, sName.zString, sName.nByte);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if(pMeth == 0) {
|
if(pMeth == 0) {
|
||||||
/* Browse hashtable from the beginning */
|
/* Browse hashtable from the beginning */
|
||||||
@@ -4510,7 +4536,16 @@ static sxi32 VmByteCodeExec(
|
|||||||
if(sName.nByte > 0) {
|
if(sName.nByte > 0) {
|
||||||
/* Extract the target attribute */
|
/* Extract the target attribute */
|
||||||
if(pNos->iFlags != MEMOBJ_PARENTOBJ) {
|
if(pNos->iFlags != MEMOBJ_PARENTOBJ) {
|
||||||
pAttr = PH7_ClassExtractAttribute(pClass, sName.zString, sName.nByte);
|
/* Private fields belong to their declaring class, even on a derived object. */
|
||||||
|
if(pScope && VmInstanceOf(pClass, pScope)) {
|
||||||
|
pAttr = PH7_ClassExtractAttribute(pScope, sName.zString, sName.nByte);
|
||||||
|
if(pAttr && pAttr->iProtection != PH7_CLASS_PROT_PRIVATE) {
|
||||||
|
pAttr = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(pAttr == 0) {
|
||||||
|
pAttr = PH7_ClassExtractAttribute(pClass, sName.zString, sName.nByte);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if(pAttr == 0) {
|
if(pAttr == 0) {
|
||||||
/* Browse hashtable from the beginning */
|
/* Browse hashtable from the beginning */
|
||||||
@@ -4903,7 +4938,6 @@ static sxi32 VmByteCodeExec(
|
|||||||
if(pEntry) {
|
if(pEntry) {
|
||||||
ph7_vm_func_arg *aFormalArg;
|
ph7_vm_func_arg *aFormalArg;
|
||||||
ph7_class_instance *pThis;
|
ph7_class_instance *pThis;
|
||||||
ph7_class *pClass;
|
|
||||||
ph7_value *pFrameStack;
|
ph7_value *pFrameStack;
|
||||||
ph7_vm_func *pVmFunc;
|
ph7_vm_func *pVmFunc;
|
||||||
ph7_class *pSelf;
|
ph7_class *pSelf;
|
||||||
@@ -4915,7 +4949,6 @@ static sxi32 VmByteCodeExec(
|
|||||||
pVmFunc = (ph7_vm_func *)pEntry->pUserData;
|
pVmFunc = (ph7_vm_func *)pEntry->pUserData;
|
||||||
pThis = 0;
|
pThis = 0;
|
||||||
pSelf = 0;
|
pSelf = 0;
|
||||||
pClass = 0;
|
|
||||||
if(pVmFunc->iFlags & VM_FUNC_CLASS_METHOD) {
|
if(pVmFunc->iFlags & VM_FUNC_CLASS_METHOD) {
|
||||||
/* Class method call */
|
/* Class method call */
|
||||||
ph7_value *pTarget = &pTos[-1];
|
ph7_value *pTarget = &pTos[-1];
|
||||||
@@ -4925,9 +4958,7 @@ static sxi32 VmByteCodeExec(
|
|||||||
/* Instance already loaded */
|
/* Instance already loaded */
|
||||||
pThis = (ph7_class_instance *)pTarget->x.pOther;
|
pThis = (ph7_class_instance *)pTarget->x.pOther;
|
||||||
pThis->iRef += 2;
|
pThis->iRef += 2;
|
||||||
pClass = pThis->pClass;
|
pSelf = pVmFunc->pClass;
|
||||||
pThis->pClass = pVmFunc->pClass;
|
|
||||||
pSelf = pThis->pClass;
|
|
||||||
}
|
}
|
||||||
if(pSelf == 0) {
|
if(pSelf == 0) {
|
||||||
if((pTarget->nType & MEMOBJ_STRING) && SyBlobLength(&pTarget->sBlob) > 0) {
|
if((pTarget->nType & MEMOBJ_STRING) && SyBlobLength(&pTarget->sBlob) > 0) {
|
||||||
@@ -4957,6 +4988,9 @@ static sxi32 VmByteCodeExec(
|
|||||||
if(pInstr->iP2 == 0) {
|
if(pInstr->iP2 == 0) {
|
||||||
pVmFunc = VmOverload(&(*pVm), pVmFunc, pArg, (int)(pTos - pArg));
|
pVmFunc = VmOverload(&(*pVm), pVmFunc, pArg, (int)(pTos - pArg));
|
||||||
}
|
}
|
||||||
|
if(pThis && (pVmFunc->iFlags & VM_FUNC_CLASS_METHOD)) {
|
||||||
|
pSelf = pVmFunc->pClass;
|
||||||
|
}
|
||||||
/* Extract the formal argument set */
|
/* Extract the formal argument set */
|
||||||
aFormalArg = (ph7_vm_func_arg *)SySetBasePtr(&pVmFunc->aArgs);
|
aFormalArg = (ph7_vm_func_arg *)SySetBasePtr(&pVmFunc->aArgs);
|
||||||
/* Create a new VM frame */
|
/* Create a new VM frame */
|
||||||
@@ -5256,10 +5290,6 @@ static sxi32 VmByteCodeExec(
|
|||||||
SyMemBackendFree(&pVm->sAllocator, pFrameStack);
|
SyMemBackendFree(&pVm->sAllocator, pFrameStack);
|
||||||
/* Leave the frame */
|
/* Leave the frame */
|
||||||
VmLeaveFrame(&(*pVm));
|
VmLeaveFrame(&(*pVm));
|
||||||
if(pClass != 0 && pClass != pThis->pClass) {
|
|
||||||
/* Restore original class */
|
|
||||||
pThis->pClass = pClass;
|
|
||||||
}
|
|
||||||
if(rc == PH7_ABORT) {
|
if(rc == PH7_ABORT) {
|
||||||
/* Abort processing immediately */
|
/* Abort processing immediately */
|
||||||
goto Abort;
|
goto Abort;
|
||||||
@@ -6209,26 +6239,19 @@ static int VmClassMemberAccess(
|
|||||||
sxi32 iProtection /* Attribute protection level [i.e: public,protected or private] */
|
sxi32 iProtection /* Attribute protection level [i.e: public,protected or private] */
|
||||||
) {
|
) {
|
||||||
if(iProtection != PH7_CLASS_PROT_PUBLIC) {
|
if(iProtection != PH7_CLASS_PROT_PUBLIC) {
|
||||||
VmFrame *pFrame = pVm->pFrame;
|
ph7_class *pScope = VmMethodClass(pVm);
|
||||||
ph7_vm_func *pVmFunc;
|
if(pScope == 0) {
|
||||||
while(pFrame->pParent && (pFrame->iFlags & (VM_FRAME_EXCEPTION | VM_FRAME_CATCH | VM_FRAME_FINALLY))) {
|
|
||||||
/* Safely ignore the exception frame */
|
|
||||||
pFrame = pFrame->pParent;
|
|
||||||
}
|
|
||||||
pVmFunc = (ph7_vm_func *)pFrame->pUserData;
|
|
||||||
if(pVmFunc == 0 || (pVmFunc->iFlags & VM_FUNC_CLASS_METHOD) == 0) {
|
|
||||||
return 0; /* Access is forbidden */
|
return 0; /* Access is forbidden */
|
||||||
}
|
}
|
||||||
if(iProtection == PH7_CLASS_PROT_PRIVATE) {
|
if(iProtection == PH7_CLASS_PROT_PRIVATE) {
|
||||||
/* Must be the same instance */
|
/* Must be the same instance */
|
||||||
if((ph7_class *)pVmFunc->pUserData != pClass) {
|
if(pScope != pClass) {
|
||||||
return 0; /* Access is forbidden */
|
return 0; /* Access is forbidden */
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Protected */
|
/* Protected */
|
||||||
ph7_class *pBase = (ph7_class *)pVmFunc->pUserData;
|
|
||||||
/* Must be a derived class */
|
/* Must be a derived class */
|
||||||
if(!VmInstanceOf(pBase, pClass)) {
|
if(!VmInstanceOf(pScope, pClass)) {
|
||||||
return 0; /* Access is forbidden */
|
return 0; /* Access is forbidden */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user