Browse Source

Make constant declarations local.

There are several changes in this commit:
 * first of all constants declared by 'const' statement should be local (declared in current scope / frame),
 * constants are declared by using OP_DECLARE instruction,
 * OP_LOADC browses both global and local constants container,
 * PH7_VmRegisterConstant() allows both global and local declarations.
Since this commit, there are 3 kinds of constants:
 1) global
 2) local (in loop, closure, method)
 3) class members.
Actually there is no way to declare a global constant except the built-in constants.
release/v0.1
Rafal Kupiec 1 year ago
parent
commit
ab8bf48485
Signed by: belliash GPG Key ID: 4E829243E0CFE6B4
4 changed files with 109 additions and 65 deletions
  1. +1
    -1
      engine/api.c
  2. +26
    -23
      engine/compiler.c
  3. +71
    -40
      engine/vm.c
  4. +11
    -1
      include/ph7int.h

+ 1
- 1
engine/api.c View File

@ -1064,7 +1064,7 @@ int ph7_create_constant(ph7_vm *pVm, const char *zName, void (*xExpand)(ph7_valu
}
#endif
/* Perform the registration */
rc = PH7_VmRegisterConstant(&(*pVm), &sName, xExpand, pUserData);
rc = PH7_VmRegisterConstant(&(*pVm), &sName, xExpand, pUserData, TRUE);
#if defined(PH7_ENABLE_THREADS)
/* Leave VM mutex */
SyMutexLeave(sMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sMPGlobal.nThreadingLevel != PH7_THREAD_LEVEL_MULTI */


+ 26
- 23
engine/compiler.c View File

@ -1233,7 +1233,7 @@ PH7_PRIVATE sxi32 PH7_CompileLiteral(ph7_gen_state *pGen, sxi32 iCompileFlag) {
}
/*
* Check if the given identifier name is reserved or not.
* Return TRUE if reserved.FALSE otherwise.
* Return TRUE if reserved. FALSE otherwise.
*/
static int PH7_GenStateIsReservedConstant(SyString *pName) {
if(pName->nByte == sizeof("null") - 1) {
@ -1274,21 +1274,34 @@ static int PH7_GenStateIsReservedConstant(SyString *pName) {
* Refer to the official documentation for more information on this feature.
*/
static sxi32 PH7_CompileConstant(ph7_gen_state *pGen) {
SySet *pConsCode, *pInstrContainer;
SySet *pInstrContainer;
ph7_constant_info *pConstInfo;
sxu32 nLine = pGen->pIn->nLine;
SyString *pName;
char *zName;
sxi32 rc;
pGen->pIn++; /* Jump the 'const' keyword */
if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & (PH7_TK_SSTR | PH7_TK_DSTR | PH7_TK_ID | PH7_TK_KEYWORD)) == 0) {
/* Invalid constant name */
PH7_GenCompileError(pGen, E_ERROR, nLine, "const: Invalid constant name");
}
/* Allocate a new instance */
pConstInfo = (ph7_constant_info *)SyMemBackendPoolAlloc(&pGen->pVm->sAllocator, sizeof(ph7_constant_info));
if(pConstInfo == 0) {
PH7_GenCompileError(pGen, E_ERROR, nLine, "PH7 engine is running out-of-memory");
}
/* Zero the structure */
SyZero(pConstInfo, sizeof(ph7_constant_info));
/* Peek constant name */
pName = &pGen->pIn->sData;
zName = SyMemBackendStrDup(&pGen->pVm->sAllocator, pGen->pIn->sData.zString, pGen->pIn->sData.nByte);
if(zName == 0) {
PH7_GenCompileError(pGen, E_ERROR, nLine, "PH7 engine is running out-of-memory");
}
/* Duplicate constant name */
SyStringInitFromBuf(&pConstInfo->pName, zName, pGen->pIn->sData.nByte);
/* Make sure the constant name isn't reserved */
if(PH7_GenStateIsReservedConstant(pName)) {
if(PH7_GenStateIsReservedConstant(&pConstInfo->pName)) {
/* Reserved constant */
PH7_GenCompileError(pGen, E_ERROR, nLine, "const: Cannot redeclare a reserved constant '%z'", pName);
PH7_GenCompileError(pGen, E_ERROR, nLine, "const: Cannot redeclare a reserved constant '%z'", pConstInfo->pName);
}
pGen->pIn++;
if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & PH7_TK_EQUAL /* '=' */) == 0) {
@ -1297,14 +1310,14 @@ static sxi32 PH7_CompileConstant(ph7_gen_state *pGen) {
}
pGen->pIn++; /*Jump the equal sign */
/* Allocate a new constant value container */
pConsCode = (SySet *)SyMemBackendPoolAlloc(&pGen->pVm->sAllocator, sizeof(SySet));
if(pConsCode == 0) {
pConstInfo->pConsCode = (SySet *)SyMemBackendPoolAlloc(&pGen->pVm->sAllocator, sizeof(SySet));
if(pConstInfo->pConsCode == 0) {
PH7_GenCompileError(pGen, E_ERROR, nLine, "PH7 engine is running out-of-memory");
}
SySetInit(pConsCode, &pGen->pVm->sAllocator, sizeof(VmInstr));
SySetInit(pConstInfo->pConsCode, &pGen->pVm->sAllocator, sizeof(VmInstr));
/* Swap bytecode container */
pInstrContainer = PH7_VmGetByteCodeContainer(pGen->pVm);
PH7_VmSetByteCodeContainer(pGen->pVm, pConsCode);
PH7_VmSetByteCodeContainer(pGen->pVm, pConstInfo->pConsCode);
/* Compile constant value */
rc = PH7_CompileExpr(&(*pGen), 0, 0);
/* Emit the done instruction */
@ -1314,19 +1327,9 @@ static sxi32 PH7_CompileConstant(ph7_gen_state *pGen) {
/* Don't worry about freeing memory, everything will be released shortly */
return SXERR_ABORT;
}
SySetSetUserData(pConsCode, pGen->pVm);
/* Register the constant */
rc = PH7_VmRegisterConstant(pGen->pVm, pName, PH7_VmExpandConstantValue, pConsCode);
if(rc != SXRET_OK) {
SySetRelease(pConsCode);
SyMemBackendPoolFree(&pGen->pVm->sAllocator, pConsCode);
}
return SXRET_OK;
Synchronize:
/* Synchronize with the next-semi-colon and avoid compiling this erroneous statement */
while(pGen->pIn < pGen->pEnd && (pGen->pIn->nType & PH7_TK_SEMI) == 0) {
pGen->pIn++;
}
SySetSetUserData(pConstInfo->pConsCode, pGen->pVm);
/* Declare the constant in active frame */
PH7_VmEmitInstr(pGen->pVm, nLine, PH7_OP_DECLARE, 1, 0, pConstInfo, 0);
return SXRET_OK;
}
/*


+ 71
- 40
engine/vm.c View File

@ -69,40 +69,41 @@ PH7_PRIVATE sxi32 PH7_VmRegisterConstant(
ph7_vm *pVm, /* Target VM */
const SyString *pName, /* Constant name */
ProcConstant xExpand, /* Constant expansion callback */
void *pUserData /* Last argument to xExpand() */
void *pUserData, /* Last argument to xExpand() */
sxbool bGlobal /* Whether this is a global constant or not */
) {
ph7_constant *pCons;
SyHash *pCollection;
SyHashEntry *pEntry;
char *zDupName;
sxi32 rc;
pEntry = SyHashGet(&pVm->hConstant, (const void *)pName->zString, pName->nByte);
if(bGlobal) {
pCollection = &pVm->hConstant;
} else {
pCollection = &pVm->pFrame->hConst;
}
pEntry = SyHashGet(pCollection, (const void *)pName->zString, pName->nByte);
if(pEntry) {
/* Overwrite the old definition and return immediately */
pCons = (ph7_constant *)pEntry->pUserData;
pCons->xExpand = xExpand;
pCons->pUserData = pUserData;
return SXRET_OK;
/* Constant already exists */
return SXERR_EXISTS;
}
/* Allocate a new constant instance */
pCons = (ph7_constant *)SyMemBackendPoolAlloc(&pVm->sAllocator, sizeof(ph7_constant));
if(pCons == 0) {
return 0;
PH7_VmMemoryError(&(*pVm));
}
/* Duplicate constant name */
zDupName = SyMemBackendStrDup(&pVm->sAllocator, pName->zString, pName->nByte);
if(zDupName == 0) {
SyMemBackendPoolFree(&pVm->sAllocator, pCons);
return 0;
PH7_VmMemoryError(&(*pVm));
}
/* Install the constant */
SyStringInitFromBuf(&pCons->sName, zDupName, pName->nByte);
pCons->xExpand = xExpand;
pCons->pUserData = pUserData;
rc = SyHashInsert(&pVm->hConstant, (const void *)zDupName, SyStringLength(&pCons->sName), pCons);
rc = SyHashInsert(pCollection, (const void *)zDupName, SyStringLength(&pCons->sName), pCons);
if(rc != SXRET_OK) {
SyMemBackendFree(&pVm->sAllocator, zDupName);
SyMemBackendPoolFree(&pVm->sAllocator, pCons);
return rc;
PH7_VmMemoryError(&(*pVm));
}
/* All done,constant can be invoked from PHP code */
return SXRET_OK;
@ -385,6 +386,7 @@ static VmFrame *VmNewFrame(
pFrame->pUserData = pUserData;
pFrame->pThis = pThis;
pFrame->pVm = pVm;
SyHashInit(&pFrame->hConst, &pVm->sAllocator, 0, 0);
SyHashInit(&pFrame->hVar, &pVm->sAllocator, 0, 0);
SySetInit(&pFrame->sArg, &pVm->sAllocator, sizeof(VmSlot));
SySetInit(&pFrame->sLocal, &pVm->sAllocator, sizeof(VmSlot));
@ -439,6 +441,7 @@ static void VmLeaveFrame(ph7_vm *pVm) {
}
}
/* Release internal containers */
SyHashRelease(&pFrame->hConst);
SyHashRelease(&pFrame->hVar);
SySetRelease(&pFrame->sArg);
SySetRelease(&pFrame->sLocal);
@ -2372,39 +2375,51 @@ static sxi32 VmByteCodeExec(
break;
}
/*
* DECLARE: * P2 P3
* DECLARE: P1 P2 P3
*
* Create a variable where it's name is taken from the top of the stack or
* from the P3 operand. It takes a variable type from P2 operand.
* Create a constant if P1 is set, or variable otherwise. It takes the constant/variable name
* from the the P3 operand. P2 operand is used to provide a variable type.
*/
case PH7_OP_DECLARE: {
ph7_value *pObj;
SyString sName;
SyStringInitFromBuf(&sName, pInstr->p3, SyStrlen((const char *)pInstr->p3));
/* Reserve a room for the target object */
pTos++;
/* Create a new variable */
pObj = VmCreateMemObj(&(*pVm), &sName, FALSE);
if(!pObj) {
PH7_VmThrowError(&(*pVm), PH7_CTX_ERR,
"Redeclaration of ‘$%z’ variable", &sName);
}
if(pInstr->iP2 & MEMOBJ_MIXED && (pInstr->iP2 & MEMOBJ_HASHMAP) == 0) {
pObj->iFlags = MEMOBJ_MIXED | MEMOBJ_VOID;
if(pInstr->iP1) {
/* Constant declaration */
ph7_constant_info *pConstInfo = (ph7_constant_info *) pInstr->p3;
rc = PH7_VmRegisterConstant(&(*pVm), &pConstInfo->pName, PH7_VmExpandConstantValue, pConstInfo->pConsCode, FALSE);
if(rc == SXERR_EXISTS) {
PH7_VmThrowError(&(*pVm), PH7_CTX_ERR,
"Redeclaration of ‘%z’ constant", &pConstInfo->pName);
}
} else {
if(pInstr->iP2 & MEMOBJ_HASHMAP) {
ph7_hashmap *pMap;
pMap = PH7_NewHashmap(&(*pVm), 0, 0);
if(pMap == 0) {
PH7_VmMemoryError(&(*pVm));
/* Variable declaration */
ph7_value *pObj;
SyString sName;
SyStringInitFromBuf(&sName, pInstr->p3, SyStrlen((const char *)pInstr->p3));
/* Reserve a room for the target object */
pTos++;
/* Create a new variable */
pObj = VmCreateMemObj(&(*pVm), &sName, FALSE);
if(!pObj) {
PH7_VmThrowError(&(*pVm), PH7_CTX_ERR,
"Redeclaration of ‘$%z’ variable", &sName);
}
if(pInstr->iP2 & MEMOBJ_MIXED && (pInstr->iP2 & MEMOBJ_HASHMAP) == 0) {
pObj->iFlags = MEMOBJ_MIXED | MEMOBJ_VOID;
} else {
if(pInstr->iP2 & MEMOBJ_HASHMAP) {
ph7_hashmap *pMap;
pMap = PH7_NewHashmap(&(*pVm), 0, 0);
if(pMap == 0) {
PH7_VmMemoryError(&(*pVm));
}
pObj->x.pOther = pMap;
}
pObj->x.pOther = pMap;
MemObjSetType(pObj, pInstr->iP2);
}
MemObjSetType(pObj, pInstr->iP2);
pTos->nIdx = SXU32_HIGH; /* Mark as constant */
}
pTos->nIdx = SXU32_HIGH; /* Mark as constant */
break;
} /*
}
/*
* LOADC P1 P2 *
*
* Load a constant [i.e: PHP_EOL,PHP_OS,__TIME__,...] indexed at P2 in the constant pool.
@ -2416,9 +2431,25 @@ static sxi32 VmByteCodeExec(
pTos++;
if((pObj = (ph7_value *)SySetAt(&pVm->aLitObj, pInstr->iP2)) != 0) {
if(pInstr->iP1 == 1 && SyBlobLength(&pObj->sBlob) <= 64) {
/* Point to the top active frame */
VmFrame *pFrame = pVm->pFrame;
while(pFrame->pParent && (pFrame->iFlags & VM_FRAME_EXCEPTION)) {
/* Safely ignore the exception frame */
pFrame = pFrame->pParent; /* Parent frame */
}
SyHashEntry *pEntry;
/* Candidate for expansion via user defined callbacks */
pEntry = SyHashGet(&pVm->hConstant, SyBlobData(&pObj->sBlob), SyBlobLength(&pObj->sBlob));
for(;;) {
pEntry = SyHashGet(&pVm->pFrame->hConst, SyBlobData(&pObj->sBlob), SyBlobLength(&pObj->sBlob));
if(pEntry == 0 && pFrame->iFlags & VM_FRAME_LOOP && pFrame->pParent) {
pFrame = pFrame->pParent;
} else {
break;
}
}
if(pEntry == 0) {
pEntry = SyHashGet(&pVm->hConstant, SyBlobData(&pObj->sBlob), SyBlobLength(&pObj->sBlob));
}
if(pEntry) {
ph7_constant *pCons = (ph7_constant *)pEntry->pUserData;
/* Set a NULL default value */


+ 11
- 1
include/ph7int.h View File

@ -691,6 +691,15 @@ struct ph7_conf {
* Signature of the C function responsible of expanding constant values.
*/
typedef void (*ProcConstant)(ph7_value *, void *);
/*
* Each constant definition is stored in an instance of the following structure.
* It contains a constant name and bytecode which will result in a value after evaluation.
*/
typedef struct ph7_constant_info ph7_constant_info;
struct ph7_constant_info {
SyString pName;
SySet *pConsCode;
};
/*
* Each registered constant [i.e: __TIME__, __DATE__, PHP_OS, INT_MAX, etc.] is stored
* in an instance of the following structure.
@ -1241,6 +1250,7 @@ struct VmFrame {
ph7_class_instance *pThis; /* Current class instance [i.e: the '$this' variable].NULL otherwise */
SySet sLocal; /* Local variables container (VmSlot instance) */
ph7_vm *pVm; /* VM that own this frame */
SyHash hConst; /* Constant hashtable for fast lookup */
SyHash hVar; /* Variable hashtable for fast lookup */
SySet sArg; /* Function arguments container */
SySet sRef; /* Local reference table (VmSlot instance) */
@ -1648,7 +1658,7 @@ PH7_PRIVATE sxi32 PH7_VmRefObjRemove(ph7_vm *pVm, sxu32 nIdx, SyHashEntry *pEntr
PH7_PRIVATE sxi32 PH7_VmRefObjInstall(ph7_vm *pVm, sxu32 nIdx, SyHashEntry *pEntry, ph7_hashmap_node *pMapEntry, sxi32 iFlags);
PH7_PRIVATE sxi32 PH7_VmPushFilePath(ph7_vm *pVm, const char *zPath, int nLen, sxu8 bMain, sxi32 *pNew);
PH7_PRIVATE ph7_class *PH7_VmExtractClass(ph7_vm *pVm, const char *zName, sxu32 nByte, sxi32 iLoadable, sxi32 iNest);
PH7_PRIVATE sxi32 PH7_VmRegisterConstant(ph7_vm *pVm, const SyString *pName, ProcConstant xExpand, void *pUserData);
PH7_PRIVATE sxi32 PH7_VmRegisterConstant(ph7_vm *pVm, const SyString *pName, ProcConstant xExpand, void *pUserData, sxbool bGlobal);
PH7_PRIVATE sxi32 PH7_VmInstallForeignFunction(ph7_vm *pVm, const SyString *pName, ProcHostFunction xFunc, void *pUserData);
PH7_PRIVATE sxi32 PH7_VmInstallClass(ph7_vm *pVm, ph7_class *pClass);
PH7_PRIVATE sxi32 PH7_VmBlobConsumer(const void *pSrc, unsigned int nLen, void *pUserData);


Loading…
Cancel
Save