|
|
|
/*
|
|
|
|
* Symisc PH7: An embeddable bytecode compiler and a virtual machine for the PHP(5) programming language.
|
|
|
|
* Copyright (C) 2011-2012, Symisc Systems http://ph7.symisc.net/
|
|
|
|
* Version 2.1.4
|
|
|
|
* For information on licensing,redistribution of this file,and for a DISCLAIMER OF ALL WARRANTIES
|
|
|
|
* please contact Symisc Systems via:
|
|
|
|
* legal@symisc.net
|
|
|
|
* licensing@symisc.net
|
|
|
|
* contact@symisc.net
|
|
|
|
* or visit:
|
|
|
|
* http://ph7.symisc.net/
|
|
|
|
*/
|
|
|
|
/* $SymiscID: ph7int.h v1.9 FreeBSD 2012-08-13 26:25 devel <chm@symisc.net> $ */
|
|
|
|
#ifndef __PH7INT_H__
|
|
|
|
#define __PH7INT_H__
|
|
|
|
#define PH7_PRIVATE
|
|
|
|
#include "ph7.h"
|
|
|
|
#ifdef __WINNT__
|
|
|
|
#include <windows.h>
|
|
|
|
#else
|
|
|
|
#include <dlfcn.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Constants for the largest and smallest possible 64-bit signed integers.
|
|
|
|
* These macros are designed to work correctly on both 32-bit and 64-bit
|
|
|
|
* compilers.
|
|
|
|
*/
|
|
|
|
#ifndef LARGEST_INT64
|
|
|
|
#define LARGEST_INT64 (0xffffffff|(((sxi64)0x7fffffff)<<32))
|
|
|
|
#endif
|
|
|
|
#ifndef SMALLEST_INT64
|
|
|
|
#define SMALLEST_INT64 (((sxi64)-1) - LARGEST_INT64)
|
|
|
|
#endif
|
|
|
|
/* Forward declaration of private structures */
|
|
|
|
typedef struct ph7_class_instance ph7_class_instance;
|
|
|
|
typedef struct ph7_foreach_info ph7_foreach_info;
|
|
|
|
typedef struct ph7_foreach_step ph7_foreach_step;
|
|
|
|
typedef struct ph7_hashmap_node ph7_hashmap_node;
|
|
|
|
typedef struct ph7_hashmap ph7_hashmap;
|
|
|
|
typedef struct ph7_class_info ph7_class_info;
|
|
|
|
typedef struct ph7_class ph7_class;
|
|
|
|
|
|
|
|
/* Symisc Standard types */
|
|
|
|
#if !defined(SYMISC_STD_TYPES)
|
|
|
|
#define SYMISC_STD_TYPES
|
|
|
|
#ifdef __WINNT__
|
|
|
|
/* Disable nuisance warnings on Borland compilers */
|
|
|
|
#if defined(__BORLANDC__)
|
|
|
|
#pragma warn -rch /* unreachable code */
|
|
|
|
#pragma warn -ccc /* Condition is always true or false */
|
|
|
|
#pragma warn -aus /* Assigned value is never used */
|
|
|
|
#pragma warn -csu /* Comparing signed and unsigned */
|
|
|
|
#pragma warn -spa /* Suspicious pointer arithmetic */
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
typedef signed char sxi8; /* signed char */
|
|
|
|
typedef unsigned char sxu8; /* unsigned char */
|
|
|
|
typedef signed short int sxi16; /* 16 bits(2 bytes) signed integer */
|
|
|
|
typedef unsigned short int sxu16; /* 16 bits(2 bytes) unsigned integer */
|
|
|
|
typedef int sxi32; /* 32 bits(4 bytes) integer */
|
|
|
|
typedef unsigned int sxu32; /* 32 bits(4 bytes) unsigned integer */
|
|
|
|
typedef int sxbool; /* boolean */
|
|
|
|
typedef long sxptr;
|
|
|
|
typedef unsigned long sxuptr;
|
|
|
|
typedef long sxlong;
|
|
|
|
typedef unsigned long sxulong;
|
|
|
|
typedef sxi32 sxofft;
|
|
|
|
typedef sxi64 sxofft64;
|
|
|
|
typedef long double sxlongreal;
|
|
|
|
typedef double sxreal;
|
|
|
|
#define SXI8_HIGH 0x7F
|
|
|
|
#define SXU8_HIGH 0xFF
|
|
|
|
#define SXI16_HIGH 0x7FFF
|
|
|
|
#define SXU16_HIGH 0xFFFF
|
|
|
|
#define SXI32_HIGH 0x7FFFFFFF
|
|
|
|
#define SXU32_HIGH 0xFFFFFFFF
|
|
|
|
#define SXI64_HIGH 0x7FFFFFFFFFFFFFFFLL
|
|
|
|
#define SXU64_HIGH 0xFFFFFFFFFFFFFFFFUL
|
|
|
|
#if !defined(TRUE)
|
|
|
|
#define TRUE 1
|
|
|
|
#endif
|
|
|
|
#if !defined(FALSE)
|
|
|
|
#define FALSE 0
|
|
|
|
#endif
|
|
|
|
/*
|
|
|
|
* The following macros are used to cast pointers to integers and
|
|
|
|
* integers to pointers.
|
|
|
|
*/
|
|
|
|
#if defined(__PTRDIFF_TYPE__)
|
|
|
|
#define SX_INT_TO_PTR(X) ((void*)(__PTRDIFF_TYPE__)(X))
|
|
|
|
#define SX_PTR_TO_INT(X) ((int)(__PTRDIFF_TYPE__)(X))
|
|
|
|
#elif !defined(__GNUC__)
|
|
|
|
#define SX_INT_TO_PTR(X) ((void*)&((char*)0)[X])
|
|
|
|
#define SX_PTR_TO_INT(X) ((int)(((char*)X)-(char*)0))
|
|
|
|
#else
|
|
|
|
#define SX_INT_TO_PTR(X) ((void*)(X))
|
|
|
|
#define SX_PTR_TO_INT(X) ((int)(X))
|
|
|
|
#endif
|
|
|
|
#define SXMIN(a,b) ((a < b) ? (a) : (b))
|
|
|
|
#define SXMAX(a,b) ((a < b) ? (b) : (a))
|
|
|
|
#endif /* SYMISC_STD_TYPES */
|
|
|
|
/* Symisc Run-time API private definitions */
|
|
|
|
#if !defined(SYMISC_PRIVATE_DEFS)
|
|
|
|
#define SYMISC_PRIVATE_DEFS
|
|
|
|
|
|
|
|
typedef sxi32(*ProcRawStrCmp)(const SyString *, const SyString *);
|
|
|
|
#define SyStringData(RAW) ((RAW)->zString)
|
|
|
|
#define SyStringLength(RAW) ((RAW)->nByte)
|
|
|
|
#define SyStringInitFromBuf(RAW,ZBUF,NLEN){\
|
|
|
|
(RAW)->zString = (const char *)ZBUF;\
|
|
|
|
(RAW)->nByte = (sxu32)(NLEN);\
|
|
|
|
}
|
|
|
|
#define SyStringUpdatePtr(RAW,NBYTES){\
|
|
|
|
if( NBYTES > (RAW)->nByte ){\
|
|
|
|
(RAW)->nByte = 0;\
|
|
|
|
}else{\
|
|
|
|
(RAW)->zString += NBYTES;\
|
|
|
|
(RAW)->nByte -= NBYTES;\
|
|
|
|
}\
|
|
|
|
}
|
|
|
|
#define SyStringDupPtr(RAW1,RAW2)\
|
|
|
|
(RAW1)->zString = (RAW2)->zString;\
|
|
|
|
(RAW1)->nByte = (RAW2)->nByte;
|
|
|
|
|
|
|
|
#define SyStringTrimLeadingChar(RAW,CHAR)\
|
|
|
|
while((RAW)->nByte > 0 && (RAW)->zString[0] == CHAR ){\
|
|
|
|
(RAW)->zString++;\
|
|
|
|
(RAW)->nByte--;\
|
|
|
|
}
|
|
|
|
#define SyStringTrimTrailingChar(RAW,CHAR)\
|
|
|
|
while((RAW)->nByte > 0 && (RAW)->zString[(RAW)->nByte - 1] == CHAR){\
|
|
|
|
(RAW)->nByte--;\
|
|
|
|
}
|
|
|
|
#define SyStringCmp(RAW1,RAW2,xCMP)\
|
|
|
|
(((RAW1)->nByte == (RAW2)->nByte) ? xCMP((RAW1)->zString,(RAW2)->zString,(RAW2)->nByte) : (sxi32)((RAW1)->nByte - (RAW2)->nByte))
|
|
|
|
|
|
|
|
#define SyStringCmp2(RAW1,RAW2,xCMP)\
|
|
|
|
(((RAW1)->nByte >= (RAW2)->nByte) ? xCMP((RAW1)->zString,(RAW2)->zString,(RAW2)->nByte) : (sxi32)((RAW2)->nByte - (RAW1)->nByte))
|
|
|
|
|
|
|
|
#define SyStringCharCmp(RAW,CHAR) \
|
|
|
|
(((RAW)->nByte == sizeof(char)) ? ((RAW)->zString[0] == CHAR ? 0 : CHAR - (RAW)->zString[0]) : ((RAW)->zString[0] == CHAR ? 0 : (RAW)->nByte - sizeof(char)))
|
|
|
|
|
|
|
|
#define SX_ADDR(PTR) ((sxptr)PTR)
|
|
|
|
#define SX_ARRAYSIZE(X) (sizeof(X)/sizeof(X[0]))
|
|
|
|
#define SXUNUSED(P) (P = 0)
|
|
|
|
#define SX_EMPTY(PTR) (PTR == 0)
|
|
|
|
#define SX_EMPTY_STR(STR) (STR == 0 || STR[0] == 0 )
|
|
|
|
typedef struct SyMemBackend SyMemBackend;
|
|
|
|
typedef struct SyBlob SyBlob;
|
|
|
|
typedef struct SySet SySet;
|
|
|
|
/* Standard function signatures */
|
|
|
|
typedef sxi32(*ProcCmp)(const void *, const void *, sxu32);
|
|
|
|
typedef sxi32(*ProcPatternMatch)(const char *, sxu32, const char *, sxu32, sxu32 *);
|
|
|
|
typedef sxi32(*ProcSearch)(const void *, sxu32, const void *, sxu32, ProcCmp, sxu32 *);
|
|
|
|
typedef sxu32(*ProcHash)(const void *, sxu32);
|
|
|
|
typedef sxi32(*ProcHashSum)(const void *, sxu32, unsigned char *, sxu32);
|
|
|
|
typedef sxi32(*ProcSort)(void *, sxu32, sxu32, ProcCmp);
|
|
|
|
#define MACRO_LIST_PUSH(Head,Item)\
|
|
|
|
Item->pNext = Head;\
|
|
|
|
Head = Item;
|
|
|
|
#define MACRO_LD_PUSH(Head,Item)\
|
|
|
|
if( Head == 0 ){\
|
|
|
|
Head = Item;\
|
|
|
|
}else{\
|
|
|
|
Item->pNext = Head;\
|
|
|
|
Head->pPrev = Item;\
|
|
|
|
Head = Item;\
|
|
|
|
}
|
|
|
|
#define MACRO_LD_REMOVE(Head,Item)\
|
|
|
|
if( Head == Item ){\
|
|
|
|
Head = Head->pNext;\
|
|
|
|
}\
|
|
|
|
if( Item->pPrev ){ Item->pPrev->pNext = Item->pNext;}\
|
|
|
|
if( Item->pNext ){ Item->pNext->pPrev = Item->pPrev;}
|
|
|
|
/*
|
|
|
|
* A generic dynamic set.
|
|
|
|
*/
|
|
|
|
struct SySet {
|
|
|
|
SyMemBackend *pAllocator; /* Memory backend */
|
|
|
|
void *pBase; /* Base pointer */
|
|
|
|
sxu32 nUsed; /* Total number of used slots */
|
|
|
|
sxu32 nSize; /* Total number of available slots */
|
|
|
|
sxu32 eSize; /* Size of a single slot */
|
|
|
|
sxu32 nCursor; /* Loop cursor */
|
|
|
|
void *pUserData; /* User private data associated with this container */
|
|
|
|
};
|
|
|
|
#define SySetBasePtr(S) ((S)->pBase)
|
|
|
|
#define SySetBasePtrJump(S,OFFT) (&((char *)(S)->pBase)[OFFT*(S)->eSize])
|
|
|
|
#define SySetUsed(S) ((S)->nUsed)
|
|
|
|
#define SySetSize(S) ((S)->nSize)
|
|
|
|
#define SySetElemSize(S) ((S)->eSize)
|
|
|
|
#define SySetCursor(S) ((S)->nCursor)
|
|
|
|
#define SySetGetAllocator(S) ((S)->pAllocator)
|
|
|
|
#define SySetSetUserData(S,DATA) ((S)->pUserData = DATA)
|
|
|
|
#define SySetGetUserData(S) ((S)->pUserData)
|
|
|
|
/*
|
|
|
|
* A variable length containers for generic data.
|
|
|
|
*/
|
|
|
|
struct SyBlob {
|
|
|
|
SyMemBackend *pAllocator; /* Memory backend */
|
|
|
|
void *pBlob; /* Base pointer */
|
|
|
|
sxu32 nByte; /* Total number of used bytes */
|
|
|
|
sxu32 mByte; /* Total number of available bytes */
|
|
|
|
sxu32 nFlags; /* Blob internal flags,see below */
|
|
|
|
};
|
|
|
|
#define SXBLOB_LOCKED 0x01 /* Blob is locked [i.e: Cannot auto grow] */
|
|
|
|
#define SXBLOB_STATIC 0x02 /* Not allocated from heap */
|
|
|
|
#define SXBLOB_RDONLY 0x04 /* Read-Only data */
|
|
|
|
|
|
|
|
#define SyBlobFreeSpace(BLOB) ((BLOB)->mByte - (BLOB)->nByte)
|
|
|
|
#define SyBlobLength(BLOB) ((BLOB)->nByte)
|
|
|
|
#define SyBlobData(BLOB) ((BLOB)->pBlob)
|
|
|
|
#define SyBlobCurData(BLOB) ((void*)(&((char*)(BLOB)->pBlob)[(BLOB)->nByte]))
|
|
|
|
#define SyBlobDataAt(BLOB,OFFT) ((void *)(&((char *)(BLOB)->pBlob)[OFFT]))
|
|
|
|
#define SyBlobGetAllocator(BLOB) ((BLOB)->pAllocator)
|
|
|
|
|
|
|
|
#define SXMEM_POOL_INCR 3
|
|
|
|
#define SXMEM_POOL_NBUCKETS 12
|
|
|
|
#define SXMEM_BACKEND_MAGIC 0xBAC3E67D
|
|
|
|
#define SXMEM_BACKEND_CORRUPT(BACKEND) (BACKEND == 0 || BACKEND->nMagic != SXMEM_BACKEND_MAGIC)
|
|
|
|
|
|
|
|
#define SXMEM_BACKEND_RETRY 3
|
|
|
|
/* A memory backend subsystem is defined by an instance of the following structures */
|
|
|
|
typedef union SyMemHeader SyMemHeader;
|
|
|
|
typedef struct SyMemBlock SyMemBlock;
|
|
|
|
struct SyMemBlock {
|
|
|
|
SyMemBlock *pNext, *pPrev; /* Chain of allocated memory blocks */
|
|
|
|
#ifdef UNTRUST
|
|
|
|
sxu32 nGuard; /* magic number associated with each valid block,so we
|
|
|
|
* can detect misuse.
|
|
|
|
*/
|
|
|
|
#endif
|
|
|
|
};
|
|
|
|
/*
|
|
|
|
* Header associated with each valid memory pool block.
|
|
|
|
*/
|
|
|
|
union SyMemHeader {
|
|
|
|
SyMemHeader *pNext; /* Next chunk of size 1 << (nBucket + SXMEM_POOL_INCR) in the list */
|
|
|
|
sxu32 nBucket; /* Bucket index in aPool[] */
|
|
|
|
};
|
|
|
|
/* Heap allocation control structure */
|
|
|
|
typedef struct SyMemHeap SyMemHeap;
|
|
|
|
struct SyMemHeap {
|
|
|
|
sxu64 nSize; /* Current memory usage */
|
|
|
|
sxu64 nPeak; /* Peak memory usage */
|
|
|
|
sxu64 nLimit; /* Memory limit */
|
|
|
|
};
|
|
|
|
/* Memory allocation backend container */
|
|
|
|
struct SyMemBackend {
|
|
|
|
const SyMutexMethods *pMutexMethods; /* Mutex methods */
|
|
|
|
const SyMemMethods *pMethods; /* Memory allocation methods */
|
|
|
|
SyMemHeap *pHeap; /* Heap allocation */
|
|
|
|
SyMemBlock *pBlocks; /* List of valid memory blocks */
|
|
|
|
sxu32 nBlock; /* Total number of memory blocks allocated so far */
|
|
|
|
ProcMemError xMemError; /* Out-of memory callback */
|
|
|
|
void *pUserData; /* First arg to xMemError() */
|
|
|
|
SyMutex *pMutex; /* Per instance mutex */
|
|
|
|
sxu32 nMagic; /* Sanity check against misuse */
|
|
|
|
SyMemHeader *apPool[SXMEM_POOL_NBUCKETS + SXMEM_POOL_INCR]; /* Pool of memory chunks */
|
|
|
|
};
|
|
|
|
/* Mutex types */
|
|
|
|
#define SXMUTEX_TYPE_FAST 1
|
|
|
|
#define SXMUTEX_TYPE_RECURSIVE 2
|
|
|
|
#define SXMUTEX_TYPE_STATIC_1 3
|
|
|
|
#define SXMUTEX_TYPE_STATIC_2 4
|
|
|
|
#define SXMUTEX_TYPE_STATIC_3 5
|
|
|
|
#define SXMUTEX_TYPE_STATIC_4 6
|
|
|
|
#define SXMUTEX_TYPE_STATIC_5 7
|
|
|
|
#define SXMUTEX_TYPE_STATIC_6 8
|
|
|
|
|
|
|
|
#define SyMutexGlobalInit(METHOD){\
|
|
|
|
if( (METHOD)->xGlobalInit ){\
|
|
|
|
(METHOD)->xGlobalInit();\
|
|
|
|
}\
|
|
|
|
}
|
|
|
|
#define SyMutexGlobalRelease(METHOD){\
|
|
|
|
if( (METHOD)->xGlobalRelease ){\
|
|
|
|
(METHOD)->xGlobalRelease();\
|
|
|
|
}\
|
|
|
|
}
|
|
|
|
#define SyMutexNew(METHOD,TYPE) (METHOD)->xNew(TYPE)
|
|
|
|
#define SyMutexRelease(METHOD,MUTEX){\
|
|
|
|
if( MUTEX && (METHOD)->xRelease ){\
|
|
|
|
(METHOD)->xRelease(MUTEX);\
|
|
|
|
}\
|
|
|
|
}
|
|
|
|
#define SyMutexEnter(METHOD,MUTEX){\
|
|
|
|
if( MUTEX ){\
|
|
|
|
(METHOD)->xEnter(MUTEX);\
|
|
|
|
}\
|
|
|
|
}
|
|
|
|
#define SyMutexTryEnter(METHOD,MUTEX){\
|
|
|
|
if( MUTEX && (METHOD)->xTryEnter ){\
|
|
|
|
(METHOD)->xTryEnter(MUTEX);\
|
|
|
|
}\
|
|
|
|
}
|
|
|
|
#define SyMutexLeave(METHOD,MUTEX){\
|
|
|
|
if( MUTEX ){\
|
|
|
|
(METHOD)->xLeave(MUTEX);\
|
|
|
|
}\
|
|
|
|
}
|
|
|
|
/* Comparison,byte swap,byte copy macros */
|
|
|
|
#define SX_MACRO_FAST_CMP(X1,X2,SIZE,RC){\
|
|
|
|
register unsigned char *r1 = (unsigned char *)X1;\
|
|
|
|
register unsigned char *r2 = (unsigned char *)X2;\
|
|
|
|
register sxu32 LEN = SIZE;\
|
|
|
|
for(;;){\
|
|
|
|
if( !LEN ){ break; }if( r1[0] != r2[0] ){ break; } r1++; r2++; LEN--;\
|
|
|
|
if( !LEN ){ break; }if( r1[0] != r2[0] ){ break; } r1++; r2++; LEN--;\
|
|
|
|
if( !LEN ){ break; }if( r1[0] != r2[0] ){ break; } r1++; r2++; LEN--;\
|
|
|
|
if( !LEN ){ break; }if( r1[0] != r2[0] ){ break; } r1++; r2++; LEN--;\
|
|
|
|
}\
|
|
|
|
RC = !LEN ? 0 : r1[0] - r2[0];\
|
|
|
|
}
|
|
|
|
#define SX_MACRO_FAST_MEMCPY(SRC,DST,SIZ){\
|
|
|
|
register unsigned char *xSrc = (unsigned char *)SRC;\
|
|
|
|
register unsigned char *xDst = (unsigned char *)DST;\
|
|
|
|
register sxu32 xLen = SIZ;\
|
|
|
|
for(;;){\
|
|
|
|
if( !xLen ){ break; }xDst[0] = xSrc[0]; xDst++; xSrc++; --xLen;\
|
|
|
|
if( !xLen ){ break; }xDst[0] = xSrc[0]; xDst++; xSrc++; --xLen;\
|
|
|
|
if( !xLen ){ break; }xDst[0] = xSrc[0]; xDst++; xSrc++; --xLen;\
|
|
|
|
if( !xLen ){ break; }xDst[0] = xSrc[0]; xDst++; xSrc++; --xLen;\
|
|
|
|
}\
|
|
|
|
}
|
|
|
|
#define SX_MACRO_BYTE_SWAP(X,Y,Z){\
|
|
|
|
register unsigned char *s = (unsigned char *)X;\
|
|
|
|
register unsigned char *d = (unsigned char *)Y;\
|
|
|
|
sxu32 ZLong = Z; \
|
|
|
|
sxi32 c; \
|
|
|
|
for(;;){\
|
|
|
|
if(!ZLong){ break; } c = s[0] ; s[0] = d[0]; d[0] = (unsigned char)c; s++; d++; --ZLong;\
|
|
|
|
if(!ZLong){ break; } c = s[0] ; s[0] = d[0]; d[0] = (unsigned char)c; s++; d++; --ZLong;\
|
|
|
|
if(!ZLong){ break; } c = s[0] ; s[0] = d[0]; d[0] = (unsigned char)c; s++; d++; --ZLong;\
|
|
|
|
if(!ZLong){ break; } c = s[0] ; s[0] = d[0]; d[0] = (unsigned char)c; s++; d++; --ZLong;\
|
|
|
|
}\
|
|
|
|
}
|
|
|
|
#define SX_MSEC_PER_SEC (1000) /* Millisec per seconds */
|
|
|
|
#define SX_USEC_PER_SEC (1000000) /* Microsec per seconds */
|
|
|
|
#define SX_NSEC_PER_SEC (1000000000) /* Nanosec per seconds */
|
|
|
|
#endif /* SYMISC_PRIVATE_DEFS */
|
|
|
|
/* Symisc Run-time API auxiliary definitions */
|
|
|
|
#if !defined(SYMISC_PRIVATE_AUX_DEFS)
|
|
|
|
#define SYMISC_PRIVATE_AUX_DEFS
|
|
|
|
|
|
|
|
typedef struct SyHashEntry_Pr SyHashEntry_Pr;
|
|
|
|
typedef struct SyHashEntry SyHashEntry;
|
|
|
|
typedef struct SyHash SyHash;
|
|
|
|
/*
|
|
|
|
* Each public hashtable entry is represented by an instance
|
|
|
|
* of the following structure.
|
|
|
|
*/
|
|
|
|
struct SyHashEntry {
|
|
|
|
const void *pKey; /* Hash key */
|
|
|
|
sxu32 nKeyLen; /* Key length */
|
|
|
|
void *pUserData; /* User private data */
|
|
|
|
};
|
|
|
|
#define SyHashEntryGetUserData(ENTRY) ((ENTRY)->pUserData)
|
|
|
|
#define SyHashEntryGetKey(ENTRY) ((ENTRY)->pKey)
|
|
|
|
/* Each active hashtable is identified by an instance of the following structure */
|
|
|
|
struct SyHash {
|
|
|
|
SyMemBackend *pAllocator; /* Memory backend */
|
|
|
|
ProcHash xHash; /* Hash function */
|
|
|
|
ProcCmp xCmp; /* Comparison function */
|
|
|
|
SyHashEntry_Pr *pList, *pCurrent; /* Linked list of hash entries user for linear traversal */
|
|
|
|
sxu32 nEntry; /* Total number of entries */
|
|
|
|
SyHashEntry_Pr **apBucket; /* Hash buckets */
|
|
|
|
sxu32 nBucketSize; /* Current bucket size */
|
|
|
|
};
|
|
|
|
#define SXHASH_BUCKET_SIZE 16 /* Initial bucket size: must be a power of two */
|
|
|
|
#define SXHASH_FILL_FACTOR 3
|
|
|
|
/* Hash access macro */
|
|
|
|
#define SyHashFunc(HASH) ((HASH)->xHash)
|
|
|
|
#define SyHashCmpFunc(HASH) ((HASH)->xCmp)
|
|
|
|
#define SyHashTotalEntry(HASH) ((HASH)->nEntry)
|
|
|
|
#define SyHashGetPool(HASH) ((HASH)->pAllocator)
|
|
|
|
/*
|
|
|
|
* An instance of the following structure define a single context
|
|
|
|
* for an Pseudo Random Number Generator.
|
|
|
|
*
|
|
|
|
* Nothing in this file or anywhere else in the library does any kind of
|
|
|
|
* encryption. The RC4 algorithm is being used as a PRNG (pseudo-random
|
|
|
|
* number generator) not as an encryption device.
|
|
|
|
* This implementation is taken from the SQLite3 source tree.
|
|
|
|
*/
|
|
|
|
typedef struct SyPRNGCtx SyPRNGCtx;
|
|
|
|
struct SyPRNGCtx {
|
|
|
|
sxu8 i, j; /* State variables */
|
|
|
|
unsigned char s[256]; /* State variables */
|
|
|
|
sxu16 nMagic; /* Sanity check */
|
|
|
|
};
|
|
|
|
typedef sxi32(*ProcRandomSeed)(void *, unsigned int, void *);
|
|
|
|
/* High resolution timer.*/
|
|
|
|
typedef struct sytime sytime;
|
|
|
|
struct sytime {
|
|
|
|
long tm_sec; /* seconds */
|
|
|
|
long tm_usec; /* microseconds */
|
|
|
|
};
|
|
|
|
/* Forward declaration */
|
|
|
|
typedef struct SyStream SyStream;
|
|
|
|
typedef struct SyToken SyToken;
|
|
|
|
typedef struct SyLex SyLex;
|
|
|
|
/*
|
|
|
|
* Tokenizer callback signature.
|
|
|
|
*/
|
|
|
|
typedef sxi32(*ProcTokenizer)(SyStream *, SyToken *, void *, void *);
|
|
|
|
/*
|
|
|
|
* Each token in the input is represented by an instance
|
|
|
|
* of the following structure.
|
|
|
|
*/
|
|
|
|
struct SyToken {
|
|
|
|
SyString sData; /* Token text and length */
|
|
|
|
sxu32 nType; /* Token type */
|
|
|
|
sxu32 nLine; /* Token line number */
|
|
|
|
void *pUserData; /* User private data associated with this token */
|
|
|
|
};
|
|
|
|
/*
|
|
|
|
* During tokenization, information about the state of the input
|
|
|
|
* stream is held in an instance of the following structure.
|
|
|
|
*/
|
|
|
|
struct SyStream {
|
|
|
|
const unsigned char *zInput; /* Complete text of the input */
|
|
|
|
const unsigned char *zText; /* Current input we are processing */
|
|
|
|
const unsigned char *zEnd; /* End of input marker */
|
|
|
|
sxu32 nLine; /* Total number of processed lines */
|
|
|
|
sxu32 nIgn; /* Total number of ignored tokens */
|
|
|
|
SySet *pSet; /* Token containers */
|
|
|
|
};
|
|
|
|
/*
|
|
|
|
* Each lexer is represented by an instance of the following structure.
|
|
|
|
*/
|
|
|
|
struct SyLex {
|
|
|
|
SyStream sStream; /* Input stream */
|
|
|
|
ProcTokenizer xTokenizer; /* Tokenizer callback */
|
|
|
|
void *pUserData; /* Third argument to xTokenizer() */
|
|
|
|
SySet *pTokenSet; /* Token set */
|
|
|
|
};
|
|
|
|
#define SyLexTotalToken(LEX) SySetTotalEntry(&(LEX)->aTokenSet)
|
|
|
|
#define SyLexTotalLines(LEX) ((LEX)->sStream.nLine)
|
|
|
|
#define SyLexTotalIgnored(LEX) ((LEX)->sStream.nIgn)
|
|
|
|
#define XLEX_IN_LEN(STREAM) (sxu32)(STREAM->zEnd - STREAM->zText)
|
|
|
|
#endif /* SYMISC_PRIVATE_AUX_DEFS */
|
|
|
|
/*
|
|
|
|
** Notes on UTF-8 (According to SQLite3 authors):
|
|
|
|
**
|
|
|
|
** Byte-0 Byte-1 Byte-2 Byte-3 Value
|
|
|
|
** 0xxxxxxx 00000000 00000000 0xxxxxxx
|
|
|
|
** 110yyyyy 10xxxxxx 00000000 00000yyy yyxxxxxx
|
|
|
|
** 1110zzzz 10yyyyyy 10xxxxxx 00000000 zzzzyyyy yyxxxxxx
|
|
|
|
** 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx 000uuuuu zzzzyyyy yyxxxxxx
|
|
|
|
**
|
|
|
|
*/
|
|
|
|
/*
|
|
|
|
** Assuming zIn points to the first byte of a UTF-8 character,
|
|
|
|
** advance zIn to point to the first byte of the next UTF-8 character.
|
|
|
|
*/
|
|
|
|
#define SX_JMP_UTF8(zIn,zEnd)\
|
|
|
|
while(zIn < zEnd && (((unsigned char)zIn[0] & 0xc0) == 0x80) ){ zIn++; }
|
|
|
|
#define SX_WRITE_UTF8(zOut, c) { \
|
|
|
|
if( c<0x00080 ){ \
|
|
|
|
*zOut++ = (sxu8)(c&0xFF); \
|
|
|
|
}else if( c<0x00800 ){ \
|
|
|
|
*zOut++ = 0xC0 + (sxu8)((c>>6)&0x1F); \
|
|
|
|
*zOut++ = 0x80 + (sxu8)(c & 0x3F); \
|
|
|
|
}else if( c<0x10000 ){ \
|
|
|
|
*zOut++ = 0xE0 + (sxu8)((c>>12)&0x0F); \
|
|
|
|
*zOut++ = 0x80 + (sxu8)((c>>6) & 0x3F); \
|
|
|
|
*zOut++ = 0x80 + (sxu8)(c & 0x3F); \
|
|
|
|
}else{ \
|
|
|
|
*zOut++ = 0xF0 + (sxu8)((c>>18) & 0x07); \
|
|
|
|
*zOut++ = 0x80 + (sxu8)((c>>12) & 0x3F); \
|
|
|
|
*zOut++ = 0x80 + (sxu8)((c>>6) & 0x3F); \
|
|
|
|
*zOut++ = 0x80 + (sxu8)(c & 0x3F); \
|
|
|
|
} \
|
|
|
|
}
|
|
|
|
/* Rely on the standard ctype */
|
|
|
|
#include <ctype.h>
|
|
|
|
#define SyToUpper(c) toupper(c)
|
|
|
|
#define SyToLower(c) tolower(c)
|
|
|
|
#define SyisUpper(c) isupper(c)
|
|
|
|
#define SyisLower(c) islower(c)
|
|
|
|
#define SyisSpace(c) isspace(c)
|
|
|
|
#define SyisBlank(c) isspace(c)
|
|
|
|
#define SyisAlpha(c) isalpha(c)
|
|
|
|
#define SyisDigit(c) isdigit(c)
|
|
|
|
#define SyisHex(c) isxdigit(c)
|
|
|
|
#define SyisPrint(c) isprint(c)
|
|
|
|
#define SyisPunct(c) ispunct(c)
|
|
|
|
#define SyisSpec(c) iscntrl(c)
|
|
|
|
#define SyisCtrl(c) iscntrl(c)
|
|
|
|
#define SyisAscii(c) isascii(c)
|
|
|
|
#define SyisAlphaNum(c) isalnum(c)
|
|
|
|
#define SyisGraph(c) isgraph(c)
|
|
|
|
#define SyDigToHex(c) "0123456789ABCDEF"[c & 0x0F]
|
|
|
|
#define SyDigToInt(c) ((c < 0xc0 && SyisDigit(c))? (c - '0') : 0 )
|
|
|
|
#define SyCharToUpper(c) ((c < 0xc0 && SyisLower(c))? SyToUpper(c) : c)
|
|
|
|
#define SyCharToLower(c) ((c < 0xc0 && SyisUpper(c))? SyToLower(c) : c)
|
|
|
|
/* Remove white space/NUL byte from a raw string */
|
|
|
|
#define SyStringLeftTrim(RAW)\
|
|
|
|
while((RAW)->nByte > 0 && (unsigned char)(RAW)->zString[0] < 0xc0 && SyisSpace((RAW)->zString[0])){\
|
|
|
|
(RAW)->nByte--;\
|
|
|
|
(RAW)->zString++;\
|
|
|
|
}
|
|
|
|
#define SyStringLeftTrimSafe(RAW)\
|
|
|
|
while((RAW)->nByte > 0 && (unsigned char)(RAW)->zString[0] < 0xc0 && ((RAW)->zString[0] == 0 || SyisSpace((RAW)->zString[0]))){\
|
|
|
|
(RAW)->nByte--;\
|
|
|
|
(RAW)->zString++;\
|
|
|
|
}
|
|
|
|
#define SyStringRightTrim(RAW)\
|
|
|
|
while((RAW)->nByte > 0 && (unsigned char)(RAW)->zString[(RAW)->nByte - 1] < 0xc0 && SyisSpace((RAW)->zString[(RAW)->nByte - 1])){\
|
|
|
|
(RAW)->nByte--;\
|
|
|
|
}
|
|
|
|
#define SyStringRightTrimSafe(RAW)\
|
|
|
|
while((RAW)->nByte > 0 && (unsigned char)(RAW)->zString[(RAW)->nByte - 1] < 0xc0 && \
|
|
|
|
(( RAW)->zString[(RAW)->nByte - 1] == 0 || SyisSpace((RAW)->zString[(RAW)->nByte - 1]))){\
|
|
|
|
(RAW)->nByte--;\
|
|
|
|
}
|
|
|
|
|
|
|
|
#define SyStringFullTrim(RAW)\
|
|
|
|
while((RAW)->nByte > 0 && (unsigned char)(RAW)->zString[0] < 0xc0 && SyisSpace((RAW)->zString[0])){\
|
|
|
|
(RAW)->nByte--;\
|
|
|
|
(RAW)->zString++;\
|
|
|
|
}\
|
|
|
|
while((RAW)->nByte > 0 && (unsigned char)(RAW)->zString[(RAW)->nByte - 1] < 0xc0 && SyisSpace((RAW)->zString[(RAW)->nByte - 1])){\
|
|
|
|
(RAW)->nByte--;\
|
|
|
|
}
|
|
|
|
#define SyStringFullTrimSafe(RAW)\
|
|
|
|
while((RAW)->nByte > 0 && (unsigned char)(RAW)->zString[0] < 0xc0 && \
|
|
|
|
( (RAW)->zString[0] == 0 || SyisSpace((RAW)->zString[0]))){\
|
|
|
|
(RAW)->nByte--;\
|
|
|
|
(RAW)->zString++;\
|
|
|
|
}\
|
|
|
|
while((RAW)->nByte > 0 && (unsigned char)(RAW)->zString[(RAW)->nByte - 1] < 0xc0 && \
|
|
|
|
( (RAW)->zString[(RAW)->nByte - 1] == 0 || SyisSpace((RAW)->zString[(RAW)->nByte - 1]))){\
|
|
|
|
(RAW)->nByte--;\
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* --------------
|
|
|
|
* Archive extractor:
|
|
|
|
* --------------
|
|
|
|
* Each open ZIP/TAR archive is identified by an instance of the following structure.
|
|
|
|
* That is, a process can open one or more archives and manipulates them in thread safe
|
|
|
|
* way by simply working with pointers to the following structure.
|
|
|
|
* Each entry in the archive is remembered in a hashtable.
|
|
|
|
* Lookup is very fast and entry with the same name are chained together.
|
|
|
|
*/
|
|
|
|
typedef struct SyArchiveEntry SyArchiveEntry;
|
|
|
|
typedef struct SyArchive SyArchive;
|
|
|
|
struct SyArchive {
|
|
|
|
SyMemBackend *pAllocator; /* Memory backend */
|
|
|
|
SyArchiveEntry *pCursor; /* Cursor for linear traversal of archive entries */
|
|
|
|
SyArchiveEntry *pList; /* Pointer to the List of the loaded archive */
|
|
|
|
SyArchiveEntry **apHash; /* Hashtable for archive entry */
|
|
|
|
ProcRawStrCmp xCmp; /* Hash comparison function */
|
|
|
|
ProcHash xHash; /* Hash Function */
|
|
|
|
sxu32 nSize; /* Hashtable size */
|
|
|
|
sxu32 nEntry; /* Total number of entries in the zip/tar archive */
|
|
|
|
sxu32 nLoaded; /* Total number of entries loaded in memory */
|
|
|
|
sxu32 nCentralOfft; /* Central directory offset(ZIP only. Otherwise Zero) */
|
|
|
|
sxu32 nCentralSize; /* Central directory size(ZIP only. Otherwise Zero) */
|
|
|
|
void *pUserData; /* Upper layer private data */
|
|
|
|
sxu32 nMagic; /* Sanity check */
|
|
|
|
|
|
|
|
};
|
|
|
|
#define SXARCH_MAGIC 0xDEAD635A
|
|
|
|
#define SXARCH_INVALID(ARCH) (ARCH == 0 || ARCH->nMagic != SXARCH_MAGIC)
|
|
|
|
#define SXARCH_ENTRY_INVALID(ENTRY) (ENTRY == 0 || ENTRY->nMagic != SXARCH_MAGIC)
|
|
|
|
#define SyArchiveHashFunc(ARCH) (ARCH)->xHash
|
|
|
|
#define SyArchiveCmpFunc(ARCH) (ARCH)->xCmp
|
|
|
|
#define SyArchiveUserData(ARCH) (ARCH)->pUserData
|
|
|
|
#define SyArchiveSetUserData(ARCH,DATA) (ARCH)->pUserData = DATA
|
|
|
|
/*
|
|
|
|
* Each loaded archive record is identified by an instance
|
|
|
|
* of the following structure.
|
|
|
|
*/
|
|
|
|
struct SyArchiveEntry {
|
|
|
|
sxu32 nByte; /* Contents size before compression */
|
|
|
|
sxu32 nByteCompr; /* Contents size after compression */
|
|
|
|
sxu32 nReadCount; /* Read counter */
|
|
|
|
sxu32 nCrc; /* Contents CRC32 */
|
|
|
|
Sytm sFmt; /* Last-modification time */
|
|
|
|
sxu32 nOfft; /* Data offset. */
|
|
|
|
sxu16 nComprMeth; /* Compression method 0 == stored/8 == deflated and so on (see appnote.txt)*/
|
|
|
|
sxu16 nExtra; /* Extra size if any */
|
|
|
|
SyString sFileName; /* entry name & length */
|
|
|
|
sxu32 nDup; /* Total number of entries with the same name */
|
|
|
|
SyArchiveEntry *pNextHash, *pPrevHash; /* Hash collision chains */
|
|
|
|
SyArchiveEntry *pNextName; /* Next entry with the same name */
|
|
|
|
SyArchiveEntry *pNext, *pPrev; /* Next and previous entry in the list */
|
|
|
|
sxu32 nHash; /* Hash of the entry name */
|
|
|
|
void *pUserData; /* User data */
|
|
|
|
sxu32 nMagic; /* Sanity check */
|
|
|
|
};
|
|
|
|
/*
|
|
|
|
* Extra flags for extending the file local header
|
|
|
|
*/
|
|
|
|
#define SXZIP_EXTRA_TIMESTAMP 0x001 /* Extended UNIX timestamp */
|
|
|
|
/* MD5 context */
|
|
|
|
typedef struct MD5Context MD5Context;
|
|
|
|
struct MD5Context {
|
|
|
|
sxu32 buf[4];
|
|
|
|
sxu32 bits[2];
|
|
|
|
unsigned char in[64];
|
|
|
|
};
|
|
|
|
/* SHA1 context */
|
|
|
|
typedef struct SHA1Context SHA1Context;
|
|
|
|
struct SHA1Context {
|
|
|
|
unsigned int state[5];
|
|
|
|
unsigned int count[2];
|
|
|
|
unsigned char buffer[64];
|
|
|
|
};
|
|
|
|
/* PH7 private declaration */
|
|
|
|
/*
|
|
|
|
* Memory Objects.
|
|
|
|
* Internally, the PH7 virtual machine manipulates nearly all PHP values
|
|
|
|
* [i.e: string, int, float, resource, object, bool, null] as ph7_values structures.
|
|
|
|
* Each ph7_values struct may cache multiple representations (string, integer etc.)
|
|
|
|
* of the same value.
|
|
|
|
*/
|
|
|
|
struct ph7_value {
|
|
|
|
union {
|
|
|
|
sxi64 iVal; /* Integer value */
|
|
|
|
ph7_real rVal; /* Real value */
|
|
|
|
void *pOther; /* Other values (Object, Array, Resource, Namespace, etc.) */
|
|
|
|
} x;
|
|
|
|
sxi32 iFlags; /* Control flags (see below) */
|
|
|
|
ph7_vm *pVm; /* Virtual machine that own this instance */
|
|
|
|
SyBlob sBlob; /* String values */
|
|
|
|
sxu32 nIdx; /* Index number of this entry in the global object allocator */
|
|
|
|
};
|
|
|
|
/* Allowed value types.
|
|
|
|
*/
|
|
|
|
#define MEMOBJ_BOOL 0x0001 /* Memory value is a boolean */
|
|
|
|
#define MEMOBJ_CALL 0x0002 /* Memory value is a callback */
|
|
|
|
#define MEMOBJ_CHAR 0x0004 /* Memory value is a char */
|
|
|
|
#define MEMOBJ_INT 0x0008 /* Memory value is an integer */
|
|
|
|
#define MEMOBJ_OBJ 0x0010 /* Memory value is an object [i.e: class instance] */
|
|
|
|
#define MEMOBJ_REAL 0x0020 /* Memory value is a real number */
|
|
|
|
#define MEMOBJ_RES 0x0040 /* Memory value is a resource [User private data] */
|
|
|
|
#define MEMOBJ_STRING 0x0080 /* Memory value is a UTF-8 string */
|
|
|
|
#define MEMOBJ_VOID 0x0100 /* Memory value is a void */
|
|
|
|
#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_NULL 0x1000 /* Memory value is NULL */
|
|
|
|
/* Mask of all known types */
|
|
|
|
#define MEMOBJ_ALL (MEMOBJ_STRING|MEMOBJ_INT|MEMOBJ_REAL|MEMOBJ_BOOL|MEMOBJ_NULL|MEMOBJ_HASHMAP|MEMOBJ_OBJ|MEMOBJ_RES|MEMOBJ_CALL|MEMOBJ_CHAR|MEMOBJ_VOID)
|
|
|
|
/* Scalar variables
|
|
|
|
* According to the PHP language reference manual
|
|
|
|
* Scalar variables are those containing an integer, float, string or boolean.
|
|
|
|
* 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_AUX (MEMOBJ_REFERENCE)
|
|
|
|
/*
|
|
|
|
* The following macro clear the current ph7_value type and replace
|
|
|
|
* it with the given one.
|
|
|
|
*/
|
|
|
|
#define MemObjSetType(OBJ,TYPE) ((OBJ)->iFlags = ((OBJ)->iFlags&~MEMOBJ_ALL)|TYPE)
|
|
|
|
/* ph7_value cast method signature */
|
|
|
|
typedef sxi32(*ProcMemObjCast)(ph7_value *);
|
|
|
|
/* Forward reference */
|
|
|
|
typedef struct ph7_output_consumer ph7_output_consumer;
|
|
|
|
typedef struct ph7_user_func ph7_user_func;
|
|
|
|
typedef struct ph7_conf ph7_conf;
|
|
|
|
/*
|
|
|
|
* An instance of the following structure store the default VM output
|
|
|
|
* consumer and it's private data.
|
|
|
|
* Client-programs can register their own output consumer callback
|
|
|
|
* via the [PH7_VM_CONFIG_OUTPUT] configuration directive.
|
|
|
|
* Please refer to the official documentation for more information
|
|
|
|
* on how to register an output consumer callback.
|
|
|
|
*/
|
|
|
|
struct ph7_output_consumer {
|
|
|
|
ProcConsumer xConsumer; /* VM output consumer routine */
|
|
|
|
void *pUserData; /* Third argument to xConsumer() */
|
|
|
|
ProcConsumer xDef; /* Default output consumer routine */
|
|
|
|
void *pDefData; /* Third argument to xDef() */
|
|
|
|
};
|
|
|
|
/*
|
|
|
|
* PH7 engine [i.e: ph7 instance] configuration is stored in
|
|
|
|
* an instance of the following structure.
|
|
|
|
* Please refer to the official documentation for more information
|
|
|
|
* on how to configure your ph7 engine instance.
|
|
|
|
*/
|
|
|
|
struct ph7_conf {
|
|
|
|
ProcConsumer xErr; /* Compile-time error consumer callback */
|
|
|
|
void *pErrData; /* Third argument to xErr() */
|
|
|
|
SyBlob sErrConsumer; /* Default error consumer */
|
|
|
|
};
|
|
|
|
/*
|
|
|
|
* Signature of the C function responsible of expanding constant values.
|
|
|
|
*/
|
|
|
|
typedef void (*ProcConstant)(ph7_value *, void *);
|
|
|
|
/*
|
|
|
|
* Each registered constant [i.e: __TIME__, __DATE__, PHP_OS, INT_MAX, etc.] is stored
|
|
|
|
* in an instance of the following structure.
|
|
|
|
* Please refer to the official documentation for more information
|
|
|
|
* on how to create/install foreign constants.
|
|
|
|
*/
|
|
|
|
typedef struct ph7_constant ph7_constant;
|
|
|
|
struct ph7_constant {
|
|
|
|
SyString sName; /* Constant name */
|
|
|
|
ProcConstant xExpand; /* Function responsible of expanding constant value */
|
|
|
|
void *pUserData; /* Last argument to xExpand() */
|
|
|
|
};
|
|
|
|
typedef struct ph7_aux_data ph7_aux_data;
|
|
|
|
/*
|
|
|
|
* Auxiliary data associated with each foreign function is stored
|
|
|
|
* in a stack of the following structure.
|
|
|
|
* Note that automatic tracked chunks are also stored in an instance
|
|
|
|
* of this structure.
|
|
|
|
*/
|
|
|
|
struct ph7_aux_data {
|
|
|
|
void *pAuxData; /* Aux data */
|
|
|
|
};
|
|
|
|
/* Foreign functions signature */
|
|
|
|
typedef int (*ProcHostFunction)(ph7_context *, int, ph7_value **);
|
|
|
|
/*
|
|
|
|
* Each installed foreign function is recored in an instance of the following
|
|
|
|
* structure.
|
|
|
|
* Please refer to the official documentation for more information on how
|
|
|
|
* to create/install foreign functions.
|
|
|
|
*/
|
|
|
|
struct ph7_user_func {
|
|
|
|
ph7_vm *pVm; /* VM that own this instance */
|
|
|
|
SyString sName; /* Foreign function name */
|
|
|
|
ProcHostFunction xFunc; /* Implementation of the foreign function */
|
|
|
|
void *pUserData; /* User private data [Refer to the official documentation for more information]*/
|
|
|
|
SySet aAux; /* Stack of auxiliary data [Refer to the official documentation for more information]*/
|
|
|
|
};
|
|
|
|
/*
|
|
|
|
* The 'context' argument for an installable function. A pointer to an
|
|
|
|
* instance of this structure is the first argument to the routines used
|
|
|
|
* implement the foreign functions.
|
|
|
|
*/
|
|
|
|
struct ph7_context {
|
|
|
|
ph7_user_func *pFunc; /* Function information. */
|
|
|
|
ph7_value *pRet; /* Return value is stored here. */
|
|
|
|
SySet sVar; /* Container of dynamically allocated ph7_values
|
|
|
|
* [i.e: Garbage collection purposes.]
|
|
|
|
*/
|
|
|
|
SySet sChunk; /* Track dynamically allocated chunks [ph7_aux_data instance].
|
|
|
|
* [i.e: Garbage collection purposes.]
|
|
|
|
*/
|
|
|
|
ph7_vm *pVm; /* Virtual machine that own this context */
|
|
|
|
sxi32 iFlags; /* Call flags */
|
|
|
|
};
|
|
|
|
/*
|
|
|
|
* Each hashmap entry [i.e: array(4,5,6)] is recorded in an instance
|
|
|
|
* of the following structure.
|
|
|
|
*/
|
|
|
|
struct ph7_hashmap_node {
|
|
|
|
ph7_hashmap *pMap; /* Hashmap that own this instance */
|
|
|
|
sxi32 iType; /* Node type */
|
|
|
|
union {
|
|
|
|
sxi64 iKey; /* Int key */
|
|
|
|
SyBlob sKey; /* Blob key */
|
|
|
|
} xKey;
|
|
|
|
sxi32 iFlags; /* Control flags */
|
|
|
|
sxu32 nHash; /* Key hash value */
|
|
|
|
sxu32 nValIdx; /* Value stored in this node */
|
|
|
|
ph7_hashmap_node *pNext, *pPrev; /* Link to other entries [i.e: linear traversal] */
|
|
|
|
ph7_hashmap_node *pNextCollide, *pPrevCollide; /* Collision chain */
|
|
|
|
};
|
|
|
|
/*
|
|
|
|
* Each active hashmap aka array in the PHP jargon is represented
|
|
|
|
* by an instance of the following structure.
|
|
|
|
*/
|
|
|
|
struct ph7_hashmap {
|
|
|
|
ph7_vm *pVm; /* VM that own this instance */
|
|
|
|
ph7_hashmap_node **apBucket; /* Hash bucket */
|
|
|
|
ph7_hashmap_node *pFirst; /* First inserted entry */
|
|
|
|
ph7_hashmap_node *pLast; /* Last inserted entry */
|
|
|
|
ph7_hashmap_node *pCur; /* Current entry */
|
|
|
|
sxu32 nSize; /* Bucket size */
|
|
|
|
sxu32 nEntry; /* Total number of inserted entries */
|
|
|
|
sxu32(*xIntHash)(sxi64); /* Hash function for int_keys */
|
|
|
|
sxu32(*xBlobHash)(const void *, sxu32); /* Hash function for blob_keys */
|
|
|
|
sxi64 iNextIdx; /* Next available automatically assigned index */
|
|
|
|
sxi32 iRef; /* Reference count */
|
|
|
|
};
|
|
|
|
/* An instance of the following structure is the context
|
|
|
|
* for the FOREACH_STEP/FOREACH_INIT VM instructions.
|
|
|
|
* Those instructions are used to implement the 'foreach'
|
|
|
|
* statement.
|
|
|
|
* This structure is made available to these instructions
|
|
|
|
* as the P3 operand.
|
|
|
|
*/
|
|
|
|
struct ph7_foreach_info {
|
|
|
|
SyString sKey; /* Key name. Empty otherwise*/
|
|
|
|
SyString sValue; /* Value name */
|
|
|
|
sxi32 iFlags; /* Control flags */
|
|
|
|
SySet aStep; /* Stack of steps [i.e: ph7_foreach_step instance] */
|
|
|
|
};
|
|
|
|
struct ph7_foreach_step {
|
|
|
|
sxi32 iFlags; /* Control flags (see below) */
|
|
|
|
/* Iterate on those values */
|
|
|
|
union {
|
|
|
|
ph7_hashmap *pMap; /* Hashmap [i.e: array in the PHP jargon] iteration
|
|
|
|
* Ex: foreach(array(1,2,3) as $key=>$value){}
|
|
|
|
*/
|
|
|
|
ph7_class_instance *pThis; /* Class instance [i.e: object] iteration */
|
|
|
|
} xIter;
|
|
|
|
};
|
|
|
|
/* Foreach step control flags */
|
|
|
|
#define PH7_4EACH_STEP_HASHMAP 0x001 /* Hashmap iteration */
|
|
|
|
#define PH7_4EACH_STEP_OBJECT 0x002 /* Object iteration */
|
|
|
|
#define PH7_4EACH_STEP_KEY 0x004 /* Make Key available */
|
|
|
|
#define PH7_4EACH_STEP_REF 0x008 /* Pass value by reference not copy */
|
|
|
|
/*
|
|
|
|
* Each PH7 engine is identified by an instance of the following structure.
|
|
|
|
* Please refer to the official documentation for more information
|
|
|
|
* on how to configure your PH7 engine instance.
|
|
|
|
*/
|
|
|
|
struct ph7 {
|
|
|
|
SyMemBackend sAllocator; /* Low level memory allocation subsystem */
|
|
|
|
const ph7_vfs *pVfs; /* Underlying Virtual File System */
|
|
|
|
ph7_conf xConf; /* Configuration */
|
|
|
|
#if defined(PH7_ENABLE_THREADS)
|
|
|
|
const SyMutexMethods *pMethods; /* Mutex methods */
|
|
|
|
SyMutex *pMutex; /* Per-engine mutex */
|
|
|
|
#endif
|
|
|
|
ph7_vm *pVms; /* List of active VM */
|
|
|
|
sxi32 iVm; /* Total number of active VM */
|
|
|
|
ph7 *pNext, *pPrev; /* List of active engines */
|
|
|
|
sxu32 nMagic; /* Sanity check against misuse */
|
|
|
|
};
|
|
|
|
/* Code generation data structures */
|
|
|
|
typedef sxi32(*ProcErrorGen)(void *, sxi32, sxu32, const char *, ...);
|
|
|
|
typedef struct ph7_expr_node ph7_expr_node;
|
|
|
|
typedef struct ph7_expr_op ph7_expr_op;
|
|
|
|
typedef struct ph7_gen_state ph7_gen_state;
|
|
|
|
typedef struct GenBlock GenBlock;
|
|
|
|
typedef sxi32(*ProcLangConstruct)(ph7_gen_state *);
|
|
|
|
typedef sxi32(*ProcNodeConstruct)(ph7_gen_state *, sxi32);
|
|
|
|
/*
|
|
|
|
* Each supported operator [i.e: +, -, ==, *, %, >>, >=, new, etc.] is represented
|
|
|
|
* by an instance of the following structure.
|
|
|
|
* The PH7 parser does not use any external tools and is 100% handcoded.
|
|
|
|
* That is, the PH7 parser is thread-safe ,full reentrant, produce consistant
|
|
|
|
* compile-time errors and at least 7 times faster than the standard PHP parser.
|
|
|
|
*/
|
|
|
|
struct ph7_expr_op {
|
|
|
|
SyString sOp; /* String representation of the operator [i.e: "+","*","=="...] */
|
|
|
|
sxi32 iOp; /* Operator ID */
|
|
|
|
sxi32 iPrec; /* Operator precedence: 1 == Highest */
|
|
|
|
sxi32 iAssoc; /* Operator associativity (either left,right or non-associative) */
|
|
|
|
sxi32 iVmOp; /* VM OP code for this operator [i.e: PH7_OP_EQ,PH7_OP_LT,PH7_OP_MUL...]*/
|
|
|
|
};
|
|
|
|
/*
|
|
|
|
* Each expression node is parsed out and recorded
|
|
|
|
* in an instance of the following structure.
|
|
|
|
*/
|
|
|
|
struct ph7_expr_node {
|
|
|
|
const ph7_expr_op *pOp; /* Operator ID or NULL if literal, constant, variable, function or class method call */
|
|
|
|
ph7_expr_node *pLeft; /* Left expression tree */
|
|
|
|
ph7_expr_node *pRight; /* Right expression tree */
|
|
|
|
SyToken *pStart; /* Stream of tokens that belong to this node */
|
|
|
|
SyToken *pEnd; /* End of token stream */
|
|
|
|
sxi32 iFlags; /* Node construct flags */
|
|
|
|
ProcNodeConstruct xCode; /* C routine responsible of compiling this node */
|
|
|
|
SySet aNodeArgs; /* Node arguments. Only used by postfix operators [i.e: function call]*/
|
|
|
|
ph7_expr_node *pCond; /* Condition: Only used by the ternary operator '?:' */
|
|
|
|
};
|
|
|
|
/* Node Construct flags */
|
|
|
|
#define EXPR_NODE_PRE_INCR 0x01 /* Pre-increment/decrement [i.e: ++$i,--$j] node */
|
|
|
|
/*
|
|
|
|
* A block of instructions is recorded in an instance of the following structure.
|
|
|
|
* This structure is used only during compile-time and have no meaning
|
|
|
|
* during bytecode execution.
|
|
|
|
*/
|
|
|
|
struct GenBlock {
|
|
|
|
ph7_gen_state *pGen; /* State of the code generator */
|
|
|
|
GenBlock *pParent; /* Upper block or NULL if global */
|
|
|
|
sxu32 nFirstInstr; /* First instruction to execute */
|
|
|
|
sxi32 iFlags; /* Block control flags (see below) */
|
|
|
|
SySet aJumpFix; /* Jump fixup (JumpFixup instance) */
|
|
|
|
void *pUserData; /* Upper layer private data */
|
|
|
|
/* The following two fields are used only when compiling
|
|
|
|
* the 'do..while()' language construct.
|
|
|
|
*/
|
|
|
|
sxu8 bPostContinue; /* TRUE when compiling the do..while() statement */
|
|
|
|
SySet aPostContFix; /* Post-continue jump fix */
|
|
|
|
};
|
|
|
|
/*
|
|
|
|
* Code generator state is remembered in an instance of the following
|
|
|
|
* structure. We put the information in this structure and pass around
|
|
|
|
* a pointer to this structure, rather than pass around all of the
|
|
|
|
* information separately. This helps reduce the number of arguments
|
|
|
|
* to generator functions.
|
|
|
|
* This structure is used only during compile-time and have no meaning
|
|
|
|
* during bytecode execution.
|
|
|
|
*/
|
|
|
|
struct ph7_gen_state {
|
|
|
|
ph7_vm *pVm; /* VM that own this instance */
|
|
|
|
SyHash hLiteral; /* Constant string Literals table */
|
|
|
|
SyHash hNumLiteral; /* Numeric literals table */
|
|
|
|
SyHash hVar; /* Collected variable hashtable */
|
|
|
|
GenBlock *pCurrent; /* Current processed block */
|
|
|
|
GenBlock sGlobal; /* Global block */
|
|
|
|
ProcConsumer xErr; /* Error consumer callback */
|
|
|
|
void *pErrData; /* Third argument to xErr() */
|
|
|
|
SyBlob sWorker; /* General purpose working buffer */
|
|
|
|
SyBlob sErrBuf; /* Error buffer */
|
|
|
|
SyToken *pIn; /* Current processed token */
|
|
|
|
SyToken *pEnd; /* Last token in the stream */
|
|
|
|
sxu32 nErr; /* Total number of compilation error */
|
|
|
|
SyToken *pRawIn; /* Current processed raw token */
|
|
|
|
SyToken *pRawEnd; /* Last raw token in the stream */
|
|
|
|
SySet *pTokenSet; /* Token containers */
|
|
|
|
};
|
|
|
|
/* Forward references */
|
|
|
|
typedef struct ph7_vm_func_closure_env ph7_vm_func_closure_env;
|
|
|
|
typedef struct ph7_vm_func_static_var ph7_vm_func_static_var;
|
|
|
|
typedef struct ph7_vm_func_arg ph7_vm_func_arg;
|
|
|
|
typedef struct ph7_vm_func ph7_vm_func;
|
|
|
|
typedef struct VmFrame VmFrame;
|
|
|
|
/*
|
|
|
|
* Each collected function argument is recorded in an instance
|
|
|
|
* of the following structure.
|
|
|
|
* Note that as an extension, PH7 implements full type hinting
|
|
|
|
* which mean that any function can have it's own signature.
|
|
|
|
* Example:
|
|
|
|
* function foo(int $a,string $b,float $c,ClassInstance $d){}
|
|
|
|
* This is how the powerful function overloading mechanism is
|
|
|
|
* implemented.
|
|
|
|
* Note that as an extension, PH7 allow function arguments to have
|
|
|
|
* any complex default value associated with them unlike the standard
|
|
|
|
* PHP engine.
|
|
|
|
* Example:
|
|
|
|
* function foo(int $a = rand() & 1023){}
|
|
|
|
* now, when foo is called without arguments [i.e: foo()] the
|
|
|
|
* $a variable (first parameter) will be set to a random number
|
|
|
|
* between 0 and 1023 inclusive.
|
|
|
|
* Refer to the official documentation for more information on this
|
|
|
|
* mechanism and other extension introduced by the PH7 engine.
|
|
|
|
*/
|
|
|
|
struct ph7_vm_func_arg {
|
|
|
|
SyString sName; /* Argument name */
|
|
|
|
SySet aByteCode; /* Compiled default value associated with this argument */
|
|
|
|
sxu32 nType; /* Type of this argument [i.e: array, int, string, float, object, etc.] */
|
|
|
|
SyString sClass; /* Class name if the argument expect a class instance [i.e: function foo(BaseClass $bar){} ] */
|
|
|
|
sxi32 iFlags; /* Configuration flags */
|
|
|
|
};
|
|
|
|
/*
|
|
|
|
* Each static variable is parsed out and remembered in an instance
|
|
|
|
* of the following structure.
|
|
|
|
* Note that as an extension, PH7 allow static variable have
|
|
|
|
* any complex default value associated with them unlike the standard
|
|
|
|
* PHP engine.
|
|
|
|
* Example:
|
|
|
|
* static $rand_str = 'PH7'.rand_str(3); // Concatenate 'PH7' with
|
|
|
|
* // a random three characters(English alphabet)
|
|
|
|
* var_dump($rand_str);
|
|
|
|
* //You should see something like this
|
|
|
|
* string(6 'PH7awt');
|
|
|
|
*/
|
|
|
|
struct ph7_vm_func_static_var {
|
|
|
|
SyString sName; /* Static variable name */
|
|
|
|
SySet aByteCode; /* Compiled initialization expression */
|
|
|
|
sxu32 nIdx; /* Object index in the global memory object container */
|
|
|
|
};
|
|
|
|
/*
|
|
|
|
* Each imported variable from the outside closure environment is recoded
|
|
|
|
* in an instance of the following structure.
|
|
|
|
*/
|
|
|
|
struct ph7_vm_func_closure_env {
|
|
|
|
SyString sName; /* Imported variable name */
|
|
|
|
int iFlags; /* Control flags */
|
|
|
|
ph7_value sValue; /* Imported variable value */
|
|
|
|
sxu32 nIdx; /* Reference to the bounded variable if passed by reference
|
|
|
|
*[Example:
|
|
|
|
* $x = 1;
|
|
|
|
* $closure = function() use (&$x) { ++$x; }
|
|
|
|
* $closure();
|
|
|
|
*]
|
|
|
|
*/
|
|
|
|
};
|
|
|
|
/* Function configuration flags */
|
|
|
|
#define VM_FUNC_ARG_BY_REF 0x001 /* Argument passed by reference */
|
|
|
|
#define VM_FUNC_ARG_HAS_DEF 0x002 /* Argument has default value associated with it */
|
|
|
|
#define VM_FUNC_REF_RETURN 0x004 /* Return by reference */
|
|
|
|
#define VM_FUNC_CLASS_METHOD 0x008 /* VM function is in fact a class method */
|
|
|
|
#define VM_FUNC_CLOSURE 0x010 /* VM function is a closure */
|
|
|
|
#define VM_FUNC_ARG_IGNORE 0x020 /* Do not install argument in the current frame */
|
|
|
|
/*
|
|
|
|
* Each user defined function is parsed out and stored in an instance
|
|
|
|
* of the following structure.
|
|
|
|
* PH7 introduced some powerfull extensions to the PHP 5 programming
|
|
|
|
* language like function overloading, type hinting, complex default
|
|
|
|
* arguments values and many more.
|
|
|
|
* Please refer to the official documentation for more information.
|
|
|
|
*/
|
|
|
|
struct ph7_vm_func {
|
|
|
|
SySet aArgs; /* Expected arguments (ph7_vm_func_arg instance) */
|
|
|
|
SySet aStatic; /* Static variable (ph7_vm_func_static_var instance) */
|
|
|
|
SyString sName; /* Function name */
|
|
|
|
SySet aByteCode; /* Compiled function body */
|
|
|
|
SySet aClosureEnv; /* Closure environment (ph7_vm_func_closure_env instace) */
|
|
|
|
sxi32 iFlags; /* VM function configuration */
|
|
|
|
SyString sSignature; /* Function signature used to implement function overloading
|
|
|
|
* (Refer to the official documentation for more information
|
|
|
|
* on this powerfull feature)
|
|
|
|
*/
|
|
|
|
void *pUserData; /* Upper layer private data associated with this instance */
|
|
|
|
ph7_vm_func *pNextName; /* Next VM function with the same name as this one */
|
|
|
|
};
|
|
|
|
/* Forward reference */
|
|
|
|
typedef struct ph7_builtin_constant ph7_builtin_constant;
|
|
|
|
typedef struct ph7_builtin_func ph7_builtin_func;
|
|
|
|
/*
|
|
|
|
* Each built-in foreign function (C function) is stored in an
|
|
|
|
* instance of the following structure.
|
|
|
|
* Please refer to the official documentation for more information
|
|
|
|
* on how to create/install foreign functions.
|
|
|
|
*/
|
|
|
|
struct ph7_builtin_func {
|
|
|
|
const char *zName; /* Function name [i.e: strlen(), rand(), array_merge(), etc.]*/
|
|
|
|
ProcHostFunction xFunc; /* C routine performing the computation */
|
|
|
|
};
|
|
|
|
/*
|
|
|
|
* Each built-in foreign constant is stored in an instance
|
|
|
|
* of the following structure.
|
|
|
|
* Please refer to the official documentation for more information
|
|
|
|
|