From b040886b9725a623d8fd268709bde6e03ff67a1b Mon Sep 17 00:00:00 2001 From: belliash Date: Fri, 27 Jul 2018 08:24:53 +0200 Subject: [PATCH] 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. --- engine/compiler.c | 114 ++++++++++++++++++---------------------------- engine/oop.c | 2 + engine/vm.c | 41 +++++++++++++++++ include/ph7int.h | 4 ++ 4 files changed, 91 insertions(+), 70 deletions(-) diff --git a/engine/compiler.c b/engine/compiler.c index ef32d5d..84db7f3 100644 --- a/engine/compiler.c +++ b/engine/compiler.c @@ -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,50 +4258,42 @@ 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 */ - if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & PH7_TK_ID) == 0) { - /* Syntax error */ - rc = PH7_GenCompileError(pGen, E_ERROR, nLine, - "Expected 'class_name' after 'extends' keyword inside class '%z'", - pName); - SyMemBackendPoolFree(&pGen->pVm->sAllocator, pClass); - if(rc == SXERR_ABORT) { - /* Error count limit reached,abort immediately */ - return SXERR_ABORT; + for(;;) { + if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & PH7_TK_ID) == 0) { + /* Syntax error */ + rc = PH7_GenCompileError(pGen, E_ERROR, nLine, + "Expected 'class_name' after 'extends' keyword inside class '%z'", + pName); + SyMemBackendPoolFree(&pGen->pVm->sAllocator, pClass); + if(rc == SXERR_ABORT) { + /* Error count limit reached,abort immediately */ + return SXERR_ABORT; + } + return SXRET_OK; } - return SXRET_OK; + /* Extract base class name */ + 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++; } - /* 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; -// } -// } -// } - /* Advance the stream cursor */ - 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; diff --git a/engine/oop.c b/engine/oop.c index 33ca357..33c947b 100644 --- a/engine/oop.c +++ b/engine/oop.c @@ -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; diff --git a/engine/vm.c b/engine/vm.c index 47c4e95..cf3bc8a 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -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; diff --git a/include/ph7int.h b/include/ph7int.h index 1724a22..cb3e9e2 100644 --- a/include/ph7int.h +++ b/include/ph7int.h @@ -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 */