winamp/Src/ns-eel/nseel-compiler.c
2024-09-24 14:54:57 +02:00

946 lines
No EOL
25 KiB
C

/*
Nullsoft Expression Evaluator Library (NS-EEL)
Copyright (C) 1999-2003 Nullsoft, Inc.
nseel-compiler.c
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include <windows.h>
#include "ns-eel-int.h"
#ifdef NSEEL_REENTRANT_EXECUTION
#include <malloc.h>
#endif
#define ltoupper(x) ((char)CharUpper((LPSTR)x))
static int nseel_evallib_stats[5]; // source bytes, static code bytes, call code bytes, data bytes, segments
int *NSEEL_getstats()
{
return nseel_evallib_stats;
}
double *NSEEL_getglobalregs()
{
return nseel_globalregs;
}
static size_t LLB_DSIZE=0;
//#define LLB_DSIZE (65536-64)
typedef struct _llBlockHeader
{
struct _llBlock *next;
size_t sizeused;
} llBlockHeader;
typedef struct _llBlock {
llBlockHeader header;
char block[1];
} llBlock;
typedef struct _startPtr {
struct _startPtr *next;
void *startptr;
} startPtr;
typedef struct {
int workTablePtr_size;
llBlock *blocks;
void *code;
int code_stats[4];
} codeHandleType;
#ifndef NSEEL_MAX_TEMPSPACE_ENTRIES
#define NSEEL_MAX_TEMPSPACE_ENTRIES 2048
#endif
static void *__newBlock(llBlock **start,size_t size);
#define newTmpBlock(x) __newBlock((llBlock **)&ctx->tmpblocks_head,x)
#define newBlock(x) __newBlock((llBlock **)&ctx->blocks_head,x)
static void freeBlocks(llBlock *start);
void nseel_asm_sin(void);
void nseel_asm_sin_end(void);
void nseel_asm_cos(void);
void nseel_asm_cos_end(void);
void nseel_asm_tan(void);
void nseel_asm_tan_end(void);
void nseel_asm_asin(void);
void nseel_asm_asin_end(void);
void nseel_asm_acos(void);
void nseel_asm_acos_end(void);
void nseel_asm_atan(void);
void nseel_asm_atan_end(void);
void nseel_asm_atan2(void);
void nseel_asm_atan2_end(void);
void nseel_asm_sqr(void);
void nseel_asm_sqr_end(void);
void nseel_asm_sqrt(void);
void nseel_asm_sqrt_end(void);
void nseel_asm_pow(void);
void nseel_asm_pow_end(void);
void nseel_asm_exp(void);
void nseel_asm_exp_end(void);
void nseel_asm_log(void);
void nseel_asm_log_end(void);
void nseel_asm_log10(void);
void nseel_asm_log10_end(void);
void nseel_asm_abs(void);
void nseel_asm_abs_end(void);
void nseel_asm_min(void);
void nseel_asm_min_end(void);
void nseel_asm_max(void);
void nseel_asm_max_end(void);
void nseel_asm_sig(void);
void nseel_asm_sig_end(void);
void nseel_asm_sign(void);
void nseel_asm_sign_end(void);
void nseel_asm_rand(void);
void nseel_asm_rand_end(void);
void nseel_asm_band(void);
void nseel_asm_band_end(void);
void nseel_asm_bor(void);
void nseel_asm_bor_end(void);
void nseel_asm_bnot(void);
void nseel_asm_bnot_end(void);
void nseel_asm_if(void);
void nseel_asm_if_end(void);
void nseel_asm_repeat(void);
void nseel_asm_repeat_end(void);
void nseel_asm_equal(void);
void nseel_asm_equal_end(void);
void nseel_asm_below(void);
void nseel_asm_below_end(void);
void nseel_asm_above(void);
void nseel_asm_above_end(void);
void nseel_asm_assign(void);
void nseel_asm_assign_end(void);
void nseel_asm_add(void);
void nseel_asm_add_end(void);
void nseel_asm_sub(void);
void nseel_asm_sub_end(void);
void nseel_asm_mul(void);
void nseel_asm_mul_end(void);
void nseel_asm_div(void);
void nseel_asm_div_end(void);
void nseel_asm_mod(void);
void nseel_asm_mod_end(void);
void nseel_asm_or(void);
void nseel_asm_or_end(void);
void nseel_asm_and(void);
void nseel_asm_and_end(void);
void nseel_asm_uplus(void);
void nseel_asm_uplus_end(void);
void nseel_asm_uminus(void);
void nseel_asm_uminus_end(void);
void nseel_asm_floor(void);
void nseel_asm_floor_end(void);
void nseel_asm_ceil(void);
void nseel_asm_ceil_end(void);
void nseel_asm_invsqrt(void);
void nseel_asm_invsqrt_end(void);
void nseel_asm_exec2(void);
void nseel_asm_exec2_end(void);
/*
#define DECL_ASMFUNC(x) \
void nseel_asm_##x##(void); \
void nseel_asm_##x##_end(void); \
DECL_ASMFUNC(sin)
DECL_ASMFUNC(cos)
DECL_ASMFUNC(tan)
DECL_ASMFUNC(asin)
DECL_ASMFUNC(acos)
DECL_ASMFUNC(atan)
DECL_ASMFUNC(atan2)
DECL_ASMFUNC(sqr)
DECL_ASMFUNC(sqrt)
DECL_ASMFUNC(pow)
DECL_ASMFUNC(exp)
DECL_ASMFUNC(log)
DECL_ASMFUNC(log10)
DECL_ASMFUNC(abs)
DECL_ASMFUNC(min)
DECL_ASMFUNC(min)
DECL_ASMFUNC(max)
DECL_ASMFUNC(sig)
DECL_ASMFUNC(sign)
DECL_ASMFUNC(rand)
DECL_ASMFUNC(band)
DECL_ASMFUNC(bor)
DECL_ASMFUNC(bnot)
DECL_ASMFUNC(if)
DECL_ASMFUNC(repeat)
DECL_ASMFUNC(equal)
DECL_ASMFUNC(below)
DECL_ASMFUNC(above)
DECL_ASMFUNC(assign)
DECL_ASMFUNC(add)
DECL_ASMFUNC(sub)
DECL_ASMFUNC(mul)
DECL_ASMFUNC(div)
DECL_ASMFUNC(mod)
DECL_ASMFUNC(or)
DECL_ASMFUNC(and)
DECL_ASMFUNC(uplus)
DECL_ASMFUNC(uminus)
DECL_ASMFUNC(floor)
DECL_ASMFUNC(ceil)
DECL_ASMFUNC(invsqrt)
DECL_ASMFUNC(exec2)
*/
static functionType fnTable1[] = {
{ "if", nseel_asm_if,nseel_asm_if_end, 3 },
#ifdef NSEEL_LOOPFUNC_SUPPORT
{ "loop", nseel_asm_repeat,nseel_asm_repeat_end, 2 },
#endif
{ "sin", nseel_asm_sin,nseel_asm_sin_end, 1 },
{ "cos", nseel_asm_cos,nseel_asm_cos_end, 1 },
{ "tan", nseel_asm_tan,nseel_asm_tan_end, 1 },
{ "asin", nseel_asm_asin,nseel_asm_asin_end, 1 },
{ "acos", nseel_asm_acos,nseel_asm_acos_end, 1 },
{ "atan", nseel_asm_atan,nseel_asm_atan_end, 1 },
{ "atan2", nseel_asm_atan2,nseel_asm_atan2_end, 2 },
{ "sqr", nseel_asm_sqr,nseel_asm_sqr_end, 1 },
{ "sqrt", nseel_asm_sqrt,nseel_asm_sqrt_end, 1 },
{ "pow", nseel_asm_pow,nseel_asm_pow_end, 2 },
{ "exp", nseel_asm_exp,nseel_asm_exp_end, 1 },
{ "log", nseel_asm_log,nseel_asm_log_end, 1 },
{ "log10", nseel_asm_log10,nseel_asm_log10_end, 1 },
{ "abs", nseel_asm_abs,nseel_asm_abs_end, 1 },
{ "min", nseel_asm_min,nseel_asm_min_end, 2 },
{ "max", nseel_asm_max,nseel_asm_max_end, 2 },
{ "sigmoid",nseel_asm_sig,nseel_asm_sig_end, 2 } ,
{ "sign", nseel_asm_sign,nseel_asm_sign_end, 1 } ,
{ "rand", nseel_asm_rand,nseel_asm_rand_end, 1 } ,
{ "band", nseel_asm_band,nseel_asm_band_end, 2 } ,
{ "bor", nseel_asm_bor,nseel_asm_bor_end, 2 } ,
{ "bnot", nseel_asm_bnot,nseel_asm_bnot_end, 1 } ,
{ "equal", nseel_asm_equal,nseel_asm_equal_end, 2 },
{ "below", nseel_asm_below,nseel_asm_below_end, 2 },
{ "above", nseel_asm_above,nseel_asm_above_end, 2 },
{ "floor", nseel_asm_floor,nseel_asm_floor_end, 1 },
{ "ceil", nseel_asm_ceil,nseel_asm_ceil_end, 1 },
{ "invsqrt", nseel_asm_invsqrt,nseel_asm_invsqrt_end, 1 },
{ "assign",nseel_asm_assign,nseel_asm_assign_end,2},
{ "exec2",nseel_asm_exec2,nseel_asm_exec2_end,2},
{ "exec3",nseel_asm_exec2,nseel_asm_exec2_end,3},
};
static functionType *fnTableUser;
static int fnTableUser_size;
functionType *nseel_getFunctionFromTable(int idx)
{
if (idx<0) return 0;
if (idx>=sizeof(fnTable1)/sizeof(fnTable1[0]))
{
idx -= sizeof(fnTable1)/sizeof(fnTable1[0]);
if (!fnTableUser || idx >= fnTableUser_size) return 0;
return fnTableUser+idx;
}
return fnTable1+idx;
}
int NSEEL_init() // returns 0 on success
{
NSEEL_quit();
return 0;
}
void NSEEL_addfunctionex(char *name, int nparms, int code_startaddr, int code_len, void *pproc)
{
if (!fnTableUser || !(fnTableUser_size&7))
{
fnTableUser=(functionType *)realloc(fnTableUser,(fnTableUser_size+8)*sizeof(functionType));
}
if (fnTableUser)
{
fnTableUser[fnTableUser_size].nParams = nparms;
fnTableUser[fnTableUser_size].name = name;
fnTableUser[fnTableUser_size].afunc = (void *)code_startaddr;
fnTableUser[fnTableUser_size].func_e = (void *)(code_startaddr + code_len);
fnTableUser[fnTableUser_size].pProc = (NSEEL_PPPROC) pproc;
fnTableUser_size++;
}
}
void NSEEL_quit()
{
free(fnTableUser);
fnTableUser_size=0;
fnTableUser=0;
}
//---------------------------------------------------------------------------------------------------------------
static void *realAddress(void *fn, void *fn_e, int *size)
{
#ifdef DISABLED_DEBUG
char *ptr = (char *)fn;
int beg=(*(int *)(ptr+1))+5;
int extrasize=(int)nseel_asm_exec2_end - (int)nseel_asm_exec2;
int extrabeg=(*(int *)(((char *)nseel_asm_exec2)+1))+5;
*size=((int)fn_e - (int)fn) - (extrasize-extrabeg) - beg;
return ptr + beg;
#else
// Release Mode
*size = (int)fn_e - (int) fn;
return fn;
#endif
}
//---------------------------------------------------------------------------------------------------------------
static void freeBlocks(llBlock *start)
{
while (start)
{
llBlock *llB = start->header.next;
VirtualFree(start, 0 /*LLB_DSIZE*/, MEM_RELEASE);
start=llB;
}
}
//---------------------------------------------------------------------------------------------------------------
static void *__newBlock(llBlock **start, size_t size)
{
llBlock *llb = NULL;
size_t alloc_size = 0;
if (!LLB_DSIZE)
{
SYSTEM_INFO systemInfo;
GetSystemInfo(&systemInfo);
LLB_DSIZE = systemInfo.dwAllocationGranularity;
}
if (*start && (LLB_DSIZE - (*start)->header.sizeused) >= size)
{
void *t=(*start)->block+(*start)->header.sizeused;
(*start)->header.sizeused+=size;
return t;
}
alloc_size=LLB_DSIZE;
size+=sizeof(llBlockHeader); // make sure we have enough room for the block header;
while (size > alloc_size) alloc_size += LLB_DSIZE;
llb = (llBlock *)VirtualAlloc(NULL, alloc_size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
llb->header.sizeused=size;
llb->header.next = *start;
*start = llb;
return llb->block;
}
#define X86_MOV_EAX_DIRECTVALUE 0xB8
#define X86_MOV_ESI_DIRECTVALUE 0xBE
#define X86_MOV_ESI_DIRECTMEMVALUE 0x358B
#define X86_PUSH_EAX 0x50
#define X86_POP_EBX 0x5B
#define X86_POP_ECX 0x59
#define X86_MOV_ESI_EDI 0xF78B
#define X86_PUSH_ESI 0x56
#define X86_POP_ESI 0x5E
#define X86_RET 0xC3
//---------------------------------------------------------------------------------------------------------------
static int *findFBlock(char *p)
{
while (*(int *)p != 0xFFFFFFFF) p++;
return (int*)p;
}
//---------------------------------------------------------------------------------------------------------------
int nseel_createCompiledValue(compileContext *ctx, double value, double *addrValue)
{
unsigned char *block = NULL;
double *dupValue = NULL;
block=(unsigned char *)newTmpBlock(4+5);
if (addrValue == NULL)
{
ctx->l_stats[3]+=sizeof(double);
*(dupValue = (double *)newBlock(sizeof(double))) = value;
}
else
dupValue = addrValue;
((int*)block)[0]=5;
block[4]=X86_MOV_EAX_DIRECTVALUE; // mov eax, <value>
*(int *)(block+5) = (int)dupValue;
return ((int)(block));
}
//---------------------------------------------------------------------------------------------------------------
static int nseel_getFunctionAddress(int fntype, int fn, int *size, NSEEL_PPPROC *pProc)
{
*pProc = NULL;
switch (fntype)
{
case MATH_SIMPLE:
switch (fn)
{
case FN_ASSIGN:
return (int)realAddress(nseel_asm_assign,nseel_asm_assign_end,size);
case FN_ADD:
return (int)realAddress(nseel_asm_add,nseel_asm_add_end,size);
case FN_SUB:
return (int)realAddress(nseel_asm_sub,nseel_asm_sub_end,size);
case FN_MULTIPLY:
return (int)realAddress(nseel_asm_mul,nseel_asm_mul_end,size);
case FN_DIVIDE:
return (int)realAddress(nseel_asm_div,nseel_asm_div_end,size);
case FN_MODULO:
return (int)realAddress(nseel_asm_mod,nseel_asm_mod_end,size);
case FN_AND:
return (int)realAddress(nseel_asm_and,nseel_asm_and_end,size);
case FN_OR:
return (int)realAddress(nseel_asm_or,nseel_asm_or_end,size);
case FN_UPLUS:
return (int)realAddress(nseel_asm_uplus,nseel_asm_uplus_end,size);
case FN_UMINUS:
return (int)realAddress(nseel_asm_uminus,nseel_asm_uminus_end,size);
}
case MATH_FN:
{
functionType *p=nseel_getFunctionFromTable(fn);
if (!p)
{
if (size) *size=0;
return 0;
}
if (p->pProc) *pProc=p->pProc;
return (int)realAddress(p->afunc,p->func_e,size);
}
}
return 0;
}
//---------------------------------------------------------------------------------------------------------------
int nseel_createCompiledFunction3(compileContext *ctx, int fntype, int fn, int code1, int code2, int code3)
{
int sizes1=((int *)code1)[0];
int sizes2=((int *)code2)[0];
int sizes3=((int *)code3)[0];
if (fntype == MATH_FN && fn == 0) // special case: IF
{
void *func3 = NULL;
int size = 0;
int *ptr = NULL;
char *block = NULL;
unsigned char *newblock2,*newblock3 = NULL;
newblock2=newBlock(sizes2+1);
memcpy(newblock2,(char*)code2+4,sizes2);
newblock2[sizes2]=X86_RET;
newblock3=newBlock(sizes3+1);
memcpy(newblock3,(char*)code3+4,sizes3);
newblock3[sizes3]=X86_RET;
ctx->l_stats[2]+=sizes2+sizes3+2;
func3 = realAddress(nseel_asm_if,nseel_asm_if_end,&size);
block=(char *)newTmpBlock(4+sizes1+size);
((int*)block)[0]=sizes1+size;
memcpy(block+4,(char*)code1+4,sizes1);
ptr=(int *)(block+4+sizes1);
memcpy(ptr,func3,size);
ptr=findFBlock((char*)ptr); *ptr++=(int)newblock2;
ptr=findFBlock((char*)ptr); *ptr=(int)newblock3;
ctx->computTableTop++;
return (int)block;
}
else
{
int size2 = 0;
unsigned char *block = NULL;
unsigned char *outp = NULL;
int myfunc = 0;
NSEEL_PPPROC preProc;
myfunc = nseel_getFunctionAddress(fntype, fn, &size2, &preProc);
block=(unsigned char *)newTmpBlock(4+size2+sizes1+sizes2+sizes3+4);
((int*)block)[0]=4+size2+sizes1+sizes2+sizes3;
outp=block+4;
memcpy(outp,(char*)code1+4,sizes1);
outp+=sizes1;
*outp++ = X86_PUSH_EAX;
memcpy(outp,(char*)code2+4,sizes2);
outp+=sizes2;
*outp++ = X86_PUSH_EAX;
memcpy(outp,(char*)code3+4,sizes3);
outp+=sizes3;
*outp++ = X86_POP_EBX;
*outp++ = X86_POP_ECX;
memcpy(outp,(void*)myfunc,size2);
if (preProc) preProc(outp,size2,ctx->userfunc_data);
ctx->computTableTop++;
return ((int)(block));
}
}
//---------------------------------------------------------------------------------------------------------------
int nseel_createCompiledFunction2(compileContext *ctx, int fntype, int fn, int code1, int code2)
{
int size2 = 0;
unsigned char *block = NULL;
unsigned char *outp = NULL;
int myfunc = 0;
int sizes1=((int *)code1)[0];
int sizes2=((int *)code2)[0];
#ifdef NSEEL_LOOPFUNC_SUPPORT
if (fntype == MATH_FN && fn == 1) // special case: REPEAT
{
void *func3 = NULL;
int size = 0;
int *ptr = NULL;
char *block = NULL;
unsigned char *newblock2 = NULL;
newblock2=newBlock(sizes2+1);
memcpy(newblock2,(char*)code2+4,sizes2);
newblock2[sizes2]=X86_RET;
ctx->l_stats[2]+=sizes2+2;
func3 = realAddress(nseel_asm_repeat,nseel_asm_repeat_end,&size);
block=(char *)newTmpBlock(4+sizes1+size);
((int*)block)[0]=sizes1+size;
memcpy(block+4,(char*)code1+4,sizes1);
ptr=(int *)(block+4+sizes1);
memcpy(ptr,func3,size);
ptr=findFBlock((char*)ptr); *ptr++=(int)newblock2;
ctx->computTableTop++;
return (int)block;
}
else
#endif
{
NSEEL_PPPROC preProc;
myfunc = nseel_getFunctionAddress(fntype, fn, &size2,&preProc);
block=(unsigned char *)newTmpBlock(2+size2+sizes1+sizes2+4);
((int*)block)[0]=2+size2+sizes1+sizes2;
outp=block+4;
memcpy(outp,(char*)code1+4,sizes1);
outp+=sizes1;
*outp++ = X86_PUSH_EAX;
memcpy(outp,(char*)code2+4,sizes2);
outp+=sizes2;
*outp++ = X86_POP_EBX;
memcpy(outp,(void*)myfunc,size2);
if (preProc) preProc(outp,size2,ctx->userfunc_data);
ctx->computTableTop++;
return ((int)(block));
}
}
//---------------------------------------------------------------------------------------------------------------
int nseel_createCompiledFunction1(compileContext *ctx, int fntype, int fn, int code)
{
NSEEL_PPPROC preProc;
int size,size2 = 0;
char *block = NULL;
int myfunc = 0;
void *func1 = NULL;
size =((int *)code)[0];
func1 = (void *)(code+4);
myfunc = nseel_getFunctionAddress(fntype, fn, &size2,&preProc);
block=(char *)newTmpBlock(4+size+size2);
((int*)block)[0]=size+size2;
memcpy(block+4, func1, size);
memcpy(block+size+4,(void*)myfunc,size2);
if (preProc) preProc(block+size+4,size2,ctx->userfunc_data);
ctx->computTableTop++;
return ((int)(block));
}
static char *preprocessCode(compileContext *ctx, char *expression)
{
int len=0;
int alloc_len=strlen(expression)+1+64;
char *buf=(char *)malloc(alloc_len);
while (*expression)
{
if (len > alloc_len-32)
{
alloc_len = len+128;
buf=(char*)realloc(buf,alloc_len);
}
if (expression[0] == '/')
{
if (expression[1] == '/')
{
expression+=2;
while (expression[0] && expression[0] != '\r' && expression[0] != '\n') expression++;
}
else if (expression[1] == '*')
{
expression+=2;
while (expression[0] && (expression[0] != '*' || expression[1] != '/')) expression++;
if (expression[0]) expression+=2; // at this point we KNOW expression[0]=* and expression[1]=/
}
else
{
char c=buf[len++]=*expression++;
if (c != ' ' && c != '\t' && c != '\r' && c != '\n') ctx->l_stats[0]++;
}
}
else if (expression[0] == '$')
{
if (ltoupper(expression[1]) == 'P' && ltoupper(expression[2]) == 'I')
{
static char *str="3.141592653589793";
expression+=3;
memcpy(buf+len,str,17);
len+=17; //strlen(str);
ctx->l_stats[0]+=17;
}
else if (ltoupper(expression[1]) == 'E')
{
static char *str="2.71828183";
expression+=2;
memcpy(buf+len,str,10);
len+=10; //strlen(str);
ctx->l_stats[0]+=10;
}
if (ltoupper(expression[1]) == 'P' && ltoupper(expression[2]) == 'H' && ltoupper(expression[3]) == 'I')
{
static char *str="1.61803399";
expression+=4;
memcpy(buf+len,str,10);
len+=10; //strlen(str);
ctx->l_stats[0]+=10;
}
else
{
char c = buf[len++]=*expression++;
if (c != ' ' && c != '\t' && c != '\r' && c != '\n') ctx->l_stats[0]++;
}
}
else
{
char c=*expression++;
if (c == '\r' || c == '\n' || c == '\t') c=' ';
buf[len++]=c;
if (c != ' ') ctx->l_stats[0]++;
}
}
buf[len]=0;
return buf;
}
static void movestringover(char *str, int amount)
{
char tmp[1024+8];
int l=(int)strlen(str);
l=min(1024-amount-1,l);
memcpy(tmp,str,l+1);
while (l >= 0 && tmp[l]!='\n') l--;
l++;
tmp[l]=0;//ensure we null terminate
memcpy(str+amount,tmp,l+1);
}
//------------------------------------------------------------------------------
NSEEL_CODEHANDLE NSEEL_code_compile(NSEEL_VMCTX _ctx, char *_expression)
{
compileContext *ctx = (compileContext *)_ctx;
char *expression,*expression_start;
int computable_size=0;
codeHandleType *handle;
startPtr *scode=NULL;
startPtr *startpts=NULL;
if (!ctx || !_expression || !*_expression) return 0;
ctx->last_error_string[0]=0;
ctx->blocks_head=0;
ctx->tmpblocks_head=0;
memset(ctx->l_stats,0, sizeof(ctx->l_stats) / sizeof(ctx->l_stats[0]));
handle = (codeHandleType*)newBlock(sizeof(codeHandleType));
if (!handle)
{
return 0;
}
memset(handle,0,sizeof(codeHandleType));
expression_start=expression=preprocessCode(ctx,_expression);
while (*expression)
{
startPtr *tmp;
char *expr;
ctx->colCount=0;
// single out segment
while (*expression == ';' || *expression == ' ') expression++;
if (!*expression) break;
expr=expression;
while (*expression && *expression != ';') expression++;
if (*expression) *expression++ = 0;
// parse
tmp=(startPtr*) newTmpBlock(sizeof(startPtr));
if (!tmp) break;
ctx->computTableTop=0;
tmp->startptr=nseel_compileExpression(ctx,expr);
if (ctx->computTableTop > NSEEL_MAX_TEMPSPACE_ENTRIES- /* safety */ 16 - /* alignment */4 ||
!tmp->startptr)
{
lstrcpyn(ctx->last_error_string,expr,sizeof(ctx->last_error_string)/sizeof(ctx->last_error_string[0]));
scode=NULL;
break;
}
if (computable_size < ctx->computTableTop)
{
computable_size=ctx->computTableTop;
}
tmp->next=NULL;
if (!scode) scode=startpts=tmp;
else
{
scode->next=tmp;
scode=tmp;
}
}
// check to see if failed on the first startingCode
if (!scode)
{
freeBlocks((llBlock *)ctx->blocks_head); // free blocks
handle=NULL; // return NULL (after resetting blocks_head)
}
else
{
// now we build one big code segment out of our list of them, inserting a mov esi, computable before each item
unsigned char *writeptr;
int size=1; // for ret at end :)
startPtr *p;
p=startpts;
while (p)
{
size+=2; // mov esi, edi
size+=*(int *)p->startptr;
p=p->next;
}
handle->code = newBlock(size);
if (handle->code)
{
writeptr=(unsigned char *)handle->code;
p=startpts;
while (p)
{
int thissize=*(int *)p->startptr;
*(unsigned short *)writeptr= X86_MOV_ESI_EDI;
writeptr+=2;
memcpy(writeptr,(char*)p->startptr + 4,thissize);
writeptr += thissize;
p=p->next;
}
*writeptr=X86_RET; // ret
ctx->l_stats[1]=size;
}
handle->blocks = ctx->blocks_head;
handle->workTablePtr_size=(computable_size) * sizeof(double);
}
freeBlocks((llBlock *)ctx->tmpblocks_head); // free blocks
ctx->tmpblocks_head=0;
ctx->blocks_head=0;
if (handle)
{
memcpy(handle->code_stats,ctx->l_stats,sizeof(ctx->l_stats));
nseel_evallib_stats[0]+=ctx->l_stats[0];
nseel_evallib_stats[1]+=ctx->l_stats[1];
nseel_evallib_stats[2]+=ctx->l_stats[2];
nseel_evallib_stats[3]+=ctx->l_stats[3];
nseel_evallib_stats[4]++;
}
memset(ctx->l_stats,0,sizeof(ctx->l_stats));
free(expression_start);
return (NSEEL_CODEHANDLE)handle;
}
//------------------------------------------------------------------------------
void NSEEL_code_execute(NSEEL_CODEHANDLE code)
{
#ifdef NSEEL_REENTRANT_EXECUTION
int baseptr;
#else
static double _tab[NSEEL_MAX_TEMPSPACE_ENTRIES];
int baseptr = (int) _tab;
#endif
codeHandleType *h = (codeHandleType *)code;
if (!h || !h->code)
return;
#ifdef NSEEL_REENTRANT_EXECUTION
baseptr = (int) alloca(h->workTablePtr_size + 16*sizeof(double) /*safety*/ + 32 /*alignment*/);
if (!baseptr)
return;
#endif
{
int startPoint=(int)h->code;
__asm
{
mov ebx, baseptr
mov eax, startPoint
pushad // Lets cover our ass
add ebx, 31
and ebx, ~31
mov edi, ebx
call eax
popad
}
}
}
char *NSEEL_code_getcodeerror(NSEEL_VMCTX ctx)
{
compileContext *c=(compileContext *)ctx;
if (ctx && c->last_error_string[0]) return c->last_error_string;
return 0;
}
//------------------------------------------------------------------------------
void NSEEL_code_free(NSEEL_CODEHANDLE code)
{
codeHandleType *h = (codeHandleType *)code;
if (h != NULL)
{
nseel_evallib_stats[0]-=h->code_stats[0];
nseel_evallib_stats[1]-=h->code_stats[1];
nseel_evallib_stats[2]-=h->code_stats[2];
nseel_evallib_stats[3]-=h->code_stats[3];
nseel_evallib_stats[4]--;
freeBlocks(h->blocks);
}
}
//------------------------------------------------------------------------------
void NSEEL_VM_resetvars(NSEEL_VMCTX _ctx)
{
if (_ctx)
{
compileContext *ctx=(compileContext *)_ctx;
int x;
if (ctx->varTable_Names || ctx->varTable_Values) for (x = 0; x < ctx->varTable_numBlocks; x ++)
{
if (ctx->varTable_Names)
free(ctx->varTable_Names[x]);
if (ctx->varTable_Values)
free(ctx->varTable_Values[x]);
}
free(ctx->varTable_Values);
free(ctx->varTable_Names);
ctx->varTable_Values=0;
ctx->varTable_Names=0;
ctx->varTable_numBlocks=0;
}
}
NSEEL_VMCTX NSEEL_VM_alloc() // return a handle
{
compileContext *ctx=calloc(1,sizeof(compileContext));
return ctx;
}
void NSEEL_VM_free(NSEEL_VMCTX ctx) // free when done with a VM and ALL of its code have been freed, as well
{
free(ctx);
}
int *NSEEL_code_getstats(NSEEL_CODEHANDLE code)
{
codeHandleType *h = (codeHandleType *)code;
if (h)
{
return h->code_stats;
}
return 0;
}