Make constant declarations local.
Todas las comprobaciones han sido exitosas
The build was successful.
Todas las comprobaciones han sido exitosas
The build was successful.
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.
Este commit está contenido en:
@@ -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 */
|
||||
|
@@ -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;
|
||||
}
|
||||
/*
|
||||
|
115
engine/vm.c
115
engine/vm.c
@@ -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;
|
||||
} 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;
|
||||
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);
|
||||
}
|
||||
MemObjSetType(pObj, pInstr->iP2);
|
||||
} else {
|
||||
/* 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;
|
||||
}
|
||||
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 */
|
||||
|
@@ -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);
|
||||
|
Referencia en una nueva incidencia
Block a user