Test and temporary version of compiler emiting PH7_OP_CLASS_INIT instruction.

However it works on ph7_class and thus passes whole class into the VM, what causes memory overhead,
as finally we have to find this class on the VM's stack. Instead, we could pass some ph7_class_info
structure containing a name of class to look for and information about its inheritances.
This commit is contained in:
Rafal Kupiec 2018-07-27 08:24:53 +02:00
parent c24a9bc251
commit b040886b97
Signed by: belliash
GPG Key ID: 4E829243E0CFE6B4
4 changed files with 91 additions and 70 deletions

View File

@ -4226,6 +4226,8 @@ static sxi32 GenStateCompileClass(ph7_gen_state *pGen, sxi32 iFlags) {
SyString *pName;
sxi32 nKwrd;
sxi32 rc;
sxi32 iP1 = 0;
sxu32 iP2 = 0;
/* Jump the 'class' keyword */
pGen->pIn++;
if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & PH7_TK_ID) == 0) {
@ -4256,10 +4258,11 @@ static sxi32 GenStateCompileClass(ph7_gen_state *pGen, sxi32 iFlags) {
/* Assume a standalone class */
pBase = 0;
if(pGen->pIn < pGen->pEnd && (pGen->pIn->nType & PH7_TK_KEYWORD)) {
SyString *pBaseName;
SyString pBaseName;
nKwrd = SX_PTR_TO_INT(pGen->pIn->pUserData);
if(nKwrd == PH7_TKWRD_EXTENDS /* class b extends a */) {
pGen->pIn++; /* Advance the stream cursor */
for(;;) {
if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & PH7_TK_ID) == 0) {
/* Syntax error */
rc = PH7_GenCompileError(pGen, E_ERROR, nLine,
@ -4273,33 +4276,24 @@ static sxi32 GenStateCompileClass(ph7_gen_state *pGen, sxi32 iFlags) {
return SXRET_OK;
}
/* Extract base class name */
pBaseName = &pGen->pIn->sData;
// /* Perform the query */
// pBase = PH7_VmExtractClass(pGen->pVm, pBaseName->zString, pBaseName->nByte, FALSE, 0);
// /* Interface is not allowed */
// if(pBase == 0 || (pBase->iFlags & PH7_CLASS_INTERFACE)) {
// /* Inexistant base class */
// rc = PH7_GenCompileError(pGen, E_ERROR, pGen->pIn->nLine, "Inexistant base class '%z'", pBaseName);
// if(rc == SXERR_ABORT) {
// /* Error count limit reached,abort immediately */
// return SXERR_ABORT;
// }
// } else {
// if(pBase->iFlags & PH7_CLASS_FINAL) {
// rc = PH7_GenCompileError(pGen, E_ERROR, nLine,
// "Class '%z' may not inherit from final class '%z'", pName, &pBase->sName);
// if(rc == SXERR_ABORT) {
// /* Error count limit reached,abort immediately */
// return SXERR_ABORT;
// }
// }
// }
char *pName = malloc(pGen->pIn->sData.nByte);
SyStrncpy(pName, pGen->pIn->sData.zString, pGen->pIn->sData.nByte);
SyStringInitFromBuf(&pBaseName, pName, SyStrlen(pName));
/* Register inherited class */
SySetPut(&pClass->sExtends, (const void *)&pBaseName);
/* Advance the stream cursor */
pGen->pIn++;
if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & PH7_TK_COMMA) == 0) {
break;
}
/* Jump the comma operator */
pGen->pIn++;
}
iP1 = 1;
}
if(pGen->pIn < pGen->pEnd && (pGen->pIn->nType & PH7_TK_KEYWORD) && SX_PTR_TO_INT(pGen->pIn->pUserData) == PH7_TKWRD_IMPLEMENTS) {
ph7_class *pInterface;
SyString *pIntName;
SyString pIntName;
/* Interface implementation */
pGen->pIn++; /* Advance the stream cursor */
for(;;) {
@ -4308,35 +4302,28 @@ static sxi32 GenStateCompileClass(ph7_gen_state *pGen, sxi32 iFlags) {
rc = PH7_GenCompileError(pGen, E_ERROR, nLine,
"Expected 'interface_name' after 'implements' keyword inside class '%z' declaration",
pName);
SyMemBackendPoolFree(&pGen->pVm->sAllocator, pClass);
if(rc == SXERR_ABORT) {
/* Error count limit reached,abort immediately */
return SXERR_ABORT;
}
break;
return SXRET_OK;
}
/* Extract interface name */
pIntName = &pGen->pIn->sData;
/* Make sure the interface is already defined */
pInterface = PH7_VmExtractClass(pGen->pVm, pIntName->zString, pIntName->nByte, FALSE, 0);
/* Only interfaces are allowed */
if(pInterface == 0 || (pInterface->iFlags & PH7_CLASS_INTERFACE) == 0) {
/* Inexistant interface */
rc = PH7_GenCompileError(pGen, E_ERROR, pGen->pIn->nLine, "Inexistant base interface '%z'", pIntName);
if(rc == SXERR_ABORT) {
/* Error count limit reached,abort immediately */
return SXERR_ABORT;
}
} else {
/* Register interface */
SySetPut(&aInterfaces, (const void *)&pInterface);
}
char *pName = malloc(pGen->pIn->sData.nByte);
SyStrncpy(pName, pGen->pIn->sData.zString, pGen->pIn->sData.nByte);
SyStringInitFromBuf(&pIntName, pName, SyStrlen(pName));
/* Register inherited class */
SySetPut(&pClass->sImplements, (const void *)&pIntName);
/* Advance the stream cursor */
pGen->pIn++;
if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & PH7_TK_COMMA) == 0) {
break;
}
pGen->pIn++;/* Jump the comma */
/* Jump the comma */
pGen->pIn++;
}
iP2 = 1;
}
}
if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & PH7_TK_OCB /*'{'*/) == 0) {
@ -4576,23 +4563,10 @@ static sxi32 GenStateCompileClass(ph7_gen_state *pGen, sxi32 iFlags) {
}
/* Install the class */
rc = PH7_VmInstallClass(pGen->pVm, pClass);
// if(rc == SXRET_OK) {
// ph7_class **apInterface;
// sxu32 n;
// if(pBase) {
// /* Inherit from base class and mark as a subclass */
// rc = PH7_ClassInherit(&(*pGen), pClass, pBase);
// }
// apInterface = (ph7_class **)SySetBasePtr(&aInterfaces);
// for(n = 0 ; n < SySetUsed(&aInterfaces) ; n++) {
// /* Implements one or more interface */
// rc = PH7_ClassImplement(pClass, apInterface[n]);
// if(rc != SXRET_OK) {
// break;
// }
// }
// }
SySetRelease(&aInterfaces);
if(iP1 || iP2) {
/* Emit the CLASS_INIT instruction only if there is such a need */
PH7_VmEmitInstr(pGen->pVm, PH7_OP_CLASS_INIT, iP1, iP2, pClass, 0);
}
if(rc != SXRET_OK) {
PH7_GenCompileError(pGen, E_ERROR, nLine, "Fatal, PH7 is running out of memory");
return SXERR_ABORT;

View File

@ -41,6 +41,8 @@ PH7_PRIVATE ph7_class *PH7_NewRawClass(ph7_vm *pVm, const SyString *pName, sxu32
SyHashInit(&pClass->hAttr, &pVm->sAllocator, 0, 0);
SyHashInit(&pClass->hDerived, &pVm->sAllocator, 0, 0);
SySetInit(&pClass->aInterface, &pVm->sAllocator, sizeof(ph7_class *));
SySetInit(&pClass->sExtends, &pVm->sAllocator, sizeof(SyString));
SySetInit(&pClass->sImplements, &pVm->sAllocator, sizeof(SyString));
pClass->nLine = nLine;
/* All done */
return pClass;

View File

@ -4508,6 +4508,41 @@ static sxi32 VmByteCodeExec(
pc = nJump - 1;
break;
}
/*
* OP_CLASS_INIT P1 P2 P3
* Perform additional class initialization, by adding base classes
* and interfaces to its definition.
*/
case PH7_OP_CLASS_INIT:
{
ph7_class *pClass = (ph7_class *)pInstr->p3;
printf("Called by class: '%s'\n", pClass->sName);
if(pInstr->iP1) {
/* This class inherits from other classes */
SyString *apExtends;
while(SySetGetNextEntry(&pClass->sExtends, (void **)&apExtends) == SXRET_OK) {
printf("Class '%s' inherits from '%s'\n", pClass->sName.zString, apExtends->zString);
}
}
if(pInstr->iP2) {
/* This class implements some interfaces */
SyString *apImplements;
while(SySetGetNextEntry(&pClass->sImplements, (void **)&apImplements) == SXRET_OK) {
printf("Class '%s' implements '%s'\n", pClass->sName.zString, apImplements->zString);
}
}
SyStringInitFromBuf(&pClass->sName, "DUPA", 4);
break;
}
/*
* OP_INTERFACE_INIT * * P3
* Perform additional interface initialization, by adding base interfaces
* to its definition.
*/
case PH7_OP_INTERFACE_INIT:
{
break;
}
/*
* OP_FOREACH_INIT * P2 P3
* Prepare a foreach step.
@ -6025,6 +6060,12 @@ static const char *VmInstrToString(sxi32 nOp) {
case PH7_OP_THROW:
zOp = "THROW ";
break;
case PH7_OP_CLASS_INIT:
zOp = "CLASS_INIT ";
break;
case PH7_OP_INTERFACE_INIT:
zOp = "INTER_INIT ";
break;
case PH7_OP_FOREACH_INIT:
zOp = "4EACH_INIT ";
break;

View File

@ -1035,6 +1035,8 @@ struct ph7_class {
SyHash hMethod; /* Class methods */
sxu32 nLine; /* Line number on which this class was declared */
SySet aInterface; /* Implemented interface container */
SySet sExtends; /* List of inherited classes / interfaces */
SySet sImplements; /* List of implemented interfaces */
};
/* Class configuration flags */
#define PH7_CLASS_FINAL 0x001 /* Class is final [cannot be extended] */
@ -1360,6 +1362,8 @@ enum ph7_vm_op {
PH7_OP_CVT_NULL, /* NULL cast */
PH7_OP_CVT_ARRAY, /* Array cast */
PH7_OP_CVT_OBJ, /* Object cast */
PH7_OP_CLASS_INIT, /* Class init */
PH7_OP_INTERFACE_INIT,/* Interface init */
PH7_OP_FOREACH_INIT, /* For each init */
PH7_OP_FOREACH_STEP, /* For each step */
PH7_OP_IS_A, /* Instanceof */