Get rid of dirty references. Return a reference & pass-by reference are still working.
	
		
			
	
		
	
	
		
	
		
			All checks were successful
		
		
	
	
		
			
				
	
				 The build was successful.
				
			
		
		
	
	
				
					
				
			
		
			All checks were successful
		
		
	
	 The build was successful.
				
			This commit is contained in:
		@@ -794,7 +794,6 @@ static sxi32 PH7_GenStateArrayNodeValidator(ph7_gen_state *pGen, ph7_expr_node *
 | 
				
			|||||||
PH7_PRIVATE sxi32 PH7_CompileArray(ph7_gen_state *pGen, sxi32 iCompileFlag) {
 | 
					PH7_PRIVATE sxi32 PH7_CompileArray(ph7_gen_state *pGen, sxi32 iCompileFlag) {
 | 
				
			||||||
	sxi32(*xValidator)(ph7_gen_state *, ph7_expr_node *); /* Expression tree validator callback */
 | 
						sxi32(*xValidator)(ph7_gen_state *, ph7_expr_node *); /* Expression tree validator callback */
 | 
				
			||||||
	SyToken *pKey, *pCur;
 | 
						SyToken *pKey, *pCur;
 | 
				
			||||||
	sxi32 iEmitRef = 0;
 | 
					 | 
				
			||||||
	sxi32 nPair = 0;
 | 
						sxi32 nPair = 0;
 | 
				
			||||||
	sxi32 iNest;
 | 
						sxi32 iNest;
 | 
				
			||||||
	sxi32 rc;
 | 
						sxi32 rc;
 | 
				
			||||||
@@ -862,31 +861,12 @@ PH7_PRIVATE sxi32 PH7_CompileArray(ph7_gen_state *pGen, sxi32 iCompileFlag) {
 | 
				
			|||||||
			/* No available key,load NULL */
 | 
								/* No available key,load NULL */
 | 
				
			||||||
			PH7_VmEmitInstr(pGen->pVm, 0, PH7_OP_LOADC, 0, 0 /* nil index */, 0, 0);
 | 
								PH7_VmEmitInstr(pGen->pVm, 0, PH7_OP_LOADC, 0, 0 /* nil index */, 0, 0);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if(pCur->nType & PH7_TK_AMPER /*'&'*/) {
 | 
					 | 
				
			||||||
			/* Insertion by reference, [i.e: $a = array(&$x);] */
 | 
					 | 
				
			||||||
			xValidator = PH7_GenStateArrayNodeValidator; /* Only variable are allowed */
 | 
					 | 
				
			||||||
			iEmitRef = 1;
 | 
					 | 
				
			||||||
			pCur++; /* Jump the '&' token */
 | 
					 | 
				
			||||||
			if(pCur >= pGen->pIn) {
 | 
					 | 
				
			||||||
				/* Missing value */
 | 
					 | 
				
			||||||
				rc = PH7_GenCompileError(&(*pGen), E_ERROR, pCur->nLine, "array(): Missing referenced variable");
 | 
					 | 
				
			||||||
				if(rc == SXERR_ABORT) {
 | 
					 | 
				
			||||||
					return SXERR_ABORT;
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				return SXRET_OK;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		/* Compile indice value */
 | 
							/* Compile indice value */
 | 
				
			||||||
		rc = PH7_GenStateCompileArrayEntry(&(*pGen), pCur, pGen->pIn, EXPR_FLAG_RDONLY_LOAD/*Do not create the variable if non-existent*/, xValidator);
 | 
							rc = PH7_GenStateCompileArrayEntry(&(*pGen), pCur, pGen->pIn, EXPR_FLAG_RDONLY_LOAD/*Do not create the variable if non-existent*/, xValidator);
 | 
				
			||||||
		if(rc == SXERR_ABORT) {
 | 
							if(rc == SXERR_ABORT) {
 | 
				
			||||||
			return SXERR_ABORT;
 | 
								return SXERR_ABORT;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if(iEmitRef) {
 | 
					 | 
				
			||||||
			/* Emit the load reference instruction */
 | 
					 | 
				
			||||||
			PH7_VmEmitInstr(pGen->pVm, 0, PH7_OP_LOAD_REF, 0, 0, 0, 0);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		xValidator = 0;
 | 
							xValidator = 0;
 | 
				
			||||||
		iEmitRef = 0;
 | 
					 | 
				
			||||||
		nPair++;
 | 
							nPair++;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	/* Emit the load map instruction */
 | 
						/* Emit the load map instruction */
 | 
				
			||||||
@@ -5073,21 +5053,6 @@ static sxi32 PH7_GenStateEmitExprCode(
 | 
				
			|||||||
					(void)PH7_VmPopInstr(pGen->pVm);
 | 
										(void)PH7_VmPopInstr(pGen->pVm);
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		} else if(iVmOp == PH7_OP_STORE_REF) {
 | 
					 | 
				
			||||||
			pInstr = PH7_VmPopInstr(pGen->pVm);
 | 
					 | 
				
			||||||
			if(pInstr) {
 | 
					 | 
				
			||||||
				if(pInstr->iOp == PH7_OP_LOAD_IDX) {
 | 
					 | 
				
			||||||
					/* Array insertion by reference [i.e: $pArray[] =& $some_var; ]
 | 
					 | 
				
			||||||
					 * We have to convert the STORE_REF instruction into STORE_IDX_REF
 | 
					 | 
				
			||||||
					 */
 | 
					 | 
				
			||||||
					iVmOp = PH7_OP_STORE_IDX_REF;
 | 
					 | 
				
			||||||
					iP1 = pInstr->iP1;
 | 
					 | 
				
			||||||
					iP2 = pInstr->iP2;
 | 
					 | 
				
			||||||
					p3  = pInstr->p3;
 | 
					 | 
				
			||||||
				} else {
 | 
					 | 
				
			||||||
					p3 = pInstr->p3;
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if(iVmOp > 0) {
 | 
						if(iVmOp > 0) {
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										233
									
								
								engine/hashmap.c
									
									
									
									
									
								
							
							
						
						
									
										233
									
								
								engine/hashmap.c
									
									
									
									
									
								
							@@ -16,10 +16,6 @@
 | 
				
			|||||||
/* Allowed node types */
 | 
					/* Allowed node types */
 | 
				
			||||||
#define HASHMAP_INT_NODE   1  /* Node with an int [i.e: 64-bit integer] key */
 | 
					#define HASHMAP_INT_NODE   1  /* Node with an int [i.e: 64-bit integer] key */
 | 
				
			||||||
#define HASHMAP_BLOB_NODE  2  /* Node with a string/BLOB key */
 | 
					#define HASHMAP_BLOB_NODE  2  /* Node with a string/BLOB key */
 | 
				
			||||||
/* Node control flags */
 | 
					 | 
				
			||||||
#define HASHMAP_NODE_FOREIGN_OBJ 0x001 /* Node hold a reference to a foreign ph7_value
 | 
					 | 
				
			||||||
                                        * [i.e: array(&var)/$a[] =& $var ]
 | 
					 | 
				
			||||||
										*/
 | 
					 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Default hash function for int [i.e; 64-bit integer] keys.
 | 
					 * Default hash function for int [i.e; 64-bit integer] keys.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@@ -193,9 +189,7 @@ PH7_PRIVATE void PH7_HashmapUnlinkNode(ph7_hashmap_node *pNode, int bRestore) {
 | 
				
			|||||||
		/* Remove the ph7_value associated with this node from the reference table */
 | 
							/* Remove the ph7_value associated with this node from the reference table */
 | 
				
			||||||
		PH7_VmRefObjRemove(pVm, pNode->nValIdx, 0, pNode);
 | 
							PH7_VmRefObjRemove(pVm, pNode->nValIdx, 0, pNode);
 | 
				
			||||||
		/* Restore to the freelist */
 | 
							/* Restore to the freelist */
 | 
				
			||||||
		if((pNode->iFlags & HASHMAP_NODE_FOREIGN_OBJ) == 0) {
 | 
							PH7_VmUnsetMemObj(pVm, pNode->nValIdx, FALSE);
 | 
				
			||||||
			PH7_VmUnsetMemObj(pVm, pNode->nValIdx, FALSE);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if(pNode->iType == HASHMAP_BLOB_NODE) {
 | 
						if(pNode->iType == HASHMAP_BLOB_NODE) {
 | 
				
			||||||
		SyBlobRelease(&pNode->xKey.sKey);
 | 
							SyBlobRelease(&pNode->xKey.sKey);
 | 
				
			||||||
@@ -271,26 +265,22 @@ static sxi32 HashmapGrowBucket(ph7_hashmap *pMap) {
 | 
				
			|||||||
 * Insert a 64-bit integer key and it's associated value (if any) in the given
 | 
					 * Insert a 64-bit integer key and it's associated value (if any) in the given
 | 
				
			||||||
 * hashmap.
 | 
					 * hashmap.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static sxi32 HashmapInsertIntKey(ph7_hashmap *pMap, sxi64 iKey, ph7_value *pValue, sxu32 nRefIdx, int isForeign) {
 | 
					static sxi32 HashmapInsertIntKey(ph7_hashmap *pMap, sxi64 iKey, ph7_value *pValue, sxu32 nRefIdx) {
 | 
				
			||||||
	ph7_hashmap_node *pNode;
 | 
						ph7_hashmap_node *pNode;
 | 
				
			||||||
	sxu32 nIdx;
 | 
						sxu32 nIdx;
 | 
				
			||||||
	sxu32 nHash;
 | 
						sxu32 nHash;
 | 
				
			||||||
	sxi32 rc;
 | 
						sxi32 rc;
 | 
				
			||||||
	if(!isForeign) {
 | 
						ph7_value *pObj;
 | 
				
			||||||
		ph7_value *pObj;
 | 
						/* Reserve a ph7_value for the value */
 | 
				
			||||||
		/* Reserve a ph7_value for the value */
 | 
						pObj = PH7_ReserveMemObj(pMap->pVm);
 | 
				
			||||||
		pObj = PH7_ReserveMemObj(pMap->pVm);
 | 
						if(pObj == 0) {
 | 
				
			||||||
		if(pObj == 0) {
 | 
							return SXERR_MEM;
 | 
				
			||||||
			return SXERR_MEM;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if(pValue) {
 | 
					 | 
				
			||||||
			/* Duplicate the value */
 | 
					 | 
				
			||||||
			PH7_MemObjStore(pValue, pObj);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		nIdx = pObj->nIdx;
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		nIdx = nRefIdx;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if(pValue) {
 | 
				
			||||||
 | 
							/* Duplicate the value */
 | 
				
			||||||
 | 
							PH7_MemObjStore(pValue, pObj);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						nIdx = pObj->nIdx;
 | 
				
			||||||
	/* Hash the key */
 | 
						/* Hash the key */
 | 
				
			||||||
	nHash = pMap->xIntHash(iKey);
 | 
						nHash = pMap->xIntHash(iKey);
 | 
				
			||||||
	/* Allocate a new int node */
 | 
						/* Allocate a new int node */
 | 
				
			||||||
@@ -298,10 +288,6 @@ static sxi32 HashmapInsertIntKey(ph7_hashmap *pMap, sxi64 iKey, ph7_value *pValu
 | 
				
			|||||||
	if(pNode == 0) {
 | 
						if(pNode == 0) {
 | 
				
			||||||
		return SXERR_MEM;
 | 
							return SXERR_MEM;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if(isForeign) {
 | 
					 | 
				
			||||||
		/* Mark as a foregin entry */
 | 
					 | 
				
			||||||
		pNode->iFlags |= HASHMAP_NODE_FOREIGN_OBJ;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	/* Make sure the bucket is big enough to hold the new entry */
 | 
						/* Make sure the bucket is big enough to hold the new entry */
 | 
				
			||||||
	rc = HashmapGrowBucket(&(*pMap));
 | 
						rc = HashmapGrowBucket(&(*pMap));
 | 
				
			||||||
	if(rc != SXRET_OK) {
 | 
						if(rc != SXRET_OK) {
 | 
				
			||||||
@@ -319,26 +305,22 @@ static sxi32 HashmapInsertIntKey(ph7_hashmap *pMap, sxi64 iKey, ph7_value *pValu
 | 
				
			|||||||
 * Insert a BLOB key and it's associated value (if any) in the given
 | 
					 * Insert a BLOB key and it's associated value (if any) in the given
 | 
				
			||||||
 * hashmap.
 | 
					 * hashmap.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static sxi32 HashmapInsertBlobKey(ph7_hashmap *pMap, const void *pKey, sxu32 nKeyLen, ph7_value *pValue, sxu32 nRefIdx, int isForeign) {
 | 
					static sxi32 HashmapInsertBlobKey(ph7_hashmap *pMap, const void *pKey, sxu32 nKeyLen, ph7_value *pValue, sxu32 nRefIdx) {
 | 
				
			||||||
	ph7_hashmap_node *pNode;
 | 
						ph7_hashmap_node *pNode;
 | 
				
			||||||
	sxu32 nHash;
 | 
						sxu32 nHash;
 | 
				
			||||||
	sxu32 nIdx;
 | 
						sxu32 nIdx;
 | 
				
			||||||
	sxi32 rc;
 | 
						sxi32 rc;
 | 
				
			||||||
	if(!isForeign) {
 | 
						ph7_value *pObj;
 | 
				
			||||||
		ph7_value *pObj;
 | 
						/* Reserve a ph7_value for the value */
 | 
				
			||||||
		/* Reserve a ph7_value for the value */
 | 
						pObj = PH7_ReserveMemObj(pMap->pVm);
 | 
				
			||||||
		pObj = PH7_ReserveMemObj(pMap->pVm);
 | 
						if(pObj == 0) {
 | 
				
			||||||
		if(pObj == 0) {
 | 
							return SXERR_MEM;
 | 
				
			||||||
			return SXERR_MEM;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if(pValue) {
 | 
					 | 
				
			||||||
			/* Duplicate the value */
 | 
					 | 
				
			||||||
			PH7_MemObjStore(pValue, pObj);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		nIdx = pObj->nIdx;
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		nIdx = nRefIdx;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if(pValue) {
 | 
				
			||||||
 | 
							/* Duplicate the value */
 | 
				
			||||||
 | 
							PH7_MemObjStore(pValue, pObj);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						nIdx = pObj->nIdx;
 | 
				
			||||||
	/* Hash the key */
 | 
						/* Hash the key */
 | 
				
			||||||
	nHash = pMap->xBlobHash(pKey, nKeyLen);
 | 
						nHash = pMap->xBlobHash(pKey, nKeyLen);
 | 
				
			||||||
	/* Allocate a new blob node */
 | 
						/* Allocate a new blob node */
 | 
				
			||||||
@@ -346,10 +328,6 @@ static sxi32 HashmapInsertBlobKey(ph7_hashmap *pMap, const void *pKey, sxu32 nKe
 | 
				
			|||||||
	if(pNode == 0) {
 | 
						if(pNode == 0) {
 | 
				
			||||||
		return SXERR_MEM;
 | 
							return SXERR_MEM;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if(isForeign) {
 | 
					 | 
				
			||||||
		/* Mark as a foregin entry */
 | 
					 | 
				
			||||||
		pNode->iFlags |= HASHMAP_NODE_FOREIGN_OBJ;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	/* Make sure the bucket is big enough to hold the new entry */
 | 
						/* Make sure the bucket is big enough to hold the new entry */
 | 
				
			||||||
	rc = HashmapGrowBucket(&(*pMap));
 | 
						rc = HashmapGrowBucket(&(*pMap));
 | 
				
			||||||
	if(rc != SXRET_OK) {
 | 
						if(rc != SXRET_OK) {
 | 
				
			||||||
@@ -553,7 +531,7 @@ static sxi32 HashmapInsert(
 | 
				
			|||||||
			return SXRET_OK;
 | 
								return SXRET_OK;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		/* Perform a blob-key insertion */
 | 
							/* Perform a blob-key insertion */
 | 
				
			||||||
		rc = HashmapInsertBlobKey(&(*pMap), SyBlobData(&pKey->sBlob), SyBlobLength(&pKey->sBlob), &(*pVal), 0, FALSE);
 | 
							rc = HashmapInsertBlobKey(&(*pMap), SyBlobData(&pKey->sBlob), SyBlobLength(&pKey->sBlob), &(*pVal), 0);
 | 
				
			||||||
		return rc;
 | 
							return rc;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
IntKey:
 | 
					IntKey:
 | 
				
			||||||
@@ -577,7 +555,7 @@ IntKey:
 | 
				
			|||||||
			return SXRET_OK;
 | 
								return SXRET_OK;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		/* Perform a 64-bit-int-key insertion */
 | 
							/* Perform a 64-bit-int-key insertion */
 | 
				
			||||||
		rc = HashmapInsertIntKey(&(*pMap), pKey->x.iVal, &(*pVal), 0, FALSE);
 | 
							rc = HashmapInsertIntKey(&(*pMap), pKey->x.iVal, &(*pVal), 0);
 | 
				
			||||||
		if(rc == SXRET_OK) {
 | 
							if(rc == SXRET_OK) {
 | 
				
			||||||
			if(pKey->x.iVal >= pMap->iNextIdx) {
 | 
								if(pKey->x.iVal >= pMap->iNextIdx) {
 | 
				
			||||||
				/* Increment the automatic index */
 | 
									/* Increment the automatic index */
 | 
				
			||||||
@@ -590,102 +568,7 @@ IntKey:
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		/* Assign an automatic index */
 | 
							/* Assign an automatic index */
 | 
				
			||||||
		rc = HashmapInsertIntKey(&(*pMap), pMap->iNextIdx, &(*pVal), 0, FALSE);
 | 
							rc = HashmapInsertIntKey(&(*pMap), pMap->iNextIdx, &(*pVal), 0);
 | 
				
			||||||
		if(rc == SXRET_OK) {
 | 
					 | 
				
			||||||
			++pMap->iNextIdx;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	/* Insertion result */
 | 
					 | 
				
			||||||
	return rc;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * Insert a given key and it's associated value (foreign index) in the given
 | 
					 | 
				
			||||||
 * hashmap.
 | 
					 | 
				
			||||||
 * This is insertion by reference so be careful to mark the node
 | 
					 | 
				
			||||||
 * with the HASHMAP_NODE_FOREIGN_OBJ flag being set.
 | 
					 | 
				
			||||||
 * The insertion by reference is triggered when the following
 | 
					 | 
				
			||||||
 * expression is encountered.
 | 
					 | 
				
			||||||
 * $var = 10;
 | 
					 | 
				
			||||||
 *  $a = array(&var);
 | 
					 | 
				
			||||||
 * OR
 | 
					 | 
				
			||||||
 *  $a[] =& $var;
 | 
					 | 
				
			||||||
 * That is,$var is a foreign ph7_value and the $a array have no control
 | 
					 | 
				
			||||||
 * over it's contents.
 | 
					 | 
				
			||||||
 * Note that the node that hold the foreign ph7_value is automatically
 | 
					 | 
				
			||||||
 * removed when the foreign ph7_value is unset.
 | 
					 | 
				
			||||||
 * Example:
 | 
					 | 
				
			||||||
 *  $var = 10;
 | 
					 | 
				
			||||||
 *  $a[] =& $var;
 | 
					 | 
				
			||||||
 *  echo count($a).PHP_EOL; //1
 | 
					 | 
				
			||||||
 *  //Unset the foreign ph7_value now
 | 
					 | 
				
			||||||
 *  unset($var);
 | 
					 | 
				
			||||||
 *  echo count($a); //0
 | 
					 | 
				
			||||||
 * Note that this is a PH7 eXtension.
 | 
					 | 
				
			||||||
 * Refer to the official documentation for more information.
 | 
					 | 
				
			||||||
 * If a node with the given key already exists in the database
 | 
					 | 
				
			||||||
 * then this function overwrite the old value.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
static sxi32 HashmapInsertByRef(
 | 
					 | 
				
			||||||
	ph7_hashmap *pMap,   /* Target hashmap */
 | 
					 | 
				
			||||||
	ph7_value *pKey,     /* Lookup key */
 | 
					 | 
				
			||||||
	sxu32 nRefIdx        /* Foreign ph7_value index */
 | 
					 | 
				
			||||||
) {
 | 
					 | 
				
			||||||
	ph7_hashmap_node *pNode = 0;
 | 
					 | 
				
			||||||
	sxi32 rc = SXRET_OK;
 | 
					 | 
				
			||||||
	if(pKey && pKey->iFlags & (MEMOBJ_STRING | MEMOBJ_HASHMAP | MEMOBJ_OBJ | MEMOBJ_RES)) {
 | 
					 | 
				
			||||||
		if((pKey->iFlags & MEMOBJ_STRING) == 0) {
 | 
					 | 
				
			||||||
			/* Force a string cast */
 | 
					 | 
				
			||||||
			PH7_MemObjToString(&(*pKey));
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if(SyBlobLength(&pKey->sBlob) < 1 || HashmapIsIntKey(&pKey->sBlob)) {
 | 
					 | 
				
			||||||
			if(SyBlobLength(&pKey->sBlob) < 1) {
 | 
					 | 
				
			||||||
				/* Automatic index assign */
 | 
					 | 
				
			||||||
				pKey = 0;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			goto IntKey;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if(SXRET_OK == HashmapLookupBlobKey(&(*pMap), SyBlobData(&pKey->sBlob),
 | 
					 | 
				
			||||||
											SyBlobLength(&pKey->sBlob), &pNode)) {
 | 
					 | 
				
			||||||
			/* Overwrite */
 | 
					 | 
				
			||||||
			PH7_VmRefObjRemove(pMap->pVm, pNode->nValIdx, 0, pNode);
 | 
					 | 
				
			||||||
			pNode->nValIdx = nRefIdx;
 | 
					 | 
				
			||||||
			/* Install in the reference table */
 | 
					 | 
				
			||||||
			PH7_VmRefObjInstall(pMap->pVm, nRefIdx, 0, pNode, 0);
 | 
					 | 
				
			||||||
			return SXRET_OK;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		/* Perform a blob-key insertion */
 | 
					 | 
				
			||||||
		rc = HashmapInsertBlobKey(&(*pMap), SyBlobData(&pKey->sBlob), SyBlobLength(&pKey->sBlob), 0, nRefIdx, TRUE);
 | 
					 | 
				
			||||||
		return rc;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
IntKey:
 | 
					 | 
				
			||||||
	if(pKey) {
 | 
					 | 
				
			||||||
		if((pKey->iFlags & MEMOBJ_INT) == 0) {
 | 
					 | 
				
			||||||
			/* Force an integer cast */
 | 
					 | 
				
			||||||
			PH7_MemObjToInteger(pKey);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if(SXRET_OK == HashmapLookupIntKey(&(*pMap), pKey->x.iVal, &pNode)) {
 | 
					 | 
				
			||||||
			/* Overwrite */
 | 
					 | 
				
			||||||
			PH7_VmRefObjRemove(pMap->pVm, pNode->nValIdx, 0, pNode);
 | 
					 | 
				
			||||||
			pNode->nValIdx = nRefIdx;
 | 
					 | 
				
			||||||
			/* Install in the reference table */
 | 
					 | 
				
			||||||
			PH7_VmRefObjInstall(pMap->pVm, nRefIdx, 0, pNode, 0);
 | 
					 | 
				
			||||||
			return SXRET_OK;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		/* Perform a 64-bit-int-key insertion */
 | 
					 | 
				
			||||||
		rc = HashmapInsertIntKey(&(*pMap), pKey->x.iVal, 0, nRefIdx, TRUE);
 | 
					 | 
				
			||||||
		if(rc == SXRET_OK) {
 | 
					 | 
				
			||||||
			if(pKey->x.iVal >= pMap->iNextIdx) {
 | 
					 | 
				
			||||||
				/* Increment the automatic index */
 | 
					 | 
				
			||||||
				pMap->iNextIdx = pKey->x.iVal + 1;
 | 
					 | 
				
			||||||
				/* Make sure the automatic index is not reserved */
 | 
					 | 
				
			||||||
				while(SXRET_OK == HashmapLookupIntKey(&(*pMap), pMap->iNextIdx, 0)) {
 | 
					 | 
				
			||||||
					pMap->iNextIdx++;
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		/* Assign an automatic index */
 | 
					 | 
				
			||||||
		rc = HashmapInsertIntKey(&(*pMap), pMap->iNextIdx, 0, nRefIdx, TRUE);
 | 
					 | 
				
			||||||
		if(rc == SXRET_OK) {
 | 
							if(rc == SXRET_OK) {
 | 
				
			||||||
			++pMap->iNextIdx;
 | 
								++pMap->iNextIdx;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -693,6 +576,7 @@ IntKey:
 | 
				
			|||||||
	/* Insertion result */
 | 
						/* Insertion result */
 | 
				
			||||||
	return rc;
 | 
						return rc;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Extract node value.
 | 
					 * Extract node value.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@@ -722,12 +606,12 @@ static sxi32 HashmapInsertNode(ph7_hashmap *pMap, ph7_hashmap_node *pNode, int b
 | 
				
			|||||||
			/* Assign an automatic index */
 | 
								/* Assign an automatic index */
 | 
				
			||||||
			rc = HashmapInsert(&(*pMap), 0, pObj);
 | 
								rc = HashmapInsert(&(*pMap), 0, pObj);
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			rc = HashmapInsertIntKey(&(*pMap), pNode->xKey.iKey, pObj, 0, FALSE);
 | 
								rc = HashmapInsertIntKey(&(*pMap), pNode->xKey.iKey, pObj, 0);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		/* Blob key */
 | 
							/* Blob key */
 | 
				
			||||||
		rc = HashmapInsertBlobKey(&(*pMap), SyBlobData(&pNode->xKey.sKey),
 | 
							rc = HashmapInsertBlobKey(&(*pMap), SyBlobData(&pNode->xKey.sKey),
 | 
				
			||||||
								  SyBlobLength(&pNode->xKey.sKey), pObj, 0, FALSE);
 | 
													  SyBlobLength(&pNode->xKey.sKey), pObj, 0);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return rc;
 | 
						return rc;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -821,8 +705,8 @@ static int HashmapFindValue(
 | 
				
			|||||||
		pVal = HashmapExtractNodeValue(pEntry);
 | 
							pVal = HashmapExtractNodeValue(pEntry);
 | 
				
			||||||
		if(pVal) {
 | 
							if(pVal) {
 | 
				
			||||||
			if((pVal->iFlags | pNeedle->iFlags) & MEMOBJ_NULL) {
 | 
								if((pVal->iFlags | pNeedle->iFlags) & MEMOBJ_NULL) {
 | 
				
			||||||
				sxi32 iF1 = pVal->iFlags & ~MEMOBJ_AUX;
 | 
									sxi32 iF1 = pVal->iFlags;
 | 
				
			||||||
				sxi32 iF2 = pNeedle->iFlags & ~MEMOBJ_AUX;
 | 
									sxi32 iF2 = pNeedle->iFlags;
 | 
				
			||||||
				if(iF1 == iF2) {
 | 
									if(iF1 == iF2) {
 | 
				
			||||||
					/* NULL values are equals */
 | 
										/* NULL values are equals */
 | 
				
			||||||
					if(ppNode) {
 | 
										if(ppNode) {
 | 
				
			||||||
@@ -1144,7 +1028,7 @@ PH7_PRIVATE sxi32 PH7_HashmapDup(ph7_hashmap *pSrc, ph7_hashmap *pDest) {
 | 
				
			|||||||
			PH7_MemObjRelease(&sKey);
 | 
								PH7_MemObjRelease(&sKey);
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			/* Int key insertion */
 | 
								/* Int key insertion */
 | 
				
			||||||
			rc = HashmapInsertIntKey(&(*pDest), pEntry->xKey.iKey, pVal, 0, FALSE);
 | 
								rc = HashmapInsertIntKey(&(*pDest), pEntry->xKey.iKey, pVal, 0);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if(rc != SXRET_OK) {
 | 
							if(rc != SXRET_OK) {
 | 
				
			||||||
			return rc;
 | 
								return rc;
 | 
				
			||||||
@@ -1214,7 +1098,7 @@ PH7_PRIVATE sxi32 PH7_HashmapUnion(ph7_hashmap *pLeft, ph7_hashmap *pRight) {
 | 
				
			|||||||
				if(pObj) {
 | 
									if(pObj) {
 | 
				
			||||||
					/* Perform the insertion */
 | 
										/* Perform the insertion */
 | 
				
			||||||
					rc = HashmapInsertBlobKey(&(*pLeft), SyBlobData(&pEntry->xKey.sKey), SyBlobLength(&pEntry->xKey.sKey),
 | 
										rc = HashmapInsertBlobKey(&(*pLeft), SyBlobData(&pEntry->xKey.sKey), SyBlobLength(&pEntry->xKey.sKey),
 | 
				
			||||||
											  pObj, 0, FALSE);
 | 
																  pObj, 0);
 | 
				
			||||||
					if(rc != SXRET_OK) {
 | 
										if(rc != SXRET_OK) {
 | 
				
			||||||
						return rc;
 | 
											return rc;
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
@@ -1226,7 +1110,7 @@ PH7_PRIVATE sxi32 PH7_HashmapUnion(ph7_hashmap *pLeft, ph7_hashmap *pRight) {
 | 
				
			|||||||
				pObj = HashmapExtractNodeValue(pEntry);
 | 
									pObj = HashmapExtractNodeValue(pEntry);
 | 
				
			||||||
				if(pObj) {
 | 
									if(pObj) {
 | 
				
			||||||
					/* Perform the insertion */
 | 
										/* Perform the insertion */
 | 
				
			||||||
					rc = HashmapInsertIntKey(&(*pLeft), pEntry->xKey.iKey, pObj, 0, FALSE);
 | 
										rc = HashmapInsertIntKey(&(*pLeft), pEntry->xKey.iKey, pObj, 0);
 | 
				
			||||||
					if(rc != SXRET_OK) {
 | 
										if(rc != SXRET_OK) {
 | 
				
			||||||
						return rc;
 | 
											return rc;
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
@@ -1345,10 +1229,8 @@ PH7_PRIVATE sxi32 PH7_HashmapRelease(ph7_hashmap *pMap, int FreeDS) {
 | 
				
			|||||||
		pNext = pEntry->pPrev; /* Reverse link */
 | 
							pNext = pEntry->pPrev; /* Reverse link */
 | 
				
			||||||
		/* Remove the reference from the foreign table */
 | 
							/* Remove the reference from the foreign table */
 | 
				
			||||||
		PH7_VmRefObjRemove(pVm, pEntry->nValIdx, 0, pEntry);
 | 
							PH7_VmRefObjRemove(pVm, pEntry->nValIdx, 0, pEntry);
 | 
				
			||||||
		if((pEntry->iFlags & HASHMAP_NODE_FOREIGN_OBJ) == 0) {
 | 
							/* Restore the ph7_value to the free list */
 | 
				
			||||||
			/* Restore the ph7_value to the free list */
 | 
							PH7_VmUnsetMemObj(pVm, pEntry->nValIdx, FALSE);
 | 
				
			||||||
			PH7_VmUnsetMemObj(pVm, pEntry->nValIdx, FALSE);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		/* Release the node */
 | 
							/* Release the node */
 | 
				
			||||||
		if(pEntry->iType == HASHMAP_BLOB_NODE) {
 | 
							if(pEntry->iType == HASHMAP_BLOB_NODE) {
 | 
				
			||||||
			SyBlobRelease(&pEntry->xKey.sKey);
 | 
								SyBlobRelease(&pEntry->xKey.sKey);
 | 
				
			||||||
@@ -1419,40 +1301,7 @@ PH7_PRIVATE sxi32 PH7_HashmapInsert(
 | 
				
			|||||||
) {
 | 
					) {
 | 
				
			||||||
	return HashmapInsert(&(*pMap), &(*pKey), &(*pVal));
 | 
						return HashmapInsert(&(*pMap), &(*pKey), &(*pVal));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
/*
 | 
					
 | 
				
			||||||
 * Insert a given key and it's associated value (foreign index) in the given
 | 
					 | 
				
			||||||
 * hashmap.
 | 
					 | 
				
			||||||
 * This is insertion by reference so be careful to mark the node
 | 
					 | 
				
			||||||
 * with the HASHMAP_NODE_FOREIGN_OBJ flag being set.
 | 
					 | 
				
			||||||
 * The insertion by reference is triggered when the following
 | 
					 | 
				
			||||||
 * expression is encountered.
 | 
					 | 
				
			||||||
 * $var = 10;
 | 
					 | 
				
			||||||
 *  $a = array(&var);
 | 
					 | 
				
			||||||
 * OR
 | 
					 | 
				
			||||||
 *  $a[] =& $var;
 | 
					 | 
				
			||||||
 * That is,$var is a foreign ph7_value and the $a array have no control
 | 
					 | 
				
			||||||
 * over it's contents.
 | 
					 | 
				
			||||||
 * Note that the node that hold the foreign ph7_value is automatically
 | 
					 | 
				
			||||||
 * removed when the foreign ph7_value is unset.
 | 
					 | 
				
			||||||
 * Example:
 | 
					 | 
				
			||||||
 *  $var = 10;
 | 
					 | 
				
			||||||
 *  $a[] =& $var;
 | 
					 | 
				
			||||||
 *  echo count($a).PHP_EOL; //1
 | 
					 | 
				
			||||||
 *  //Unset the foreign ph7_value now
 | 
					 | 
				
			||||||
 *  unset($var);
 | 
					 | 
				
			||||||
 *  echo count($a); //0
 | 
					 | 
				
			||||||
 * Note that this is a PH7 eXtension.
 | 
					 | 
				
			||||||
 * Refer to the official documentation for more information.
 | 
					 | 
				
			||||||
 * If a node with the given key already exists in the database
 | 
					 | 
				
			||||||
 * then this function overwrite the old value.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
PH7_PRIVATE sxi32 PH7_HashmapInsertByRef(
 | 
					 | 
				
			||||||
	ph7_hashmap *pMap, /* Target hashmap */
 | 
					 | 
				
			||||||
	ph7_value *pKey,   /* Lookup key */
 | 
					 | 
				
			||||||
	sxu32 nRefIdx      /* Foreign ph7_value index */
 | 
					 | 
				
			||||||
) {
 | 
					 | 
				
			||||||
	return HashmapInsertByRef(&(*pMap), &(*pKey), nRefIdx);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Reset the node cursor of a given hashmap.
 | 
					 * Reset the node cursor of a given hashmap.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@@ -5500,7 +5349,6 @@ PH7_PRIVATE sxi32 PH7_HashmapDump(SyBlob *pOut, ph7_hashmap *pMap, int ShowType,
 | 
				
			|||||||
	ph7_hashmap_node *pEntry;
 | 
						ph7_hashmap_node *pEntry;
 | 
				
			||||||
	ph7_value *pObj;
 | 
						ph7_value *pObj;
 | 
				
			||||||
	sxu32 n = 0;
 | 
						sxu32 n = 0;
 | 
				
			||||||
	int isRef;
 | 
					 | 
				
			||||||
	sxi32 rc;
 | 
						sxi32 rc;
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
	if(nDepth > 31) {
 | 
						if(nDepth > 31) {
 | 
				
			||||||
@@ -5547,13 +5395,8 @@ PH7_PRIVATE sxi32 PH7_HashmapDump(SyBlob *pOut, ph7_hashmap *pMap, int ShowType,
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
			/* Dump node value */
 | 
								/* Dump node value */
 | 
				
			||||||
			pObj = HashmapExtractNodeValue(pEntry);
 | 
								pObj = HashmapExtractNodeValue(pEntry);
 | 
				
			||||||
			isRef = 0;
 | 
					 | 
				
			||||||
			if(pObj) {
 | 
								if(pObj) {
 | 
				
			||||||
				if(pEntry->iFlags & HASHMAP_NODE_FOREIGN_OBJ) {
 | 
									rc = PH7_MemObjDump(&(*pOut), pObj, ShowType, nTab + 1, nDepth);
 | 
				
			||||||
					/* Referenced object */
 | 
					 | 
				
			||||||
					isRef = 1;
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				rc = PH7_MemObjDump(&(*pOut), pObj, ShowType, nTab + 1, nDepth, isRef);
 | 
					 | 
				
			||||||
				if(rc == SXERR_LIMIT) {
 | 
									if(rc == SXERR_LIMIT) {
 | 
				
			||||||
					break;
 | 
										break;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -812,7 +812,6 @@ PH7_PRIVATE sxi32 PH7_MemObjStore(ph7_value *pSrc, ph7_value *pDest) {
 | 
				
			|||||||
		pObj = (ph7_class_instance *)pDest->x.pOther;
 | 
							pObj = (ph7_class_instance *)pDest->x.pOther;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	SyMemcpy((const void *) & (*pSrc), &(*pDest), sizeof(ph7_value) - (sizeof(ph7_vm *) + sizeof(SyBlob) + sizeof(sxu32)));
 | 
						SyMemcpy((const void *) & (*pSrc), &(*pDest), sizeof(ph7_value) - (sizeof(ph7_vm *) + sizeof(SyBlob) + sizeof(sxu32)));
 | 
				
			||||||
	pDest->iFlags &= ~MEMOBJ_AUX;
 | 
					 | 
				
			||||||
	rc = SXRET_OK;
 | 
						rc = SXRET_OK;
 | 
				
			||||||
	if(SyBlobLength(&pSrc->sBlob) > 0) {
 | 
						if(SyBlobLength(&pSrc->sBlob) > 0) {
 | 
				
			||||||
		SyBlobReset(&pDest->sBlob);
 | 
							SyBlobReset(&pDest->sBlob);
 | 
				
			||||||
@@ -931,8 +930,8 @@ PH7_PRIVATE sxi32 PH7_MemObjCmp(ph7_value *pObj1, ph7_value *pObj2, int bStrict,
 | 
				
			|||||||
	if(bStrict) {
 | 
						if(bStrict) {
 | 
				
			||||||
		sxi32 iF1, iF2;
 | 
							sxi32 iF1, iF2;
 | 
				
			||||||
		/* Strict comparisons with === */
 | 
							/* Strict comparisons with === */
 | 
				
			||||||
		iF1 = pObj1->iFlags & ~MEMOBJ_AUX;
 | 
							iF1 = pObj1->iFlags;
 | 
				
			||||||
		iF2 = pObj2->iFlags & ~MEMOBJ_AUX;
 | 
							iF2 = pObj2->iFlags;
 | 
				
			||||||
		if(iF1 != iF2) {
 | 
							if(iF1 != iF2) {
 | 
				
			||||||
			/* Not of the same type */
 | 
								/* Not of the same type */
 | 
				
			||||||
			return 1;
 | 
								return 1;
 | 
				
			||||||
@@ -1206,8 +1205,7 @@ PH7_PRIVATE sxi32 PH7_MemObjDump(
 | 
				
			|||||||
	ph7_value *pObj,   /* Dump this */
 | 
						ph7_value *pObj,   /* Dump this */
 | 
				
			||||||
	int ShowType,      /* TRUE to output value type */
 | 
						int ShowType,      /* TRUE to output value type */
 | 
				
			||||||
	int nTab,          /* # of Whitespace to insert */
 | 
						int nTab,          /* # of Whitespace to insert */
 | 
				
			||||||
	int nDepth,        /* Nesting level */
 | 
						int nDepth         /* Nesting level */
 | 
				
			||||||
	int isRef          /* TRUE if referenced object */
 | 
					 | 
				
			||||||
) {
 | 
					) {
 | 
				
			||||||
	sxi32 rc = SXRET_OK;
 | 
						sxi32 rc = SXRET_OK;
 | 
				
			||||||
	const char *zType;
 | 
						const char *zType;
 | 
				
			||||||
@@ -1216,9 +1214,6 @@ PH7_PRIVATE sxi32 PH7_MemObjDump(
 | 
				
			|||||||
		SyBlobAppend(&(*pOut), " ", sizeof(char));
 | 
							SyBlobAppend(&(*pOut), " ", sizeof(char));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if(ShowType) {
 | 
						if(ShowType) {
 | 
				
			||||||
		if(isRef) {
 | 
					 | 
				
			||||||
			SyBlobAppend(&(*pOut), "&", sizeof(char));
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		/* Get value type first */
 | 
							/* Get value type first */
 | 
				
			||||||
		zType = PH7_MemObjTypeDump(pObj);
 | 
							zType = PH7_MemObjTypeDump(pObj);
 | 
				
			||||||
		SyBlobAppend(&(*pOut), zType, SyStrlen(zType));
 | 
							SyBlobAppend(&(*pOut), zType, SyStrlen(zType));
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -929,7 +929,7 @@ PH7_PRIVATE sxi32 PH7_ClassInstanceDump(SyBlob *pOut, ph7_class_instance *pThis,
 | 
				
			|||||||
#else
 | 
					#else
 | 
				
			||||||
					SyBlobAppend(&(*pOut), "\n", sizeof(char));
 | 
										SyBlobAppend(&(*pOut), "\n", sizeof(char));
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
					rc = PH7_MemObjDump(&(*pOut), pValue, ShowType, nTab + 1, nDepth, 0);
 | 
										rc = PH7_MemObjDump(&(*pOut), pValue, ShowType, nTab + 1, nDepth);
 | 
				
			||||||
					if(rc == SXERR_LIMIT) {
 | 
										if(rc == SXERR_LIMIT) {
 | 
				
			||||||
						break;
 | 
											break;
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -209,8 +209,6 @@ static const ph7_expr_op aOpTable[] = {
 | 
				
			|||||||
	{ {"!==", sizeof(char) * 3}, EXPR_OP_TNE, 11, EXPR_OP_NON_ASSOC, PH7_OP_TNE},
 | 
						{ {"!==", sizeof(char) * 3}, EXPR_OP_TNE, 11, EXPR_OP_NON_ASSOC, PH7_OP_TNE},
 | 
				
			||||||
	/* Precedence 12,left-associative */
 | 
						/* Precedence 12,left-associative */
 | 
				
			||||||
	{ {"&", sizeof(char)}, EXPR_OP_BAND, 12, EXPR_OP_ASSOC_LEFT, PH7_OP_BAND},
 | 
						{ {"&", sizeof(char)}, EXPR_OP_BAND, 12, EXPR_OP_ASSOC_LEFT, PH7_OP_BAND},
 | 
				
			||||||
	/* Precedence 12,left-associative */
 | 
					 | 
				
			||||||
	{ {"=&", sizeof(char) * 2}, EXPR_OP_REF, 12, EXPR_OP_ASSOC_LEFT, PH7_OP_STORE_REF},
 | 
					 | 
				
			||||||
	/* Binary operators */
 | 
						/* Binary operators */
 | 
				
			||||||
	/* Precedence 13,left-associative */
 | 
						/* Precedence 13,left-associative */
 | 
				
			||||||
	{ {"^", sizeof(char)}, EXPR_OP_XOR, 13, EXPR_OP_ASSOC_LEFT, PH7_OP_BXOR},
 | 
						{ {"^", sizeof(char)}, EXPR_OP_XOR, 13, EXPR_OP_ASSOC_LEFT, PH7_OP_BXOR},
 | 
				
			||||||
@@ -859,13 +857,6 @@ static sxi32 ExprProcessFuncArguments(ph7_gen_state *pGen, ph7_expr_node *pOp, p
 | 
				
			|||||||
			iCur++;
 | 
								iCur++;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if(iCur > iNode) {
 | 
							if(iCur > iNode) {
 | 
				
			||||||
			if(apNode[iNode] && (apNode[iNode]->pStart->nType & PH7_TK_AMPER /*'&'*/) && ((iCur - iNode) == 2)
 | 
					 | 
				
			||||||
					&& apNode[iNode + 1]->xCode == PH7_CompileVariable) {
 | 
					 | 
				
			||||||
				PH7_GenCompileError(&(*pGen), E_WARNING, apNode[iNode]->pStart->nLine,
 | 
					 | 
				
			||||||
									"call-time pass-by-reference is deprecated");
 | 
					 | 
				
			||||||
				ExprFreeTree(&(*pGen), apNode[iNode]);
 | 
					 | 
				
			||||||
				apNode[iNode] = 0;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			ExprMakeTree(&(*pGen), &apNode[iNode], iCur - iNode);
 | 
								ExprMakeTree(&(*pGen), &apNode[iNode], iCur - iNode);
 | 
				
			||||||
			if(apNode[iNode]) {
 | 
								if(apNode[iNode]) {
 | 
				
			||||||
				/* Put a pointer to the root of the tree in the arguments set */
 | 
									/* Put a pointer to the root of the tree in the arguments set */
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										321
									
								
								engine/vm.c
									
									
									
									
									
								
							
							
						
						
									
										321
									
								
								engine/vm.c
									
									
									
									
									
								
							@@ -1324,24 +1324,6 @@ PH7_PRIVATE ph7_value *PH7_ReserveMemObj(ph7_vm *pVm) {
 | 
				
			|||||||
	pObj->nIdx = nIdx;
 | 
						pObj->nIdx = nIdx;
 | 
				
			||||||
	return pObj;
 | 
						return pObj;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * Insert an entry by reference (not copy) in the given hashmap.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
static sxi32 VmHashmapRefInsert(
 | 
					 | 
				
			||||||
	ph7_hashmap *pMap, /* Target hashmap */
 | 
					 | 
				
			||||||
	const char *zKey,  /* Entry key */
 | 
					 | 
				
			||||||
	sxu32 nByte,       /* Key length */
 | 
					 | 
				
			||||||
	sxu32 nRefIdx      /* Entry index in the object pool */
 | 
					 | 
				
			||||||
) {
 | 
					 | 
				
			||||||
	ph7_value sKey;
 | 
					 | 
				
			||||||
	sxi32 rc;
 | 
					 | 
				
			||||||
	PH7_MemObjInitFromString(pMap->pVm, &sKey, 0);
 | 
					 | 
				
			||||||
	PH7_MemObjStringAppend(&sKey, zKey, nByte);
 | 
					 | 
				
			||||||
	/* Perform the insertion */
 | 
					 | 
				
			||||||
	rc = PH7_HashmapInsertByRef(&(*pMap), &sKey, nRefIdx);
 | 
					 | 
				
			||||||
	PH7_MemObjRelease(&sKey);
 | 
					 | 
				
			||||||
	return rc;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Extract a variable value from the top active VM frame.
 | 
					 * Extract a variable value from the top active VM frame.
 | 
				
			||||||
 * Return a pointer to the variable value on success.
 | 
					 * Return a pointer to the variable value on success.
 | 
				
			||||||
@@ -2492,26 +2474,14 @@ static sxi32 VmByteCodeExec(
 | 
				
			|||||||
						iFlags = pEntry[1].iFlags; /* Save the type of value */
 | 
											iFlags = pEntry[1].iFlags; /* Save the type of value */
 | 
				
			||||||
						/* Perform the insertion */
 | 
											/* Perform the insertion */
 | 
				
			||||||
						while(pEntry < pTos) {
 | 
											while(pEntry < pTos) {
 | 
				
			||||||
							if(pEntry[1].iFlags & MEMOBJ_REFERENCE) {
 | 
												/* Standard insertion */
 | 
				
			||||||
								/* Insertion by reference */
 | 
												PH7_HashmapInsert(pMap,
 | 
				
			||||||
								PH7_HashmapInsertByRef(pMap,
 | 
																  (pEntry->iFlags & MEMOBJ_NULL) ? 0 /* Automatic index assign */ : pEntry,
 | 
				
			||||||
													   (pEntry->iFlags & MEMOBJ_NULL) ? 0 /* Automatic index assign */ : pEntry,
 | 
																  &pEntry[1]
 | 
				
			||||||
													   (sxu32)pEntry[1].x.iVal
 | 
																 );
 | 
				
			||||||
													  );
 | 
					 | 
				
			||||||
							} else {
 | 
					 | 
				
			||||||
								/* Standard insertion */
 | 
					 | 
				
			||||||
								PH7_HashmapInsert(pMap,
 | 
					 | 
				
			||||||
												  (pEntry->iFlags & MEMOBJ_NULL) ? 0 /* Automatic index assign */ : pEntry,
 | 
					 | 
				
			||||||
												  &pEntry[1]
 | 
					 | 
				
			||||||
												 );
 | 
					 | 
				
			||||||
							}
 | 
					 | 
				
			||||||
							/* Set the proper type of array */
 | 
												/* Set the proper type of array */
 | 
				
			||||||
							if((iFlags & MEMOBJ_MIXED) == 0) {
 | 
												if((iFlags & MEMOBJ_MIXED) == 0) {
 | 
				
			||||||
								if(pEntry[1].iFlags & MEMOBJ_REFERENCE) {
 | 
													pFlags = pEntry[1].iFlags;
 | 
				
			||||||
									pFlags = pEntry[1].iFlags ^ MEMOBJ_REFERENCE;
 | 
					 | 
				
			||||||
								} else {
 | 
					 | 
				
			||||||
									pFlags = pEntry[1].iFlags;
 | 
					 | 
				
			||||||
								}
 | 
					 | 
				
			||||||
								if(iFlags != pFlags && iFlags != (pFlags ^ MEMOBJ_HASHMAP)) {
 | 
													if(iFlags != pFlags && iFlags != (pFlags ^ MEMOBJ_HASHMAP)) {
 | 
				
			||||||
									iFlags = MEMOBJ_MIXED;
 | 
														iFlags = MEMOBJ_MIXED;
 | 
				
			||||||
								}
 | 
													}
 | 
				
			||||||
@@ -2801,12 +2771,10 @@ static sxi32 VmByteCodeExec(
 | 
				
			|||||||
				}
 | 
									}
 | 
				
			||||||
			/*
 | 
								/*
 | 
				
			||||||
			 * STORE_IDX:   P1 * P3
 | 
								 * STORE_IDX:   P1 * P3
 | 
				
			||||||
			 * STORE_IDX_R: P1 * P3
 | 
					 | 
				
			||||||
			 *
 | 
								 *
 | 
				
			||||||
			 * Perfrom a store operation an a hashmap entry.
 | 
								 * Perfrom a store operation an a hashmap entry.
 | 
				
			||||||
			 */
 | 
								 */
 | 
				
			||||||
			case PH7_OP_STORE_IDX:
 | 
								case PH7_OP_STORE_IDX: {
 | 
				
			||||||
			case PH7_OP_STORE_IDX_REF: {
 | 
					 | 
				
			||||||
					ph7_hashmap *pMap = 0; /* cc  warning */
 | 
										ph7_hashmap *pMap = 0; /* cc  warning */
 | 
				
			||||||
					ph7_value *pKey;
 | 
										ph7_value *pKey;
 | 
				
			||||||
					sxu32 nIdx;
 | 
										sxu32 nIdx;
 | 
				
			||||||
@@ -2836,7 +2804,7 @@ static sxi32 VmByteCodeExec(
 | 
				
			|||||||
							break;
 | 
												break;
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
						/* Phase#1: Load the array */
 | 
											/* Phase#1: Load the array */
 | 
				
			||||||
						if((pObj->iFlags & MEMOBJ_STRING) && (pInstr->iOp != PH7_OP_STORE_IDX_REF)) {
 | 
											if(pObj->iFlags & MEMOBJ_STRING) {
 | 
				
			||||||
							VmPopOperand(&pTos, 1);
 | 
												VmPopOperand(&pTos, 1);
 | 
				
			||||||
							if((pTos->iFlags & MEMOBJ_STRING) == 0) {
 | 
												if((pTos->iFlags & MEMOBJ_STRING) == 0) {
 | 
				
			||||||
								/* Force a string cast */
 | 
													/* Force a string cast */
 | 
				
			||||||
@@ -2880,12 +2848,7 @@ static sxi32 VmByteCodeExec(
 | 
				
			|||||||
					}
 | 
										}
 | 
				
			||||||
					VmPopOperand(&pTos, 1);
 | 
										VmPopOperand(&pTos, 1);
 | 
				
			||||||
					/* Phase#2: Perform the insertion */
 | 
										/* Phase#2: Perform the insertion */
 | 
				
			||||||
					if(pInstr->iOp == PH7_OP_STORE_IDX_REF && pTos->nIdx != SXU32_HIGH) {
 | 
										PH7_HashmapInsert(pMap, pKey, pTos);
 | 
				
			||||||
						/* Insertion by reference */
 | 
					 | 
				
			||||||
						PH7_HashmapInsertByRef(pMap, pKey, pTos->nIdx);
 | 
					 | 
				
			||||||
					} else {
 | 
					 | 
				
			||||||
						PH7_HashmapInsert(pMap, pKey, pTos);
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
					if(pKey) {
 | 
										if(pKey) {
 | 
				
			||||||
						PH7_MemObjRelease(pKey);
 | 
											PH7_MemObjRelease(pKey);
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
@@ -3958,96 +3921,6 @@ static sxi32 VmByteCodeExec(
 | 
				
			|||||||
					}
 | 
										}
 | 
				
			||||||
					break;
 | 
										break;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			/*
 | 
					 | 
				
			||||||
			 * OP_LOAD_REF * * *
 | 
					 | 
				
			||||||
			 * Push the index of a referenced object on the stack.
 | 
					 | 
				
			||||||
			 */
 | 
					 | 
				
			||||||
			case PH7_OP_LOAD_REF: {
 | 
					 | 
				
			||||||
					sxu32 nIdx;
 | 
					 | 
				
			||||||
#ifdef UNTRUST
 | 
					 | 
				
			||||||
					if(pTos < pStack) {
 | 
					 | 
				
			||||||
						goto Abort;
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
					/* Extract memory object index */
 | 
					 | 
				
			||||||
					nIdx = pTos->nIdx;
 | 
					 | 
				
			||||||
					if(nIdx != SXU32_HIGH /* Not a constant */) {
 | 
					 | 
				
			||||||
						/* Nullify the object */
 | 
					 | 
				
			||||||
						PH7_MemObjRelease(pTos);
 | 
					 | 
				
			||||||
						/* Mark as constant and store the index on the top of the stack */
 | 
					 | 
				
			||||||
						pTos->x.iVal = (sxi64)nIdx;
 | 
					 | 
				
			||||||
						pTos->nIdx = SXU32_HIGH;
 | 
					 | 
				
			||||||
						pTos->iFlags = MEMOBJ_INT | MEMOBJ_REFERENCE;
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
					break;
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			/*
 | 
					 | 
				
			||||||
			 * OP_STORE_REF * * P3
 | 
					 | 
				
			||||||
			 * Perform an assignment operation by reference.
 | 
					 | 
				
			||||||
			 */
 | 
					 | 
				
			||||||
			case PH7_OP_STORE_REF: {
 | 
					 | 
				
			||||||
					SyString sName = { 0, 0 };
 | 
					 | 
				
			||||||
					SyHashEntry *pEntry;
 | 
					 | 
				
			||||||
					sxu32 nIdx;
 | 
					 | 
				
			||||||
#ifdef UNTRUST
 | 
					 | 
				
			||||||
					if(pTos < pStack) {
 | 
					 | 
				
			||||||
						goto Abort;
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
					if(pInstr->p3 == 0) {
 | 
					 | 
				
			||||||
						char *zName;
 | 
					 | 
				
			||||||
						/* Take the variable name from the Next on the stack */
 | 
					 | 
				
			||||||
						if((pTos->iFlags & MEMOBJ_STRING) == 0) {
 | 
					 | 
				
			||||||
							/* Force a string cast */
 | 
					 | 
				
			||||||
							PH7_MemObjToString(pTos);
 | 
					 | 
				
			||||||
						}
 | 
					 | 
				
			||||||
						if(SyBlobLength(&pTos->sBlob) > 0) {
 | 
					 | 
				
			||||||
							zName = SyMemBackendStrDup(&pVm->sAllocator,
 | 
					 | 
				
			||||||
													   (const char *)SyBlobData(&pTos->sBlob), SyBlobLength(&pTos->sBlob));
 | 
					 | 
				
			||||||
							if(zName) {
 | 
					 | 
				
			||||||
								SyStringInitFromBuf(&sName, zName, SyBlobLength(&pTos->sBlob));
 | 
					 | 
				
			||||||
							}
 | 
					 | 
				
			||||||
						}
 | 
					 | 
				
			||||||
						PH7_MemObjRelease(pTos);
 | 
					 | 
				
			||||||
						pTos--;
 | 
					 | 
				
			||||||
					} else {
 | 
					 | 
				
			||||||
						SyStringInitFromBuf(&sName, pInstr->p3, SyStrlen((const char *)pInstr->p3));
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
					nIdx = pTos->nIdx;
 | 
					 | 
				
			||||||
					if(nIdx == SXU32_HIGH) {
 | 
					 | 
				
			||||||
						if((pTos->iFlags & (MEMOBJ_OBJ | MEMOBJ_HASHMAP | MEMOBJ_RES)) == 0) {
 | 
					 | 
				
			||||||
							PH7_VmThrowError(&(*pVm), PH7_CTX_ERR,
 | 
					 | 
				
			||||||
											 "Reference operator require a variable not a constant as it's right operand");
 | 
					 | 
				
			||||||
						} else {
 | 
					 | 
				
			||||||
							ph7_value *pObj;
 | 
					 | 
				
			||||||
							/* Extract the desired variable and if not available dynamically create it */
 | 
					 | 
				
			||||||
							pObj = VmExtractMemObj(&(*pVm), &sName, FALSE, TRUE);
 | 
					 | 
				
			||||||
							if(pObj == 0) {
 | 
					 | 
				
			||||||
								PH7_VmMemoryError(&(*pVm));
 | 
					 | 
				
			||||||
							}
 | 
					 | 
				
			||||||
							/* Perform the store operation */
 | 
					 | 
				
			||||||
							PH7_MemObjStore(pTos, pObj);
 | 
					 | 
				
			||||||
							pTos->nIdx = pObj->nIdx;
 | 
					 | 
				
			||||||
						}
 | 
					 | 
				
			||||||
					} else if(sName.nByte > 0) {
 | 
					 | 
				
			||||||
						VmFrame *pFrame = pVm->pFrame;
 | 
					 | 
				
			||||||
						while(pFrame->pParent && (pFrame->iFlags & VM_FRAME_EXCEPTION)) {
 | 
					 | 
				
			||||||
							/* Safely ignore the exception frame */
 | 
					 | 
				
			||||||
							pFrame = pFrame->pParent;
 | 
					 | 
				
			||||||
						}
 | 
					 | 
				
			||||||
						/* Query the local frame */
 | 
					 | 
				
			||||||
						pEntry = SyHashGet(&pFrame->hVar, (const void *)sName.zString, sName.nByte);
 | 
					 | 
				
			||||||
						if(pEntry) {
 | 
					 | 
				
			||||||
							rc = SyHashInsert(&pFrame->hVar, (const void *)sName.zString, sName.nByte, SX_INT_TO_PTR(nIdx));
 | 
					 | 
				
			||||||
							if(rc == SXRET_OK) {
 | 
					 | 
				
			||||||
								PH7_VmRefObjInstall(&(*pVm), nIdx, SyHashLastEntry(&pFrame->hVar), 0, 0);
 | 
					 | 
				
			||||||
							}
 | 
					 | 
				
			||||||
						} else {
 | 
					 | 
				
			||||||
							PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Referenced variable name '%z' does not exists", &sName);
 | 
					 | 
				
			||||||
						}
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
					break;
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			/*
 | 
								/*
 | 
				
			||||||
			 * OP_LOAD_EXCEPTION * P2 P3
 | 
								 * OP_LOAD_EXCEPTION * P2 P3
 | 
				
			||||||
			 * Push an exception in the corresponding container so that
 | 
								 * Push an exception in the corresponding container so that
 | 
				
			||||||
@@ -5668,9 +5541,6 @@ static const char *VmInstrToString(sxi32 nOp) {
 | 
				
			|||||||
		case PH7_OP_STORE_IDX:
 | 
							case PH7_OP_STORE_IDX:
 | 
				
			||||||
			zOp = "STORE_IDX";
 | 
								zOp = "STORE_IDX";
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case PH7_OP_STORE_IDX_REF:
 | 
					 | 
				
			||||||
			zOp = "STORE_IDX_R";
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		case PH7_OP_PULL:
 | 
							case PH7_OP_PULL:
 | 
				
			||||||
			zOp = "PULL";
 | 
								zOp = "PULL";
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
@@ -5734,12 +5604,6 @@ static const char *VmInstrToString(sxi32 nOp) {
 | 
				
			|||||||
		case PH7_OP_CONSUME:
 | 
							case PH7_OP_CONSUME:
 | 
				
			||||||
			zOp = "CONSUME";
 | 
								zOp = "CONSUME";
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case PH7_OP_LOAD_REF:
 | 
					 | 
				
			||||||
			zOp = "LOAD_REF";
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		case PH7_OP_STORE_REF:
 | 
					 | 
				
			||||||
			zOp = "STORE_REF";
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		case PH7_OP_MEMBER:
 | 
							case PH7_OP_MEMBER:
 | 
				
			||||||
			zOp = "MEMBER";
 | 
								zOp = "MEMBER";
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
@@ -5812,163 +5676,6 @@ PH7_PRIVATE void PH7_VmExpandConstantValue(ph7_value *pVal, void *pUserData) {
 | 
				
			|||||||
 * Status:
 | 
					 * Status:
 | 
				
			||||||
 *    Stable.
 | 
					 *    Stable.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * int func_num_args(void)
 | 
					 | 
				
			||||||
 *   Returns the number of arguments passed to the function.
 | 
					 | 
				
			||||||
 * Parameters
 | 
					 | 
				
			||||||
 *   None.
 | 
					 | 
				
			||||||
 * Return
 | 
					 | 
				
			||||||
 *  Total number of arguments passed into the current user-defined function
 | 
					 | 
				
			||||||
 *  or -1 if called from the globe scope.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
static int vm_builtin_func_num_args(ph7_context *pCtx, int nArg, ph7_value **apArg) {
 | 
					 | 
				
			||||||
	VmFrame *pFrame;
 | 
					 | 
				
			||||||
	ph7_vm *pVm;
 | 
					 | 
				
			||||||
	/* Point to the target VM */
 | 
					 | 
				
			||||||
	pVm = pCtx->pVm;
 | 
					 | 
				
			||||||
	/* Current frame */
 | 
					 | 
				
			||||||
	pFrame = pVm->pFrame;
 | 
					 | 
				
			||||||
	while(pFrame->pParent && (pFrame->iFlags & VM_FRAME_EXCEPTION)) {
 | 
					 | 
				
			||||||
		/* Safely ignore the exception frame */
 | 
					 | 
				
			||||||
		pFrame = pFrame->pParent;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if(pFrame->pParent == 0) {
 | 
					 | 
				
			||||||
		SXUNUSED(nArg);
 | 
					 | 
				
			||||||
		SXUNUSED(apArg);
 | 
					 | 
				
			||||||
		/* Global frame,return -1 */
 | 
					 | 
				
			||||||
		ph7_result_int(pCtx, -1);
 | 
					 | 
				
			||||||
		return SXRET_OK;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	/* Total number of arguments passed to the enclosing function */
 | 
					 | 
				
			||||||
	nArg = (int)SySetUsed(&pFrame->sArg);
 | 
					 | 
				
			||||||
	ph7_result_int(pCtx, nArg);
 | 
					 | 
				
			||||||
	return SXRET_OK;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * value func_get_arg(int $arg_num)
 | 
					 | 
				
			||||||
 *   Return an item from the argument list.
 | 
					 | 
				
			||||||
 * Parameters
 | 
					 | 
				
			||||||
 *  Argument number(index start from zero).
 | 
					 | 
				
			||||||
 * Return
 | 
					 | 
				
			||||||
 *  Returns the specified argument or FALSE on error.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
static int vm_builtin_func_get_arg(ph7_context *pCtx, int nArg, ph7_value **apArg) {
 | 
					 | 
				
			||||||
	ph7_value *pObj = 0;
 | 
					 | 
				
			||||||
	VmSlot *pSlot = 0;
 | 
					 | 
				
			||||||
	VmFrame *pFrame;
 | 
					 | 
				
			||||||
	ph7_vm *pVm;
 | 
					 | 
				
			||||||
	/* Point to the target VM */
 | 
					 | 
				
			||||||
	pVm = pCtx->pVm;
 | 
					 | 
				
			||||||
	/* Current frame */
 | 
					 | 
				
			||||||
	pFrame = pVm->pFrame;
 | 
					 | 
				
			||||||
	while(pFrame->pParent && (pFrame->iFlags & VM_FRAME_EXCEPTION)) {
 | 
					 | 
				
			||||||
		/* Safely ignore the exception frame */
 | 
					 | 
				
			||||||
		pFrame = pFrame->pParent;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	/* Extract the desired index */
 | 
					 | 
				
			||||||
	nArg = ph7_value_to_int(apArg[0]);
 | 
					 | 
				
			||||||
	if(nArg < 0 || nArg >= (int)SySetUsed(&pFrame->sArg)) {
 | 
					 | 
				
			||||||
		/* Invalid index,return FALSE */
 | 
					 | 
				
			||||||
		ph7_result_bool(pCtx, 0);
 | 
					 | 
				
			||||||
		return SXRET_OK;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	/* Extract the desired argument */
 | 
					 | 
				
			||||||
	if((pSlot = (VmSlot *)SySetAt(&pFrame->sArg, (sxu32)nArg)) != 0) {
 | 
					 | 
				
			||||||
		if((pObj = (ph7_value *)SySetAt(&pVm->aMemObj, pSlot->nIdx)) != 0) {
 | 
					 | 
				
			||||||
			/* Return the desired argument */
 | 
					 | 
				
			||||||
			ph7_result_value(pCtx, (ph7_value *)pObj);
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			/* No such argument,return false */
 | 
					 | 
				
			||||||
			ph7_result_bool(pCtx, 0);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		/* CAN'T HAPPEN */
 | 
					 | 
				
			||||||
		ph7_result_bool(pCtx, 0);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return SXRET_OK;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * array func_get_args_byref(void)
 | 
					 | 
				
			||||||
 *   Returns an array comprising a function's argument list.
 | 
					 | 
				
			||||||
 * Parameters
 | 
					 | 
				
			||||||
 *  None.
 | 
					 | 
				
			||||||
 * Return
 | 
					 | 
				
			||||||
 *  Returns an array in which each element is a POINTER to the corresponding
 | 
					 | 
				
			||||||
 *  member of the current user-defined function's argument list.
 | 
					 | 
				
			||||||
 *  Otherwise FALSE is returned on failure.
 | 
					 | 
				
			||||||
 * NOTE:
 | 
					 | 
				
			||||||
 *  Arguments are returned to the array by reference.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
static int vm_builtin_func_get_args_byref(ph7_context *pCtx, int nArg, ph7_value **apArg) {
 | 
					 | 
				
			||||||
	ph7_value *pArray;
 | 
					 | 
				
			||||||
	VmFrame *pFrame;
 | 
					 | 
				
			||||||
	VmSlot *aSlot;
 | 
					 | 
				
			||||||
	sxu32 n;
 | 
					 | 
				
			||||||
	/* Point to the current frame */
 | 
					 | 
				
			||||||
	pFrame = pCtx->pVm->pFrame;
 | 
					 | 
				
			||||||
	while(pFrame->pParent && (pFrame->iFlags & VM_FRAME_EXCEPTION)) {
 | 
					 | 
				
			||||||
		/* Safely ignore the exception frame */
 | 
					 | 
				
			||||||
		pFrame = pFrame->pParent;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	/* Create a new array */
 | 
					 | 
				
			||||||
	pArray = ph7_context_new_array(pCtx);
 | 
					 | 
				
			||||||
	if(pArray == 0) {
 | 
					 | 
				
			||||||
		SXUNUSED(nArg); /* cc warning */
 | 
					 | 
				
			||||||
		SXUNUSED(apArg);
 | 
					 | 
				
			||||||
		ph7_result_bool(pCtx, 0);
 | 
					 | 
				
			||||||
		return SXRET_OK;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	/* Start filling the array with the given arguments (Pass by reference) */
 | 
					 | 
				
			||||||
	aSlot = (VmSlot *)SySetBasePtr(&pFrame->sArg);
 | 
					 | 
				
			||||||
	for(n = 0;  n < SySetUsed(&pFrame->sArg) ; n++) {
 | 
					 | 
				
			||||||
		PH7_HashmapInsertByRef((ph7_hashmap *)pArray->x.pOther, 0/*Automatic index assign*/, aSlot[n].nIdx);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	/* Return the freshly created array */
 | 
					 | 
				
			||||||
	ph7_result_value(pCtx, pArray);
 | 
					 | 
				
			||||||
	return SXRET_OK;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * array func_get_args(void)
 | 
					 | 
				
			||||||
 *   Returns an array comprising a copy of function's argument list.
 | 
					 | 
				
			||||||
 * Parameters
 | 
					 | 
				
			||||||
 *  None.
 | 
					 | 
				
			||||||
 * Return
 | 
					 | 
				
			||||||
 *  Returns an array in which each element is a copy of the corresponding
 | 
					 | 
				
			||||||
 *  member of the current user-defined function's argument list.
 | 
					 | 
				
			||||||
 *  Otherwise FALSE is returned on failure.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
static int vm_builtin_func_get_args(ph7_context *pCtx, int nArg, ph7_value **apArg) {
 | 
					 | 
				
			||||||
	ph7_value *pObj = 0;
 | 
					 | 
				
			||||||
	ph7_value *pArray;
 | 
					 | 
				
			||||||
	VmFrame *pFrame;
 | 
					 | 
				
			||||||
	VmSlot *aSlot;
 | 
					 | 
				
			||||||
	sxu32 n;
 | 
					 | 
				
			||||||
	/* Point to the current frame */
 | 
					 | 
				
			||||||
	pFrame = pCtx->pVm->pFrame;
 | 
					 | 
				
			||||||
	while(pFrame->pParent && (pFrame->iFlags & VM_FRAME_EXCEPTION)) {
 | 
					 | 
				
			||||||
		/* Safely ignore the exception frame */
 | 
					 | 
				
			||||||
		pFrame = pFrame->pParent;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	/* Create a new array */
 | 
					 | 
				
			||||||
	pArray = ph7_context_new_array(pCtx);
 | 
					 | 
				
			||||||
	if(pArray == 0) {
 | 
					 | 
				
			||||||
		SXUNUSED(nArg); /* cc warning */
 | 
					 | 
				
			||||||
		SXUNUSED(apArg);
 | 
					 | 
				
			||||||
		ph7_result_bool(pCtx, 0);
 | 
					 | 
				
			||||||
		return SXRET_OK;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	/* Start filling the array with the given arguments */
 | 
					 | 
				
			||||||
	aSlot = (VmSlot *)SySetBasePtr(&pFrame->sArg);
 | 
					 | 
				
			||||||
	for(n = 0;  n < SySetUsed(&pFrame->sArg) ; n++) {
 | 
					 | 
				
			||||||
		pObj = (ph7_value *)SySetAt(&pCtx->pVm->aMemObj, aSlot[n].nIdx);
 | 
					 | 
				
			||||||
		if(pObj) {
 | 
					 | 
				
			||||||
			ph7_array_add_elem(pArray, 0/* Automatic index assign*/, pObj);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	/* Return the freshly created array */
 | 
					 | 
				
			||||||
	ph7_result_value(pCtx, pArray);
 | 
					 | 
				
			||||||
	return SXRET_OK;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * bool function_exists(string $name)
 | 
					 * bool function_exists(string $name)
 | 
				
			||||||
 *  Return TRUE if the given function has been defined.
 | 
					 *  Return TRUE if the given function has been defined.
 | 
				
			||||||
@@ -8491,7 +8198,7 @@ static int vm_builtin_var_dump(ph7_context *pCtx, int nArg, ph7_value **apArg) {
 | 
				
			|||||||
		/* Reset the working buffer */
 | 
							/* Reset the working buffer */
 | 
				
			||||||
		SyBlobReset(&sDump);
 | 
							SyBlobReset(&sDump);
 | 
				
			||||||
		/* Dump the given expression */
 | 
							/* Dump the given expression */
 | 
				
			||||||
		PH7_MemObjDump(&sDump, pObj, TRUE, 0, 0, 0);
 | 
							PH7_MemObjDump(&sDump, pObj, TRUE, 0, 0);
 | 
				
			||||||
		/* Output */
 | 
							/* Output */
 | 
				
			||||||
		if(SyBlobLength(&sDump) > 0) {
 | 
							if(SyBlobLength(&sDump) > 0) {
 | 
				
			||||||
			ph7_context_output(pCtx, (const char *)SyBlobData(&sDump), (int)SyBlobLength(&sDump));
 | 
								ph7_context_output(pCtx, (const char *)SyBlobData(&sDump), (int)SyBlobLength(&sDump));
 | 
				
			||||||
@@ -8527,7 +8234,7 @@ static int vm_builtin_print_r(ph7_context *pCtx, int nArg, ph7_value **apArg) {
 | 
				
			|||||||
		ret_string = ph7_value_to_bool(apArg[1]);
 | 
							ret_string = ph7_value_to_bool(apArg[1]);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	/* Generate dump */
 | 
						/* Generate dump */
 | 
				
			||||||
	PH7_MemObjDump(&sDump, apArg[0], FALSE, 0, 0, 0);
 | 
						PH7_MemObjDump(&sDump, apArg[0], FALSE, 0, 0);
 | 
				
			||||||
	if(!ret_string) {
 | 
						if(!ret_string) {
 | 
				
			||||||
		/* Output dump */
 | 
							/* Output dump */
 | 
				
			||||||
		ph7_context_output(pCtx, (const char *)SyBlobData(&sDump), (int)SyBlobLength(&sDump));
 | 
							ph7_context_output(pCtx, (const char *)SyBlobData(&sDump), (int)SyBlobLength(&sDump));
 | 
				
			||||||
@@ -8559,7 +8266,7 @@ static int vm_builtin_var_export(ph7_context *pCtx, int nArg, ph7_value **apArg)
 | 
				
			|||||||
		ret_string = ph7_value_to_bool(apArg[1]);
 | 
							ret_string = ph7_value_to_bool(apArg[1]);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	/* Generate dump */
 | 
						/* Generate dump */
 | 
				
			||||||
	PH7_MemObjDump(&sDump, apArg[0], FALSE, 0, 0, 0);
 | 
						PH7_MemObjDump(&sDump, apArg[0], FALSE, 0, 0);
 | 
				
			||||||
	if(!ret_string) {
 | 
						if(!ret_string) {
 | 
				
			||||||
		/* Output dump */
 | 
							/* Output dump */
 | 
				
			||||||
		ph7_context_output(pCtx, (const char *)SyBlobData(&sDump), (int)SyBlobLength(&sDump));
 | 
							ph7_context_output(pCtx, (const char *)SyBlobData(&sDump), (int)SyBlobLength(&sDump));
 | 
				
			||||||
@@ -10841,10 +10548,6 @@ static int vm_builtin_utf8_decode(ph7_context *pCtx, int nArg, ph7_value **apArg
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
/* Table of built-in VM functions. */
 | 
					/* Table of built-in VM functions. */
 | 
				
			||||||
static const ph7_builtin_func aVmFunc[] = {
 | 
					static const ph7_builtin_func aVmFunc[] = {
 | 
				
			||||||
	{ "func_num_args", vm_builtin_func_num_args },
 | 
					 | 
				
			||||||
	{ "func_get_arg", vm_builtin_func_get_arg  },
 | 
					 | 
				
			||||||
	{ "func_get_args", vm_builtin_func_get_args },
 | 
					 | 
				
			||||||
	{ "func_get_args_byref", vm_builtin_func_get_args_byref },
 | 
					 | 
				
			||||||
	{ "function_exists", vm_builtin_func_exists   },
 | 
						{ "function_exists", vm_builtin_func_exists   },
 | 
				
			||||||
	{ "is_callback", vm_builtin_is_callback   },
 | 
						{ "is_callback", vm_builtin_is_callback   },
 | 
				
			||||||
	{ "get_defined_functions", vm_builtin_get_defined_func },
 | 
						{ "get_defined_functions", vm_builtin_get_defined_func },
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -641,7 +641,6 @@ struct ph7_value {
 | 
				
			|||||||
#define MEMOBJ_STRING    0x0080  /* Memory value is a UTF-8 string */
 | 
					#define MEMOBJ_STRING    0x0080  /* Memory value is a UTF-8 string */
 | 
				
			||||||
#define MEMOBJ_VOID      0x0100  /* Memory value is a void */
 | 
					#define MEMOBJ_VOID      0x0100  /* Memory value is a void */
 | 
				
			||||||
#define MEMOBJ_MIXED     0x0200  /* Memory value is mixed */
 | 
					#define MEMOBJ_MIXED     0x0200  /* Memory value is mixed */
 | 
				
			||||||
#define MEMOBJ_REFERENCE 0x0400  /* Memory value hold a reference (64-bit index) of another ph7_value */
 | 
					 | 
				
			||||||
#define MEMOBJ_HASHMAP   0x0800  /* Memory value is a hashmap aka 'array' in the PHP jargon */
 | 
					#define MEMOBJ_HASHMAP   0x0800  /* Memory value is a hashmap aka 'array' in the PHP jargon */
 | 
				
			||||||
#define MEMOBJ_NULL      0x1000  /* Memory value is NULL */
 | 
					#define MEMOBJ_NULL      0x1000  /* Memory value is NULL */
 | 
				
			||||||
/* Mask of all known types */
 | 
					/* Mask of all known types */
 | 
				
			||||||
@@ -652,7 +651,6 @@ struct ph7_value {
 | 
				
			|||||||
 *  Types array, object and resource are not scalar.
 | 
					 *  Types array, object and resource are not scalar.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
#define MEMOBJ_SCALAR (MEMOBJ_STRING|MEMOBJ_INT|MEMOBJ_REAL|MEMOBJ_BOOL|MEMOBJ_CHAR|MEMOBJ_VOID|MEMOBJ_NULL)
 | 
					#define MEMOBJ_SCALAR (MEMOBJ_STRING|MEMOBJ_INT|MEMOBJ_REAL|MEMOBJ_BOOL|MEMOBJ_CHAR|MEMOBJ_VOID|MEMOBJ_NULL)
 | 
				
			||||||
#define MEMOBJ_AUX (MEMOBJ_REFERENCE)
 | 
					 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * The following macro clear the current ph7_value type and replace
 | 
					 * The following macro clear the current ph7_value type and replace
 | 
				
			||||||
 * it with the given one.
 | 
					 * it with the given one.
 | 
				
			||||||
@@ -1453,8 +1451,6 @@ enum ph7_vm_op {
 | 
				
			|||||||
	PH7_OP_BOR_STORE,    /* Bitor and store '|=' */
 | 
						PH7_OP_BOR_STORE,    /* Bitor and store '|=' */
 | 
				
			||||||
	PH7_OP_BXOR_STORE,   /* Bitxor and store '^=' */
 | 
						PH7_OP_BXOR_STORE,   /* Bitxor and store '^=' */
 | 
				
			||||||
	PH7_OP_CONSUME,      /* Consume VM output */
 | 
						PH7_OP_CONSUME,      /* Consume VM output */
 | 
				
			||||||
	PH7_OP_LOAD_REF,     /* Load reference */
 | 
					 | 
				
			||||||
	PH7_OP_STORE_REF,    /* Store a reference to a variable*/
 | 
					 | 
				
			||||||
	PH7_OP_MEMBER,       /* Class member run-time access */
 | 
						PH7_OP_MEMBER,       /* Class member run-time access */
 | 
				
			||||||
	PH7_OP_CVT_OBJ,      /* Object cast */
 | 
						PH7_OP_CVT_OBJ,      /* Object cast */
 | 
				
			||||||
	PH7_OP_CVT_CALL,     /* Callback cast */
 | 
						PH7_OP_CVT_CALL,     /* Callback cast */
 | 
				
			||||||
@@ -1626,7 +1622,7 @@ enum json_err_code {
 | 
				
			|||||||
	JSON_ERROR_UTF8       /* Malformed UTF-8 characters */
 | 
						JSON_ERROR_UTF8       /* Malformed UTF-8 characters */
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
/* memobj.c function prototypes */
 | 
					/* memobj.c function prototypes */
 | 
				
			||||||
PH7_PRIVATE sxi32 PH7_MemObjDump(SyBlob *pOut, ph7_value *pObj, int ShowType, int nTab, int nDepth, int isRef);
 | 
					PH7_PRIVATE sxi32 PH7_MemObjDump(SyBlob *pOut, ph7_value *pObj, int ShowType, int nTab, int nDepth);
 | 
				
			||||||
PH7_PRIVATE const char *PH7_MemObjTypeDump(ph7_value *pVal);
 | 
					PH7_PRIVATE const char *PH7_MemObjTypeDump(ph7_value *pVal);
 | 
				
			||||||
PH7_PRIVATE sxi32 PH7_MemObjAdd(ph7_value *pObj1, ph7_value *pObj2, int bAddStore);
 | 
					PH7_PRIVATE sxi32 PH7_MemObjAdd(ph7_value *pObj1, ph7_value *pObj2, int bAddStore);
 | 
				
			||||||
PH7_PRIVATE sxi32 PH7_MemObjCmp(ph7_value *pObj1, ph7_value *pObj2, int bStrict, int iNest);
 | 
					PH7_PRIVATE sxi32 PH7_MemObjCmp(ph7_value *pObj1, ph7_value *pObj2, int bStrict, int iNest);
 | 
				
			||||||
@@ -1739,7 +1735,6 @@ PH7_PRIVATE sxi32 PH7_HashmapRelease(ph7_hashmap *pMap, int FreeDS);
 | 
				
			|||||||
PH7_PRIVATE void  PH7_HashmapUnref(ph7_hashmap *pMap);
 | 
					PH7_PRIVATE void  PH7_HashmapUnref(ph7_hashmap *pMap);
 | 
				
			||||||
PH7_PRIVATE sxi32 PH7_HashmapLookup(ph7_hashmap *pMap, ph7_value *pKey, ph7_hashmap_node **ppNode);
 | 
					PH7_PRIVATE sxi32 PH7_HashmapLookup(ph7_hashmap *pMap, ph7_value *pKey, ph7_hashmap_node **ppNode);
 | 
				
			||||||
PH7_PRIVATE sxi32 PH7_HashmapInsert(ph7_hashmap *pMap, ph7_value *pKey, ph7_value *pVal);
 | 
					PH7_PRIVATE sxi32 PH7_HashmapInsert(ph7_hashmap *pMap, ph7_value *pKey, ph7_value *pVal);
 | 
				
			||||||
PH7_PRIVATE sxi32 PH7_HashmapInsertByRef(ph7_hashmap *pMap, ph7_value *pKey, sxu32 nRefIdx);
 | 
					 | 
				
			||||||
PH7_PRIVATE sxi32 PH7_HashmapUnion(ph7_hashmap *pLeft, ph7_hashmap *pRight);
 | 
					PH7_PRIVATE sxi32 PH7_HashmapUnion(ph7_hashmap *pLeft, ph7_hashmap *pRight);
 | 
				
			||||||
PH7_PRIVATE void PH7_HashmapUnlinkNode(ph7_hashmap_node *pNode, int bRestore);
 | 
					PH7_PRIVATE void PH7_HashmapUnlinkNode(ph7_hashmap_node *pNode, int bRestore);
 | 
				
			||||||
PH7_PRIVATE sxi32 PH7_HashmapDup(ph7_hashmap *pSrc, ph7_hashmap *pDest);
 | 
					PH7_PRIVATE sxi32 PH7_HashmapDup(ph7_hashmap *pSrc, ph7_hashmap *pDest);
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user