Implement C3 class linearization and validate inheritance graphs
Build / AerScript (push) Successful in 2m13s
Build / AerScript (push) Successful in 2m13s
This commit is contained in:
+35
-26
@@ -451,7 +451,7 @@ static void VmLeaveFrame(ph7_vm *pVm) {
|
||||
}
|
||||
}
|
||||
/* Forward declaration */
|
||||
static int VmInstanceOf(ph7_class *pThis, ph7_class *pClass);
|
||||
static int VmInstanceOf(ph7_vm *pVm, ph7_class *pThis, ph7_class *pClass);
|
||||
/*
|
||||
* Ranks for general parameter types. Class and interface specificity uses
|
||||
* the shortest inheritance distance instead, which is always lower than
|
||||
@@ -2577,7 +2577,7 @@ static sxi32 VmByteCodeExec(
|
||||
}
|
||||
if(pThis) {
|
||||
/* Perform the query */
|
||||
iRes = VmInstanceOf(pThis->pClass, pClass);
|
||||
iRes = VmInstanceOf(pVm, pThis->pClass, pClass);
|
||||
}
|
||||
} else {
|
||||
rc = PH7_MemObjCmp(pNos, pTos, FALSE, 0);
|
||||
@@ -4195,7 +4195,7 @@ static sxi32 VmByteCodeExec(
|
||||
/* Make sure the loaded object is an instance of the 'Exception' base class.
|
||||
*/
|
||||
pException = PH7_VmExtractClass(&(*pVm), "Exception", sizeof("Exception") - 1, TRUE);
|
||||
if(pException == 0 || !VmInstanceOf(pThis->pClass, pException)) {
|
||||
if(pException == 0 || !VmInstanceOf(pVm, pThis->pClass, pException)) {
|
||||
/* Exceptions must be valid objects derived from the Exception base class */
|
||||
rc = VmUncaughtException(&(*pVm), pThis);
|
||||
if(rc == SXERR_ABORT) {
|
||||
@@ -4307,21 +4307,15 @@ static sxi32 VmByteCodeExec(
|
||||
ph7_class_info *pClassInfo = (ph7_class_info *)pInstr->p3;
|
||||
ph7_class *pClass = PH7_VmExtractClass(pVm, pClassInfo->sName.zString, pClassInfo->sName.nByte, FALSE);
|
||||
ph7_class *pBase = 0;
|
||||
rc = PH7_ClassBuildMro(pVm, pClass);
|
||||
if(rc != SXRET_OK) {
|
||||
goto Abort;
|
||||
}
|
||||
if(pInstr->iP1) {
|
||||
/* This class inherits from other classes */
|
||||
SyString *apExtends;
|
||||
while(SySetGetNextEntry(&pClassInfo->sExtends, (void **)&apExtends) == SXRET_OK) {
|
||||
pBase = PH7_VmExtractClass(pVm, apExtends->zString, apExtends->nByte, FALSE);
|
||||
if(pBase == 0) {
|
||||
/* Non-existent base class */
|
||||
PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Call to non-existent base class '%z'", &apExtends->zString);
|
||||
} else if(pBase->iFlags & PH7_CLASS_INTERFACE) {
|
||||
/* Trying to inherit from interface */
|
||||
PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Class '%z' cannot inherit from interface '%z'", &pClass->sName.zString, &apExtends->zString);
|
||||
} else if(pBase->iFlags & PH7_CLASS_FINAL) {
|
||||
/* Trying to inherit from final class */
|
||||
PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Class '%z' cannot inherit from final class '%z'", &pClass->sName.zString, &apExtends->zString);
|
||||
}
|
||||
sxu32 i;
|
||||
for(i = 0; i < SySetUsed(&pClass->aBase); i++) {
|
||||
pBase = *(ph7_class **)SySetAt(&pClass->aBase, i);
|
||||
rc = PH7_ClassInherit(pVm, pClass, pBase);
|
||||
if(rc != SXRET_OK) {
|
||||
break;
|
||||
@@ -4495,7 +4489,7 @@ static sxi32 VmByteCodeExec(
|
||||
if(sName.nByte > 0) {
|
||||
/* Extract the target method */
|
||||
if(pNos->iFlags != MEMOBJ_PARENTOBJ) {
|
||||
if(pScope && VmInstanceOf(pClass, pScope)) {
|
||||
if(pScope && VmInstanceOf(pVm, pClass, pScope)) {
|
||||
pMeth = PH7_ClassExtractMethod(pScope, sName.zString, sName.nByte);
|
||||
if(pMeth && (pMeth->iProtection != PH7_CLASS_PROT_PRIVATE || pMeth->sFunc.pClass != pScope)) {
|
||||
pMeth = 0;
|
||||
@@ -4544,7 +4538,7 @@ static sxi32 VmByteCodeExec(
|
||||
/* Extract the target attribute */
|
||||
if(pNos->iFlags != MEMOBJ_PARENTOBJ) {
|
||||
/* Private fields belong to their declaring class, even on a derived object. */
|
||||
if(pScope && VmInstanceOf(pClass, pScope)) {
|
||||
if(pScope && VmInstanceOf(pVm, pClass, pScope)) {
|
||||
pAttr = PH7_ClassExtractAttribute(pScope, sName.zString, sName.nByte);
|
||||
if(pAttr && pAttr->iProtection != PH7_CLASS_PROT_PRIVATE) {
|
||||
pAttr = 0;
|
||||
@@ -5092,7 +5086,7 @@ static sxi32 VmByteCodeExec(
|
||||
} else {
|
||||
ph7_class_instance *pThis = (ph7_class_instance *)pArg->x.pOther;
|
||||
/* Make sure the object is an instance of the given class */
|
||||
if(pThis == 0 || !VmInstanceOf(pThis->pClass, pClass)) {
|
||||
if(pThis == 0 || !VmInstanceOf(pVm, pThis->pClass, pClass)) {
|
||||
PH7_VmThrowError(&(*pVm), PH7_CTX_ERR,
|
||||
"Argument %u passed to function '%z()' must be an object of type '%z'",
|
||||
n+1, &pVmFunc->sName, pName);
|
||||
@@ -5207,7 +5201,7 @@ static sxi32 VmByteCodeExec(
|
||||
} else {
|
||||
ph7_class_instance *pThis = (ph7_class_instance *)pObj->x.pOther;
|
||||
/* Make sure the object is an instance of the given class */
|
||||
if(pThis == 0 || !VmInstanceOf(pThis->pClass, pClass)) {
|
||||
if(pThis == 0 || !VmInstanceOf(pVm, pThis->pClass, pClass)) {
|
||||
PH7_VmThrowError(&(*pVm), PH7_CTX_ERR,
|
||||
"Default value for argument %u of '%z()' must be an object of type '%z'",
|
||||
n+1, &pVmFunc->sName, pName);
|
||||
@@ -6258,7 +6252,7 @@ static int VmClassMemberAccess(
|
||||
} else {
|
||||
/* Protected */
|
||||
/* Must be a derived class */
|
||||
if(!VmInstanceOf(pScope, pClass)) {
|
||||
if(!VmInstanceOf(pVm, pScope, pClass)) {
|
||||
return 0; /* Access is forbidden */
|
||||
}
|
||||
}
|
||||
@@ -6428,7 +6422,7 @@ static int VmQueryInterfaceSet(ph7_class *pClass, SySet *pSet) {
|
||||
* is an instance of the main class (second argument).
|
||||
* Otherwise FALSE is returned.
|
||||
*/
|
||||
static int VmInstanceOf(ph7_class *pThis, ph7_class *pClass) {
|
||||
static int VmInstanceOf(ph7_vm *pVm, ph7_class *pThis, ph7_class *pClass) {
|
||||
SyHashEntry *pEntry;
|
||||
ph7_class *pDerived, *pParent;
|
||||
sxi32 rc;
|
||||
@@ -6436,6 +6430,18 @@ static int VmInstanceOf(ph7_class *pThis, ph7_class *pClass) {
|
||||
/* Instance of the same class */
|
||||
return TRUE;
|
||||
}
|
||||
if(!(pThis->iFlags & PH7_CLASS_INTERFACE) && !(pClass->iFlags & PH7_CLASS_INTERFACE)) {
|
||||
sxu32 i;
|
||||
if(PH7_ClassBuildMro(pVm, pThis) != SXRET_OK) {
|
||||
PH7_VmThrowError(pVm, PH7_CTX_ERR, "PH7 is running out-of-memory");
|
||||
}
|
||||
for(i = 1; i < SySetUsed(&pThis->aMro); i++) {
|
||||
if(*(ph7_class **)SySetAt(&pThis->aMro, i) == pClass) {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
/* Check implemented interfaces */
|
||||
rc = VmQueryInterfaceSet(pClass, &pThis->aInterface);
|
||||
if(rc) {
|
||||
@@ -6478,11 +6484,14 @@ static int VmInstanceOf(ph7_class *pThis, ph7_class *pClass) {
|
||||
* is a subclass of the main class (second argument).
|
||||
* Otherwise FALSE is returned.
|
||||
*/
|
||||
static int VmSubclassOf(ph7_class *pClass, ph7_class *pBase) {
|
||||
static int VmSubclassOf(ph7_vm *pVm, ph7_class *pClass, ph7_class *pBase) {
|
||||
SySet *pInterface = &pClass->aInterface;
|
||||
SyHashEntry *pEntry;
|
||||
SyString *pName;
|
||||
sxi32 rc;
|
||||
if(!(pClass->iFlags & PH7_CLASS_INTERFACE) && !(pBase->iFlags & PH7_CLASS_INTERFACE)) {
|
||||
return pClass != pBase && VmInstanceOf(pVm, pClass, pBase);
|
||||
}
|
||||
while(pClass) {
|
||||
pName = &pClass->sName;
|
||||
/* Query the derived hashtable */
|
||||
@@ -6520,7 +6529,7 @@ static int vm_builtin_is_a(ph7_context *pCtx, int nArg, ph7_value **apArg) {
|
||||
pClass = VmExtractClassFromValue(pCtx->pVm, apArg[1]);
|
||||
if(pClass) {
|
||||
/* Perform the query */
|
||||
res = VmInstanceOf(pThis->pClass, pClass);
|
||||
res = VmInstanceOf(pCtx->pVm, pThis->pClass, pClass);
|
||||
}
|
||||
}
|
||||
/* Query result */
|
||||
@@ -6548,7 +6557,7 @@ static int vm_builtin_is_subclass_of(ph7_context *pCtx, int nArg, ph7_value **ap
|
||||
pMain = VmExtractClassFromValue(pCtx->pVm, apArg[1]);
|
||||
if(pClass && pMain) {
|
||||
/* Perform the query */
|
||||
res = VmSubclassOf(pClass, pMain);
|
||||
res = VmSubclassOf(pCtx->pVm, pClass, pMain);
|
||||
}
|
||||
}
|
||||
/* Query result */
|
||||
@@ -8288,7 +8297,7 @@ static sxi32 VmThrowException(
|
||||
/* No such class */
|
||||
continue;
|
||||
}
|
||||
if(VmInstanceOf(pThis->pClass, pClass)) {
|
||||
if(VmInstanceOf(pVm, pThis->pClass, pClass)) {
|
||||
/* Catch block found,break immediately */
|
||||
pCatch = &aCatch[j];
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user