nseel-compiler.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946
  1. /*
  2. Nullsoft Expression Evaluator Library (NS-EEL)
  3. Copyright (C) 1999-2003 Nullsoft, Inc.
  4. nseel-compiler.c
  5. This software is provided 'as-is', without any express or implied
  6. warranty. In no event will the authors be held liable for any damages
  7. arising from the use of this software.
  8. Permission is granted to anyone to use this software for any purpose,
  9. including commercial applications, and to alter it and redistribute it
  10. freely, subject to the following restrictions:
  11. 1. The origin of this software must not be misrepresented; you must not
  12. claim that you wrote the original software. If you use this software
  13. in a product, an acknowledgment in the product documentation would be
  14. appreciated but is not required.
  15. 2. Altered source versions must be plainly marked as such, and must not be
  16. misrepresented as being the original software.
  17. 3. This notice may not be removed or altered from any source distribution.
  18. */
  19. #include <windows.h>
  20. #include "ns-eel-int.h"
  21. #ifdef NSEEL_REENTRANT_EXECUTION
  22. #include <malloc.h>
  23. #endif
  24. #define ltoupper(x) ((char)CharUpper((LPSTR)x))
  25. static int nseel_evallib_stats[5]; // source bytes, static code bytes, call code bytes, data bytes, segments
  26. int *NSEEL_getstats()
  27. {
  28. return nseel_evallib_stats;
  29. }
  30. double *NSEEL_getglobalregs()
  31. {
  32. return nseel_globalregs;
  33. }
  34. static size_t LLB_DSIZE=0;
  35. //#define LLB_DSIZE (65536-64)
  36. typedef struct _llBlockHeader
  37. {
  38. struct _llBlock *next;
  39. size_t sizeused;
  40. } llBlockHeader;
  41. typedef struct _llBlock {
  42. llBlockHeader header;
  43. char block[1];
  44. } llBlock;
  45. typedef struct _startPtr {
  46. struct _startPtr *next;
  47. void *startptr;
  48. } startPtr;
  49. typedef struct {
  50. int workTablePtr_size;
  51. llBlock *blocks;
  52. void *code;
  53. int code_stats[4];
  54. } codeHandleType;
  55. #ifndef NSEEL_MAX_TEMPSPACE_ENTRIES
  56. #define NSEEL_MAX_TEMPSPACE_ENTRIES 2048
  57. #endif
  58. static void *__newBlock(llBlock **start,size_t size);
  59. #define newTmpBlock(x) __newBlock((llBlock **)&ctx->tmpblocks_head,x)
  60. #define newBlock(x) __newBlock((llBlock **)&ctx->blocks_head,x)
  61. static void freeBlocks(llBlock *start);
  62. void nseel_asm_sin(void);
  63. void nseel_asm_sin_end(void);
  64. void nseel_asm_cos(void);
  65. void nseel_asm_cos_end(void);
  66. void nseel_asm_tan(void);
  67. void nseel_asm_tan_end(void);
  68. void nseel_asm_asin(void);
  69. void nseel_asm_asin_end(void);
  70. void nseel_asm_acos(void);
  71. void nseel_asm_acos_end(void);
  72. void nseel_asm_atan(void);
  73. void nseel_asm_atan_end(void);
  74. void nseel_asm_atan2(void);
  75. void nseel_asm_atan2_end(void);
  76. void nseel_asm_sqr(void);
  77. void nseel_asm_sqr_end(void);
  78. void nseel_asm_sqrt(void);
  79. void nseel_asm_sqrt_end(void);
  80. void nseel_asm_pow(void);
  81. void nseel_asm_pow_end(void);
  82. void nseel_asm_exp(void);
  83. void nseel_asm_exp_end(void);
  84. void nseel_asm_log(void);
  85. void nseel_asm_log_end(void);
  86. void nseel_asm_log10(void);
  87. void nseel_asm_log10_end(void);
  88. void nseel_asm_abs(void);
  89. void nseel_asm_abs_end(void);
  90. void nseel_asm_min(void);
  91. void nseel_asm_min_end(void);
  92. void nseel_asm_max(void);
  93. void nseel_asm_max_end(void);
  94. void nseel_asm_sig(void);
  95. void nseel_asm_sig_end(void);
  96. void nseel_asm_sign(void);
  97. void nseel_asm_sign_end(void);
  98. void nseel_asm_rand(void);
  99. void nseel_asm_rand_end(void);
  100. void nseel_asm_band(void);
  101. void nseel_asm_band_end(void);
  102. void nseel_asm_bor(void);
  103. void nseel_asm_bor_end(void);
  104. void nseel_asm_bnot(void);
  105. void nseel_asm_bnot_end(void);
  106. void nseel_asm_if(void);
  107. void nseel_asm_if_end(void);
  108. void nseel_asm_repeat(void);
  109. void nseel_asm_repeat_end(void);
  110. void nseel_asm_equal(void);
  111. void nseel_asm_equal_end(void);
  112. void nseel_asm_below(void);
  113. void nseel_asm_below_end(void);
  114. void nseel_asm_above(void);
  115. void nseel_asm_above_end(void);
  116. void nseel_asm_assign(void);
  117. void nseel_asm_assign_end(void);
  118. void nseel_asm_add(void);
  119. void nseel_asm_add_end(void);
  120. void nseel_asm_sub(void);
  121. void nseel_asm_sub_end(void);
  122. void nseel_asm_mul(void);
  123. void nseel_asm_mul_end(void);
  124. void nseel_asm_div(void);
  125. void nseel_asm_div_end(void);
  126. void nseel_asm_mod(void);
  127. void nseel_asm_mod_end(void);
  128. void nseel_asm_or(void);
  129. void nseel_asm_or_end(void);
  130. void nseel_asm_and(void);
  131. void nseel_asm_and_end(void);
  132. void nseel_asm_uplus(void);
  133. void nseel_asm_uplus_end(void);
  134. void nseel_asm_uminus(void);
  135. void nseel_asm_uminus_end(void);
  136. void nseel_asm_floor(void);
  137. void nseel_asm_floor_end(void);
  138. void nseel_asm_ceil(void);
  139. void nseel_asm_ceil_end(void);
  140. void nseel_asm_invsqrt(void);
  141. void nseel_asm_invsqrt_end(void);
  142. void nseel_asm_exec2(void);
  143. void nseel_asm_exec2_end(void);
  144. /*
  145. #define DECL_ASMFUNC(x) \
  146. void nseel_asm_##x##(void); \
  147. void nseel_asm_##x##_end(void); \
  148. DECL_ASMFUNC(sin)
  149. DECL_ASMFUNC(cos)
  150. DECL_ASMFUNC(tan)
  151. DECL_ASMFUNC(asin)
  152. DECL_ASMFUNC(acos)
  153. DECL_ASMFUNC(atan)
  154. DECL_ASMFUNC(atan2)
  155. DECL_ASMFUNC(sqr)
  156. DECL_ASMFUNC(sqrt)
  157. DECL_ASMFUNC(pow)
  158. DECL_ASMFUNC(exp)
  159. DECL_ASMFUNC(log)
  160. DECL_ASMFUNC(log10)
  161. DECL_ASMFUNC(abs)
  162. DECL_ASMFUNC(min)
  163. DECL_ASMFUNC(min)
  164. DECL_ASMFUNC(max)
  165. DECL_ASMFUNC(sig)
  166. DECL_ASMFUNC(sign)
  167. DECL_ASMFUNC(rand)
  168. DECL_ASMFUNC(band)
  169. DECL_ASMFUNC(bor)
  170. DECL_ASMFUNC(bnot)
  171. DECL_ASMFUNC(if)
  172. DECL_ASMFUNC(repeat)
  173. DECL_ASMFUNC(equal)
  174. DECL_ASMFUNC(below)
  175. DECL_ASMFUNC(above)
  176. DECL_ASMFUNC(assign)
  177. DECL_ASMFUNC(add)
  178. DECL_ASMFUNC(sub)
  179. DECL_ASMFUNC(mul)
  180. DECL_ASMFUNC(div)
  181. DECL_ASMFUNC(mod)
  182. DECL_ASMFUNC(or)
  183. DECL_ASMFUNC(and)
  184. DECL_ASMFUNC(uplus)
  185. DECL_ASMFUNC(uminus)
  186. DECL_ASMFUNC(floor)
  187. DECL_ASMFUNC(ceil)
  188. DECL_ASMFUNC(invsqrt)
  189. DECL_ASMFUNC(exec2)
  190. */
  191. static functionType fnTable1[] = {
  192. { "if", nseel_asm_if,nseel_asm_if_end, 3 },
  193. #ifdef NSEEL_LOOPFUNC_SUPPORT
  194. { "loop", nseel_asm_repeat,nseel_asm_repeat_end, 2 },
  195. #endif
  196. { "sin", nseel_asm_sin,nseel_asm_sin_end, 1 },
  197. { "cos", nseel_asm_cos,nseel_asm_cos_end, 1 },
  198. { "tan", nseel_asm_tan,nseel_asm_tan_end, 1 },
  199. { "asin", nseel_asm_asin,nseel_asm_asin_end, 1 },
  200. { "acos", nseel_asm_acos,nseel_asm_acos_end, 1 },
  201. { "atan", nseel_asm_atan,nseel_asm_atan_end, 1 },
  202. { "atan2", nseel_asm_atan2,nseel_asm_atan2_end, 2 },
  203. { "sqr", nseel_asm_sqr,nseel_asm_sqr_end, 1 },
  204. { "sqrt", nseel_asm_sqrt,nseel_asm_sqrt_end, 1 },
  205. { "pow", nseel_asm_pow,nseel_asm_pow_end, 2 },
  206. { "exp", nseel_asm_exp,nseel_asm_exp_end, 1 },
  207. { "log", nseel_asm_log,nseel_asm_log_end, 1 },
  208. { "log10", nseel_asm_log10,nseel_asm_log10_end, 1 },
  209. { "abs", nseel_asm_abs,nseel_asm_abs_end, 1 },
  210. { "min", nseel_asm_min,nseel_asm_min_end, 2 },
  211. { "max", nseel_asm_max,nseel_asm_max_end, 2 },
  212. { "sigmoid",nseel_asm_sig,nseel_asm_sig_end, 2 } ,
  213. { "sign", nseel_asm_sign,nseel_asm_sign_end, 1 } ,
  214. { "rand", nseel_asm_rand,nseel_asm_rand_end, 1 } ,
  215. { "band", nseel_asm_band,nseel_asm_band_end, 2 } ,
  216. { "bor", nseel_asm_bor,nseel_asm_bor_end, 2 } ,
  217. { "bnot", nseel_asm_bnot,nseel_asm_bnot_end, 1 } ,
  218. { "equal", nseel_asm_equal,nseel_asm_equal_end, 2 },
  219. { "below", nseel_asm_below,nseel_asm_below_end, 2 },
  220. { "above", nseel_asm_above,nseel_asm_above_end, 2 },
  221. { "floor", nseel_asm_floor,nseel_asm_floor_end, 1 },
  222. { "ceil", nseel_asm_ceil,nseel_asm_ceil_end, 1 },
  223. { "invsqrt", nseel_asm_invsqrt,nseel_asm_invsqrt_end, 1 },
  224. { "assign",nseel_asm_assign,nseel_asm_assign_end,2},
  225. { "exec2",nseel_asm_exec2,nseel_asm_exec2_end,2},
  226. { "exec3",nseel_asm_exec2,nseel_asm_exec2_end,3},
  227. };
  228. static functionType *fnTableUser;
  229. static int fnTableUser_size;
  230. functionType *nseel_getFunctionFromTable(int idx)
  231. {
  232. if (idx<0) return 0;
  233. if (idx>=sizeof(fnTable1)/sizeof(fnTable1[0]))
  234. {
  235. idx -= sizeof(fnTable1)/sizeof(fnTable1[0]);
  236. if (!fnTableUser || idx >= fnTableUser_size) return 0;
  237. return fnTableUser+idx;
  238. }
  239. return fnTable1+idx;
  240. }
  241. int NSEEL_init() // returns 0 on success
  242. {
  243. NSEEL_quit();
  244. return 0;
  245. }
  246. void NSEEL_addfunctionex(char *name, int nparms, int code_startaddr, int code_len, void *pproc)
  247. {
  248. if (!fnTableUser || !(fnTableUser_size&7))
  249. {
  250. fnTableUser=(functionType *)realloc(fnTableUser,(fnTableUser_size+8)*sizeof(functionType));
  251. }
  252. if (fnTableUser)
  253. {
  254. fnTableUser[fnTableUser_size].nParams = nparms;
  255. fnTableUser[fnTableUser_size].name = name;
  256. fnTableUser[fnTableUser_size].afunc = (void *)code_startaddr;
  257. fnTableUser[fnTableUser_size].func_e = (void *)(code_startaddr + code_len);
  258. fnTableUser[fnTableUser_size].pProc = (NSEEL_PPPROC) pproc;
  259. fnTableUser_size++;
  260. }
  261. }
  262. void NSEEL_quit()
  263. {
  264. free(fnTableUser);
  265. fnTableUser_size=0;
  266. fnTableUser=0;
  267. }
  268. //---------------------------------------------------------------------------------------------------------------
  269. static void *realAddress(void *fn, void *fn_e, int *size)
  270. {
  271. #ifdef DISABLED_DEBUG
  272. char *ptr = (char *)fn;
  273. int beg=(*(int *)(ptr+1))+5;
  274. int extrasize=(int)nseel_asm_exec2_end - (int)nseel_asm_exec2;
  275. int extrabeg=(*(int *)(((char *)nseel_asm_exec2)+1))+5;
  276. *size=((int)fn_e - (int)fn) - (extrasize-extrabeg) - beg;
  277. return ptr + beg;
  278. #else
  279. // Release Mode
  280. *size = (int)fn_e - (int) fn;
  281. return fn;
  282. #endif
  283. }
  284. //---------------------------------------------------------------------------------------------------------------
  285. static void freeBlocks(llBlock *start)
  286. {
  287. while (start)
  288. {
  289. llBlock *llB = start->header.next;
  290. VirtualFree(start, 0 /*LLB_DSIZE*/, MEM_RELEASE);
  291. start=llB;
  292. }
  293. }
  294. //---------------------------------------------------------------------------------------------------------------
  295. static void *__newBlock(llBlock **start, size_t size)
  296. {
  297. llBlock *llb = NULL;
  298. size_t alloc_size = 0;
  299. if (!LLB_DSIZE)
  300. {
  301. SYSTEM_INFO systemInfo;
  302. GetSystemInfo(&systemInfo);
  303. LLB_DSIZE = systemInfo.dwAllocationGranularity;
  304. }
  305. if (*start && (LLB_DSIZE - (*start)->header.sizeused) >= size)
  306. {
  307. void *t=(*start)->block+(*start)->header.sizeused;
  308. (*start)->header.sizeused+=size;
  309. return t;
  310. }
  311. alloc_size=LLB_DSIZE;
  312. size+=sizeof(llBlockHeader); // make sure we have enough room for the block header;
  313. while (size > alloc_size) alloc_size += LLB_DSIZE;
  314. llb = (llBlock *)VirtualAlloc(NULL, alloc_size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
  315. llb->header.sizeused=size;
  316. llb->header.next = *start;
  317. *start = llb;
  318. return llb->block;
  319. }
  320. #define X86_MOV_EAX_DIRECTVALUE 0xB8
  321. #define X86_MOV_ESI_DIRECTVALUE 0xBE
  322. #define X86_MOV_ESI_DIRECTMEMVALUE 0x358B
  323. #define X86_PUSH_EAX 0x50
  324. #define X86_POP_EBX 0x5B
  325. #define X86_POP_ECX 0x59
  326. #define X86_MOV_ESI_EDI 0xF78B
  327. #define X86_PUSH_ESI 0x56
  328. #define X86_POP_ESI 0x5E
  329. #define X86_RET 0xC3
  330. //---------------------------------------------------------------------------------------------------------------
  331. static int *findFBlock(char *p)
  332. {
  333. while (*(int *)p != 0xFFFFFFFF) p++;
  334. return (int*)p;
  335. }
  336. //---------------------------------------------------------------------------------------------------------------
  337. int nseel_createCompiledValue(compileContext *ctx, double value, double *addrValue)
  338. {
  339. unsigned char *block = NULL;
  340. double *dupValue = NULL;
  341. block=(unsigned char *)newTmpBlock(4+5);
  342. if (addrValue == NULL)
  343. {
  344. ctx->l_stats[3]+=sizeof(double);
  345. *(dupValue = (double *)newBlock(sizeof(double))) = value;
  346. }
  347. else
  348. dupValue = addrValue;
  349. ((int*)block)[0]=5;
  350. block[4]=X86_MOV_EAX_DIRECTVALUE; // mov eax, <value>
  351. *(int *)(block+5) = (int)dupValue;
  352. return ((int)(block));
  353. }
  354. //---------------------------------------------------------------------------------------------------------------
  355. static int nseel_getFunctionAddress(int fntype, int fn, int *size, NSEEL_PPPROC *pProc)
  356. {
  357. *pProc = NULL;
  358. switch (fntype)
  359. {
  360. case MATH_SIMPLE:
  361. switch (fn)
  362. {
  363. case FN_ASSIGN:
  364. return (int)realAddress(nseel_asm_assign,nseel_asm_assign_end,size);
  365. case FN_ADD:
  366. return (int)realAddress(nseel_asm_add,nseel_asm_add_end,size);
  367. case FN_SUB:
  368. return (int)realAddress(nseel_asm_sub,nseel_asm_sub_end,size);
  369. case FN_MULTIPLY:
  370. return (int)realAddress(nseel_asm_mul,nseel_asm_mul_end,size);
  371. case FN_DIVIDE:
  372. return (int)realAddress(nseel_asm_div,nseel_asm_div_end,size);
  373. case FN_MODULO:
  374. return (int)realAddress(nseel_asm_mod,nseel_asm_mod_end,size);
  375. case FN_AND:
  376. return (int)realAddress(nseel_asm_and,nseel_asm_and_end,size);
  377. case FN_OR:
  378. return (int)realAddress(nseel_asm_or,nseel_asm_or_end,size);
  379. case FN_UPLUS:
  380. return (int)realAddress(nseel_asm_uplus,nseel_asm_uplus_end,size);
  381. case FN_UMINUS:
  382. return (int)realAddress(nseel_asm_uminus,nseel_asm_uminus_end,size);
  383. }
  384. case MATH_FN:
  385. {
  386. functionType *p=nseel_getFunctionFromTable(fn);
  387. if (!p)
  388. {
  389. if (size) *size=0;
  390. return 0;
  391. }
  392. if (p->pProc) *pProc=p->pProc;
  393. return (int)realAddress(p->afunc,p->func_e,size);
  394. }
  395. }
  396. return 0;
  397. }
  398. //---------------------------------------------------------------------------------------------------------------
  399. int nseel_createCompiledFunction3(compileContext *ctx, int fntype, int fn, int code1, int code2, int code3)
  400. {
  401. int sizes1=((int *)code1)[0];
  402. int sizes2=((int *)code2)[0];
  403. int sizes3=((int *)code3)[0];
  404. if (fntype == MATH_FN && fn == 0) // special case: IF
  405. {
  406. void *func3 = NULL;
  407. int size = 0;
  408. int *ptr = NULL;
  409. char *block = NULL;
  410. unsigned char *newblock2,*newblock3 = NULL;
  411. newblock2=newBlock(sizes2+1);
  412. memcpy(newblock2,(char*)code2+4,sizes2);
  413. newblock2[sizes2]=X86_RET;
  414. newblock3=newBlock(sizes3+1);
  415. memcpy(newblock3,(char*)code3+4,sizes3);
  416. newblock3[sizes3]=X86_RET;
  417. ctx->l_stats[2]+=sizes2+sizes3+2;
  418. func3 = realAddress(nseel_asm_if,nseel_asm_if_end,&size);
  419. block=(char *)newTmpBlock(4+sizes1+size);
  420. ((int*)block)[0]=sizes1+size;
  421. memcpy(block+4,(char*)code1+4,sizes1);
  422. ptr=(int *)(block+4+sizes1);
  423. memcpy(ptr,func3,size);
  424. ptr=findFBlock((char*)ptr); *ptr++=(int)newblock2;
  425. ptr=findFBlock((char*)ptr); *ptr=(int)newblock3;
  426. ctx->computTableTop++;
  427. return (int)block;
  428. }
  429. else
  430. {
  431. int size2 = 0;
  432. unsigned char *block = NULL;
  433. unsigned char *outp = NULL;
  434. int myfunc = 0;
  435. NSEEL_PPPROC preProc;
  436. myfunc = nseel_getFunctionAddress(fntype, fn, &size2, &preProc);
  437. block=(unsigned char *)newTmpBlock(4+size2+sizes1+sizes2+sizes3+4);
  438. ((int*)block)[0]=4+size2+sizes1+sizes2+sizes3;
  439. outp=block+4;
  440. memcpy(outp,(char*)code1+4,sizes1);
  441. outp+=sizes1;
  442. *outp++ = X86_PUSH_EAX;
  443. memcpy(outp,(char*)code2+4,sizes2);
  444. outp+=sizes2;
  445. *outp++ = X86_PUSH_EAX;
  446. memcpy(outp,(char*)code3+4,sizes3);
  447. outp+=sizes3;
  448. *outp++ = X86_POP_EBX;
  449. *outp++ = X86_POP_ECX;
  450. memcpy(outp,(void*)myfunc,size2);
  451. if (preProc) preProc(outp,size2,ctx->userfunc_data);
  452. ctx->computTableTop++;
  453. return ((int)(block));
  454. }
  455. }
  456. //---------------------------------------------------------------------------------------------------------------
  457. int nseel_createCompiledFunction2(compileContext *ctx, int fntype, int fn, int code1, int code2)
  458. {
  459. int size2 = 0;
  460. unsigned char *block = NULL;
  461. unsigned char *outp = NULL;
  462. int myfunc = 0;
  463. int sizes1=((int *)code1)[0];
  464. int sizes2=((int *)code2)[0];
  465. #ifdef NSEEL_LOOPFUNC_SUPPORT
  466. if (fntype == MATH_FN && fn == 1) // special case: REPEAT
  467. {
  468. void *func3 = NULL;
  469. int size = 0;
  470. int *ptr = NULL;
  471. char *block = NULL;
  472. unsigned char *newblock2 = NULL;
  473. newblock2=newBlock(sizes2+1);
  474. memcpy(newblock2,(char*)code2+4,sizes2);
  475. newblock2[sizes2]=X86_RET;
  476. ctx->l_stats[2]+=sizes2+2;
  477. func3 = realAddress(nseel_asm_repeat,nseel_asm_repeat_end,&size);
  478. block=(char *)newTmpBlock(4+sizes1+size);
  479. ((int*)block)[0]=sizes1+size;
  480. memcpy(block+4,(char*)code1+4,sizes1);
  481. ptr=(int *)(block+4+sizes1);
  482. memcpy(ptr,func3,size);
  483. ptr=findFBlock((char*)ptr); *ptr++=(int)newblock2;
  484. ctx->computTableTop++;
  485. return (int)block;
  486. }
  487. else
  488. #endif
  489. {
  490. NSEEL_PPPROC preProc;
  491. myfunc = nseel_getFunctionAddress(fntype, fn, &size2,&preProc);
  492. block=(unsigned char *)newTmpBlock(2+size2+sizes1+sizes2+4);
  493. ((int*)block)[0]=2+size2+sizes1+sizes2;
  494. outp=block+4;
  495. memcpy(outp,(char*)code1+4,sizes1);
  496. outp+=sizes1;
  497. *outp++ = X86_PUSH_EAX;
  498. memcpy(outp,(char*)code2+4,sizes2);
  499. outp+=sizes2;
  500. *outp++ = X86_POP_EBX;
  501. memcpy(outp,(void*)myfunc,size2);
  502. if (preProc) preProc(outp,size2,ctx->userfunc_data);
  503. ctx->computTableTop++;
  504. return ((int)(block));
  505. }
  506. }
  507. //---------------------------------------------------------------------------------------------------------------
  508. int nseel_createCompiledFunction1(compileContext *ctx, int fntype, int fn, int code)
  509. {
  510. NSEEL_PPPROC preProc;
  511. int size,size2 = 0;
  512. char *block = NULL;
  513. int myfunc = 0;
  514. void *func1 = NULL;
  515. size =((int *)code)[0];
  516. func1 = (void *)(code+4);
  517. myfunc = nseel_getFunctionAddress(fntype, fn, &size2,&preProc);
  518. block=(char *)newTmpBlock(4+size+size2);
  519. ((int*)block)[0]=size+size2;
  520. memcpy(block+4, func1, size);
  521. memcpy(block+size+4,(void*)myfunc,size2);
  522. if (preProc) preProc(block+size+4,size2,ctx->userfunc_data);
  523. ctx->computTableTop++;
  524. return ((int)(block));
  525. }
  526. static char *preprocessCode(compileContext *ctx, char *expression)
  527. {
  528. int len=0;
  529. int alloc_len=strlen(expression)+1+64;
  530. char *buf=(char *)malloc(alloc_len);
  531. while (*expression)
  532. {
  533. if (len > alloc_len-32)
  534. {
  535. alloc_len = len+128;
  536. buf=(char*)realloc(buf,alloc_len);
  537. }
  538. if (expression[0] == '/')
  539. {
  540. if (expression[1] == '/')
  541. {
  542. expression+=2;
  543. while (expression[0] && expression[0] != '\r' && expression[0] != '\n') expression++;
  544. }
  545. else if (expression[1] == '*')
  546. {
  547. expression+=2;
  548. while (expression[0] && (expression[0] != '*' || expression[1] != '/')) expression++;
  549. if (expression[0]) expression+=2; // at this point we KNOW expression[0]=* and expression[1]=/
  550. }
  551. else
  552. {
  553. char c=buf[len++]=*expression++;
  554. if (c != ' ' && c != '\t' && c != '\r' && c != '\n') ctx->l_stats[0]++;
  555. }
  556. }
  557. else if (expression[0] == '$')
  558. {
  559. if (ltoupper(expression[1]) == 'P' && ltoupper(expression[2]) == 'I')
  560. {
  561. static char *str="3.141592653589793";
  562. expression+=3;
  563. memcpy(buf+len,str,17);
  564. len+=17; //strlen(str);
  565. ctx->l_stats[0]+=17;
  566. }
  567. else if (ltoupper(expression[1]) == 'E')
  568. {
  569. static char *str="2.71828183";
  570. expression+=2;
  571. memcpy(buf+len,str,10);
  572. len+=10; //strlen(str);
  573. ctx->l_stats[0]+=10;
  574. }
  575. if (ltoupper(expression[1]) == 'P' && ltoupper(expression[2]) == 'H' && ltoupper(expression[3]) == 'I')
  576. {
  577. static char *str="1.61803399";
  578. expression+=4;
  579. memcpy(buf+len,str,10);
  580. len+=10; //strlen(str);
  581. ctx->l_stats[0]+=10;
  582. }
  583. else
  584. {
  585. char c = buf[len++]=*expression++;
  586. if (c != ' ' && c != '\t' && c != '\r' && c != '\n') ctx->l_stats[0]++;
  587. }
  588. }
  589. else
  590. {
  591. char c=*expression++;
  592. if (c == '\r' || c == '\n' || c == '\t') c=' ';
  593. buf[len++]=c;
  594. if (c != ' ') ctx->l_stats[0]++;
  595. }
  596. }
  597. buf[len]=0;
  598. return buf;
  599. }
  600. static void movestringover(char *str, int amount)
  601. {
  602. char tmp[1024+8];
  603. int l=(int)strlen(str);
  604. l=min(1024-amount-1,l);
  605. memcpy(tmp,str,l+1);
  606. while (l >= 0 && tmp[l]!='\n') l--;
  607. l++;
  608. tmp[l]=0;//ensure we null terminate
  609. memcpy(str+amount,tmp,l+1);
  610. }
  611. //------------------------------------------------------------------------------
  612. NSEEL_CODEHANDLE NSEEL_code_compile(NSEEL_VMCTX _ctx, char *_expression)
  613. {
  614. compileContext *ctx = (compileContext *)_ctx;
  615. char *expression,*expression_start;
  616. int computable_size=0;
  617. codeHandleType *handle;
  618. startPtr *scode=NULL;
  619. startPtr *startpts=NULL;
  620. if (!ctx || !_expression || !*_expression) return 0;
  621. ctx->last_error_string[0]=0;
  622. ctx->blocks_head=0;
  623. ctx->tmpblocks_head=0;
  624. memset(ctx->l_stats,0, sizeof(ctx->l_stats) / sizeof(ctx->l_stats[0]));
  625. handle = (codeHandleType*)newBlock(sizeof(codeHandleType));
  626. if (!handle)
  627. {
  628. return 0;
  629. }
  630. memset(handle,0,sizeof(codeHandleType));
  631. expression_start=expression=preprocessCode(ctx,_expression);
  632. while (*expression)
  633. {
  634. startPtr *tmp;
  635. char *expr;
  636. ctx->colCount=0;
  637. // single out segment
  638. while (*expression == ';' || *expression == ' ') expression++;
  639. if (!*expression) break;
  640. expr=expression;
  641. while (*expression && *expression != ';') expression++;
  642. if (*expression) *expression++ = 0;
  643. // parse
  644. tmp=(startPtr*) newTmpBlock(sizeof(startPtr));
  645. if (!tmp) break;
  646. ctx->computTableTop=0;
  647. tmp->startptr=nseel_compileExpression(ctx,expr);
  648. if (ctx->computTableTop > NSEEL_MAX_TEMPSPACE_ENTRIES- /* safety */ 16 - /* alignment */4 ||
  649. !tmp->startptr)
  650. {
  651. lstrcpyn(ctx->last_error_string,expr,sizeof(ctx->last_error_string)/sizeof(ctx->last_error_string[0]));
  652. scode=NULL;
  653. break;
  654. }
  655. if (computable_size < ctx->computTableTop)
  656. {
  657. computable_size=ctx->computTableTop;
  658. }
  659. tmp->next=NULL;
  660. if (!scode) scode=startpts=tmp;
  661. else
  662. {
  663. scode->next=tmp;
  664. scode=tmp;
  665. }
  666. }
  667. // check to see if failed on the first startingCode
  668. if (!scode)
  669. {
  670. freeBlocks((llBlock *)ctx->blocks_head); // free blocks
  671. handle=NULL; // return NULL (after resetting blocks_head)
  672. }
  673. else
  674. {
  675. // now we build one big code segment out of our list of them, inserting a mov esi, computable before each item
  676. unsigned char *writeptr;
  677. int size=1; // for ret at end :)
  678. startPtr *p;
  679. p=startpts;
  680. while (p)
  681. {
  682. size+=2; // mov esi, edi
  683. size+=*(int *)p->startptr;
  684. p=p->next;
  685. }
  686. handle->code = newBlock(size);
  687. if (handle->code)
  688. {
  689. writeptr=(unsigned char *)handle->code;
  690. p=startpts;
  691. while (p)
  692. {
  693. int thissize=*(int *)p->startptr;
  694. *(unsigned short *)writeptr= X86_MOV_ESI_EDI;
  695. writeptr+=2;
  696. memcpy(writeptr,(char*)p->startptr + 4,thissize);
  697. writeptr += thissize;
  698. p=p->next;
  699. }
  700. *writeptr=X86_RET; // ret
  701. ctx->l_stats[1]=size;
  702. }
  703. handle->blocks = ctx->blocks_head;
  704. handle->workTablePtr_size=(computable_size) * sizeof(double);
  705. }
  706. freeBlocks((llBlock *)ctx->tmpblocks_head); // free blocks
  707. ctx->tmpblocks_head=0;
  708. ctx->blocks_head=0;
  709. if (handle)
  710. {
  711. memcpy(handle->code_stats,ctx->l_stats,sizeof(ctx->l_stats));
  712. nseel_evallib_stats[0]+=ctx->l_stats[0];
  713. nseel_evallib_stats[1]+=ctx->l_stats[1];
  714. nseel_evallib_stats[2]+=ctx->l_stats[2];
  715. nseel_evallib_stats[3]+=ctx->l_stats[3];
  716. nseel_evallib_stats[4]++;
  717. }
  718. memset(ctx->l_stats,0,sizeof(ctx->l_stats));
  719. free(expression_start);
  720. return (NSEEL_CODEHANDLE)handle;
  721. }
  722. //------------------------------------------------------------------------------
  723. void NSEEL_code_execute(NSEEL_CODEHANDLE code)
  724. {
  725. #ifdef NSEEL_REENTRANT_EXECUTION
  726. int baseptr;
  727. #else
  728. static double _tab[NSEEL_MAX_TEMPSPACE_ENTRIES];
  729. int baseptr = (int) _tab;
  730. #endif
  731. codeHandleType *h = (codeHandleType *)code;
  732. if (!h || !h->code)
  733. return;
  734. #ifdef NSEEL_REENTRANT_EXECUTION
  735. baseptr = (int) alloca(h->workTablePtr_size + 16*sizeof(double) /*safety*/ + 32 /*alignment*/);
  736. if (!baseptr)
  737. return;
  738. #endif
  739. {
  740. int startPoint=(int)h->code;
  741. __asm
  742. {
  743. mov ebx, baseptr
  744. mov eax, startPoint
  745. pushad // Lets cover our ass
  746. add ebx, 31
  747. and ebx, ~31
  748. mov edi, ebx
  749. call eax
  750. popad
  751. }
  752. }
  753. }
  754. char *NSEEL_code_getcodeerror(NSEEL_VMCTX ctx)
  755. {
  756. compileContext *c=(compileContext *)ctx;
  757. if (ctx && c->last_error_string[0]) return c->last_error_string;
  758. return 0;
  759. }
  760. //------------------------------------------------------------------------------
  761. void NSEEL_code_free(NSEEL_CODEHANDLE code)
  762. {
  763. codeHandleType *h = (codeHandleType *)code;
  764. if (h != NULL)
  765. {
  766. nseel_evallib_stats[0]-=h->code_stats[0];
  767. nseel_evallib_stats[1]-=h->code_stats[1];
  768. nseel_evallib_stats[2]-=h->code_stats[2];
  769. nseel_evallib_stats[3]-=h->code_stats[3];
  770. nseel_evallib_stats[4]--;
  771. freeBlocks(h->blocks);
  772. }
  773. }
  774. //------------------------------------------------------------------------------
  775. void NSEEL_VM_resetvars(NSEEL_VMCTX _ctx)
  776. {
  777. if (_ctx)
  778. {
  779. compileContext *ctx=(compileContext *)_ctx;
  780. int x;
  781. if (ctx->varTable_Names || ctx->varTable_Values) for (x = 0; x < ctx->varTable_numBlocks; x ++)
  782. {
  783. if (ctx->varTable_Names)
  784. free(ctx->varTable_Names[x]);
  785. if (ctx->varTable_Values)
  786. free(ctx->varTable_Values[x]);
  787. }
  788. free(ctx->varTable_Values);
  789. free(ctx->varTable_Names);
  790. ctx->varTable_Values=0;
  791. ctx->varTable_Names=0;
  792. ctx->varTable_numBlocks=0;
  793. }
  794. }
  795. NSEEL_VMCTX NSEEL_VM_alloc() // return a handle
  796. {
  797. compileContext *ctx=calloc(1,sizeof(compileContext));
  798. return ctx;
  799. }
  800. void NSEEL_VM_free(NSEEL_VMCTX ctx) // free when done with a VM and ALL of its code have been freed, as well
  801. {
  802. free(ctx);
  803. }
  804. int *NSEEL_code_getstats(NSEEL_CODEHANDLE code)
  805. {
  806. codeHandleType *h = (codeHandleType *)code;
  807. if (h)
  808. {
  809. return h->code_stats;
  810. }
  811. return 0;
  812. }