y_inline.inc 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530
  1. /**--------------------------------------------------------------------------**\
  2. ===================================
  3. y_inline - PAWN inline functions.
  4. ===================================
  5. Description:
  6. This library allows a user to write inline functions in their script. It
  7. first detects all inline functions and generates data on them, such as
  8. parameter counts and addresses. When an inline function is passed in code
  9. its current context data is stored. Finally, when an inline function is
  10. found to be called at some point its current local stack is stored in global
  11. memory. When the function actually is called, the stack is restored, and
  12. additional parameters which are the inline function parameters, are passed.
  13. Legal:
  14. Version: MPL 1.1
  15. The contents of this file are subject to the Mozilla Public License Version
  16. 1.1 (the "License"); you may not use this file except in compliance with
  17. the License. You may obtain a copy of the License at
  18. http://www.mozilla.org/MPL/
  19. Software distributed under the License is distributed on an "AS IS" basis,
  20. WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  21. for the specific language governing rights and limitations under the
  22. License.
  23. The Original Code is the YSI AMX include.
  24. The Initial Developer of the Original Code is Alex "Y_Less" Cole.
  25. Portions created by the Initial Developer are Copyright (C) 2011
  26. the Initial Developer. All Rights Reserved.
  27. Contributors:
  28. ZeeX, koolk, JoeBullet/Google63, g_aSlice/Slice
  29. Thanks:
  30. JoeBullet/Google63 - Handy arbitrary ASM jump code using SCTRL.
  31. ZeeX - Very productive conversations.
  32. koolk - IsPlayerinAreaEx code.
  33. TheAlpha - Danish translation.
  34. breadfish - German translation.
  35. Fireburn - Dutch translation.
  36. yom - French translation.
  37. 50p - Polish translation.
  38. Zamaroht - Spanish translation.
  39. Dracoblue, sintax, mabako, Xtreme, other coders - Producing other modes
  40. for me to strive to better.
  41. Pixels^ - Running XScripters where the idea was born.
  42. Matite - Pestering me to release it and using it.
  43. Very special thanks to:
  44. Thiadmer - PAWN, whose limits continue to amaze me!
  45. Kye/Kalcor - SA:MP.
  46. SA:MP Team past, present and future - SA:MP.
  47. Version:
  48. 1.0
  49. Changelog:
  50. 20/10/12:
  51. Fixed a bug with "Callback_Release" with public functions.
  52. 15/11/11:
  53. Changed the precedence of "using" types.
  54. 19/09/11:
  55. First version
  56. </remarks>
  57. \**--------------------------------------------------------------------------**/
  58. #include "internal\y_version"
  59. #include "internal\y_funcinc"
  60. #include "y_amx"
  61. #include "y_utils"
  62. #include "y_malloc"
  63. #include "y_hooks"
  64. #if defined YSI_MALLOC_SECURE
  65. #error y_inline does not work with "YSI_MALLOC_SECURE" defined.
  66. #endif
  67. // "with inline X"
  68. // "with public X"
  69. // %0 = " in" or " pub" (ignored).
  70. // "%1 = "ne X" or "c X" (makes a macro).
  71. #define using%0) callback_tag:@Ik:@Il:%0)
  72. // Get ONLY this ONE parameter (this is a VERY important stage)!
  73. #define @Ik:@Il:%0, @Ip:@Iq:@Im:@Io:@Iw:|||%0|||,
  74. #define @Il:%0) @Ip:@Iq:@Im:@Io:@Iw:|||%0|||)
  75. // You can use "using InlineFunc" or the faster "using inline InlineFunc".
  76. /*#define @Ip:@Iq:@Im:@Io:@Iw:|||%0anonymous%1||| @Iu:@Iv:%0NULL%1||||
  77. #define @Iq:@Im:@Io:@Iw:|||%0callback%1||| @Ir:@Is:%1||||
  78. #define @Im:@Io:@Iw:|||%0inline%1||| @Iu:@Iv:%0%1||||
  79. #define @Io:@Iw:|||%0public%1||| @Ir:@Is:%1||||
  80. #define @Iw:|||%1||| @In:@It:%1||||*/
  81. #define @Ip:@Iq:@Im:@Io:@Iw:|||%0inline%1||| @Iu:@Iv:%0%1||||
  82. #define @Iq:@Im:@Io:@Iw:|||%0public%1||| @Ir:@Is:%1||||
  83. #define @Im:@Io:@Iw:|||%0anonymous%1||| @Iu:@Iv:%0NULL%1||||
  84. #define @Io:@Iw:|||%0callback%1||| @Ir:@Is:%1||||
  85. #define @Iw:|||%1||| @In:@It:%1||||
  86. // Callbacks with "On" in the name (often overidden by y_hooks and ALS).
  87. #define @Ir:@Is:%0On%1|||| @In:@It:#%0"On"#%1||||
  88. #define @Is:%0|||| @In:@It:#%0|||| //Using_unknown_callback
  89. // Callbacks with additional parameters (MUST have matching parameters (y_ini)).
  90. #define @In:@It:%0(%1)||||%2) %0%2,.bExtra=true,.extra=%1)
  91. #define @It:%0|||| %0
  92. // Inline function surpressing closures.
  93. #define @Iu:@Iv:%0$%1|||| (J@=0,_:@In:@It:%1|||| _Y_INLINE_END
  94. #define @Iv:%1|||| (J@=1,_:@In:@It:%1|||| _Y_INLINE_END
  95. // Defer adding the close bracket till after other macros have run.
  96. #define _Y_INLINE_END )
  97. ////////////////////////////////////////////////////////////////////////////////
  98. //// IF THESE EVER CHANGE (CAN'T SEE WHY), UPDATE _Inline_GetOpCodesX ////
  99. ////////////////////////////////////////////////////////////////////////////////
  100. #define INLINE_LOOP_PATTERN_0 0xA1E7C013
  101. #define INLINE_LOOP_PATTERN_1 0x42424242
  102. #define INLINE_LOOP_PATTERN_2 0x13C0E7A1
  103. #define INLINE_LOOP_PATTERN_3 0x21495359
  104. ////////////////////////////////////////////////////////////////////////////////
  105. //// IF THESE EVER CHANGE (CAN'T SEE WHY), UPDATE _Inline_GetOpCodesX ////
  106. ////////////////////////////////////////////////////////////////////////////////
  107. //#define INLINE_LOOP_PATTERNS INLINE_LOOP_PATTERN_0,INLINE_LOOP_PATTERN_1,INLINE_LOOP_PATTERN_2,INLINE_LOOP_PATTERN_3
  108. // This code uses a specialisation of my "tag macros" technique, embedding the
  109. // macro names in to a string instead of using them as tags. This does mean
  110. // that they will likely end up in the final AMX (unlike tag macros) but this
  111. // seems to be the only way to get this to work that I can see as there is no
  112. // variable reading involved.
  113. // The "inline" macro only has ":...", whereas the "anonymous" macro has ":...:"
  114. // because "inline" gets its second colon later on after all the parameter tag-
  115. // style macros. The structure for these extra cells is:
  116. //
  117. // 0 - Colon.
  118. // 1 - Pointer to next function name.
  119. // 2 - Pointer the the function.
  120. // 3 - Cells in the enclosing function at this point (passed and declared).
  121. // 4 - Parameters format.
  122. //
  123. #define inline%0(%1) new %0__;static const%0[]=#%0":..."#_YI@CP;for(new%1,,;Inline_Loop(.y=%0__,.f=%0);)
  124. #define callback:%0) const callback_tag:callback_check:%0£££
  125. #define callback_tag:callback_check:%0,%1£££ callback_tag:%0[],%1)
  126. #define callback_check:%0£££ %0[])
  127. #define anonymous%0(%1) new __anonVar;Q@=#_YI@CA;for(new%1,,;Inline_Loop(.y=__anonVar,.f=":...:"#);)
  128. #define _YI@CP;for(new%0,%1; @Ia#@Ib#@Ic#@Id#:;for(new @Iz|||%0|||%1;
  129. #define _YI@CA;for(new%0,%1; @If#@Ig#@Ih#@Ii#:;for(new @Iz|||%0|||%1;
  130. // Detect 0 parameters.
  131. #define @Ia#@Ib#@Ic#@Id#:;for(new%0||||||,;%1;) :;for(;%1;)
  132. // Detect strings (no array support YET).
  133. #define @Ib#@Ic#@Id#%9;for(new%0|||%1string:%2[%3]|||%4,%5; @Ib#@Ic#@Id#%9s;for(new%0,%2[YSI_MAX_STRING]|||%4|||%5;
  134. // Detect end of line.
  135. #define @Ic#@Id#%9;for(new%0|||%2|||%4,%5; @Ib#@Ic#@Id#%9i;for(new%0,%2|||%4|||%5;
  136. // Detect everything else.
  137. #define @Id#%9;for(new%0||||||; %9;for(new %0;
  138. // Drop the leading comma on the parameter list.
  139. #define @Iz,
  140. // Detect 0 parameters.
  141. #define @If#@Ig#@Ih#@Ii#:;for(new%0||||||,;%1;) :;for(;%1;)
  142. // Detect strings (no array support YET).
  143. #define @Ig#@Ih#@Ii#%9;for(new%0|||%1string:%2[%3]|||%4,%5;Inline_Loop(%6#%7) @Ig#@Ih#@Ii#%9;for(new%0,%2[YSI_MAX_STRING]|||%4|||%5;Inline_Loop(%6#%7s)
  144. // Detect end of line.
  145. #define @Ih#@Ii#%9;for(new%0|||%2|||%4,%5;Inline_Loop(%6#%7) @Ig#@Ih#@Ii#%9;for(new%0,%2|||%4|||%5;Inline_Loop(%6#%7i)
  146. // Detect everything else.
  147. #define @Ii#%9;for(new%0||||||; ;for(new%0;
  148. // Drop the leading comma on the parameter list.
  149. #define @Iz,
  150. static stock
  151. YSI_g_sFirstFunc = -1,
  152. YSI_g_sInInline = 0,
  153. //YSI_g_sLastFunc = -1,
  154. YSI_g_sReturn;
  155. enum e_CALLBACK_FLAGS (<<= 1)
  156. {
  157. // All this is required to correctly design the call stack.
  158. e_CALLBACK_FLAGS_PUSHED = 0x000000FF, // Parameters pushed to caller.
  159. e_CALLBACK_FLAGS_CREATED = 0x0FFFFF00, // Data size declared in caller.
  160. e_CALLBACK_FLAGS_PUBLIC = 0x10000000 // Is a public function.
  161. //e_CALLBACK_FLAGS_INLINE // Is an inline function.
  162. }
  163. enum E_CALLBACK_DATA
  164. {
  165. e_CALLBACK_FLAGS:E_CALLBACK_DATA_FLAGS,
  166. E_CALLBACK_DATA_POINTER, // Pointer to the function.
  167. E_CALLBACK_DATA_FORMAT, // Compressed destination format.
  168. Alloc:E_CALLBACK_DATA_ALLOC // Where our closure is stored.
  169. }
  170. static stock Inline_DoFormat(data[])
  171. {
  172. // This function encodes the data format in to a single cell. The format is:
  173. //
  174. // 1111111001
  175. //
  176. // Leading 1s indicate no data. The 0 immediately following the leading 1s
  177. // indicates the start of the format section (but is not PART of the format
  178. // section). The remaining bits represent either strings (1) or non-strings
  179. // (0). For example "(a, string:b, c)" would be:
  180. //
  181. // 1..10010
  182. //
  183. // Where "1..1" indicates full-cell padding of 1s. From this it is known that
  184. // the function takes three parameters: non-string, string, non-string. In
  185. // addition, as strings in inline functions MUST use the "string:" tag, it is
  186. // known that ALL strings will ALWAYS be 128 (or "YSI_MAX_STRING") cells big.
  187. new
  188. pos = strfind(data, ":"),
  189. //len = 0, //strlen(data),
  190. //bit = 1,
  191. total = 1;
  192. //printf("%s", data);
  193. //P:C(if (len - pos - 1 > 30) P:E("Inline functions only support up to 30 parameters"););
  194. if (pos != -1)
  195. {
  196. for ( ; ; )
  197. {
  198. // Now matchs the compile-time code much closer.
  199. switch (data[++pos])
  200. {
  201. case '\0':
  202. {
  203. break;
  204. }
  205. case 's':
  206. {
  207. total <<= 1;
  208. }
  209. default:
  210. {
  211. total = (total << 1) | 1;
  212. }
  213. }
  214. }
  215. }
  216. // Store the compressed format, also instantly end the string.
  217. data[0] = ~total;
  218. data[1] = '\0';
  219. //printf("%x", data[0]);
  220. return 1;
  221. }
  222. static stock Inline_FindFunction(const data[], const name[], address)
  223. {
  224. new
  225. value,
  226. len = strlen(name),
  227. tmp,
  228. candidate = cellmax,
  229. ret = -1;
  230. #emit LOAD.S.pri data
  231. #emit STOR.S.pri value
  232. // Check the "pointer" is valid.
  233. P:3("Inline_FindFunction called: %08x, %s, %s", value, data, name);
  234. while (value != -1)
  235. {
  236. if (strcmp(name, data, false, len) || data[len] != ':')
  237. {
  238. value = data[strlen(data) - 4];
  239. }
  240. else
  241. {
  242. /*printf("format = %04x%04x", data[len + 4] >>> 16, data[len + 4] & 0xFFFF);
  243. printf("%d", data[len + 1]);
  244. printf("%d", data[len + 2]);
  245. printf("%d", data[len + 3]);
  246. printf("%d", data[len + 4]);*/
  247. // Found a candidate. Now only finds the closest match BEFORE the call.
  248. tmp = address - data[len + 2];
  249. //if (0 < tmp < candidate)
  250. if (-5000 < tmp < 5000)
  251. {
  252. // Constrain the checks to +-5000 because of square integer limits and
  253. // to help reduce clashes.
  254. if ((tmp *= tmp) < candidate)
  255. {
  256. ret = value;
  257. candidate = tmp;
  258. //printf("candidate: %x", ret);
  259. }
  260. }
  261. value = data[len + 1];
  262. }
  263. // Move on to the next "pointer".
  264. #emit LOAD.S.pri value
  265. #emit STOR.S.pri data
  266. }
  267. return ret;
  268. }
  269. static stock Inline_FindAnonymous(const data[], address)
  270. {
  271. new
  272. value,
  273. tmp,
  274. candidate = cellmax,
  275. ret = -1;
  276. #emit LOAD.S.pri data
  277. #emit STOR.S.pri value
  278. // Check the "pointer" is valid.
  279. //printf("Inline_FindAnonymous %s %d %d", data, address, value);
  280. while (value != -1)
  281. {
  282. // Check if this is anonymous.
  283. //printf("%d %s %d %d %d", value, data, address, ret, candidate);
  284. if (data[0] == ':')
  285. {
  286. // Found a candidate.
  287. tmp = data[2] - address;
  288. // Make sure this is the closest anonymous function AFTER the return. We
  289. // don't need "0 <=" as it will never be INSTANTLY after the return
  290. // address due to the required "Inline_Loop" call.
  291. if (0 < tmp < candidate)
  292. {
  293. ret = value;
  294. candidate = tmp;
  295. }
  296. }
  297. //printf("%d %d %d,%d,%d,%d,%d", strlen(data), strlen(data) - 4, data[0], data[1], data[2], data[3], data[4]);
  298. value = data[strlen(data) - 4];
  299. // Move on to the next "pointer".
  300. #emit LOAD.S.pri value
  301. #emit STOR.S.pri data
  302. }
  303. //printf("Found anon: %d", ret);
  304. return ret;
  305. }
  306. forward _Inline_FixCompiler@@();
  307. public _Inline_FixCompiler@@()
  308. {
  309. // Call the function above at least once so the address exists in tables. But
  310. // never ACTUALLY call it at run-time (don't call this public function).
  311. Inline_DoFormat("");
  312. Inline_FindFunction("", "", 0);
  313. Inline_FindAnonymous("", 0);
  314. //memcpy("", "", 0, 0, 0);
  315. }
  316. forward _Inline_GetOpCodesX();
  317. public _Inline_GetOpCodesX()
  318. {
  319. Inline_Loop();
  320. return 0;
  321. }
  322. /*
  323. CODE 47 ; 835a0
  324. proc ; _Inline_GetOpCodesX
  325. ; line 168
  326. ; line 169
  327. push.c 229b24
  328. ;$par
  329. zero.pri
  330. heap 4
  331. stor.i
  332. push.alt
  333. ;$par
  334. push.c 21495359
  335. ;$par
  336. push.c 13c0e7a1
  337. ;$par
  338. push.c 42424242
  339. ;$par
  340. push.c a1e7c013
  341. ;$par
  342. push.c 18
  343. call Inline_Loop
  344. heap fffffffc
  345. ;$exp
  346. zero.pri
  347. retn
  348. */
  349. /*
  350. CODE 47 ; a333c
  351. proc ; _Inline_GetOpCodesX
  352. ; line 168
  353. break ; a3340
  354. ; line 169
  355. break ; a3344
  356. const.pri 229b24
  357. push.pri
  358. ;$par
  359. const.pri 0
  360. heap 4
  361. stor.i
  362. move.pri
  363. push.pri
  364. ;$par
  365. const.pri 21495359
  366. push.pri
  367. ;$par
  368. const.pri 13c0e7a1
  369. push.pri
  370. ;$par
  371. const.pri 42424242
  372. push.pri
  373. ;$par
  374. const.pri a1e7c013
  375. push.pri
  376. ;$par
  377. push.c 18
  378. call Inline_Loop
  379. heap fffffffc
  380. ;$exp
  381. zero.pri
  382. retn
  383. */
  384. hook OnScriptInit()
  385. {
  386. P:2("Inline_OnScriptInit");
  387. static
  388. sAddr,
  389. sType = 0,
  390. sSearch[15];
  391. if (!sType)
  392. {
  393. // We no longer need explicit assembly code to search for - we just
  394. // extract the exact code from "_Inline_GetOpCodesX". We also need to
  395. // later ignore that call to "Inline_Loop" in the search codes so it
  396. // doesn't think that reference dummy is a real inline function.
  397. new
  398. addr;
  399. // Get the data address of the function.
  400. #emit CONST.pri _Inline_GetOpCodesX
  401. #emit LOAD.alt AMX_HEADER_COD
  402. #emit ADD
  403. #emit STOR.S.pri addr
  404. if (AMX_Read(addr + 9 * 4) == INLINE_LOOP_PATTERN_3)
  405. {
  406. sAddr = addr + 8 * 4;
  407. P:5("Inline_OnScriptInit: Loading type 1");
  408. AMX_ReadArray(sAddr, sSearch, 11);
  409. P:7("Inline_OnScriptInit: Loaded type 1");
  410. sType = 1;
  411. }
  412. else if (AMX_Read(addr + 10 * 4) == INLINE_LOOP_PATTERN_3)
  413. {
  414. sAddr = addr + 9 * 4;
  415. P:5("Inline_OnScriptInit: Loading type 3");
  416. AMX_ReadArray(sAddr, sSearch, 11);
  417. P:7("Inline_OnScriptInit: Loaded type 3");
  418. sType = 3;
  419. }
  420. else if (AMX_Read(addr + 14 * 4) == INLINE_LOOP_PATTERN_3)
  421. {
  422. sAddr = addr + 13 * 4;
  423. P:5("Inline_OnScriptInit: Loading type 2");
  424. AMX_ReadArray(sAddr, sSearch, 15);
  425. P:7("Inline_OnScriptInit: Loaded type 2");
  426. sType = 2;
  427. }
  428. else
  429. {
  430. P:E("Could not determine pattern type in y_inline");
  431. sType = -1;
  432. }
  433. }
  434. P:7("Inline_OnScriptInit: Beginning search.");
  435. switch (sType)
  436. {
  437. case 1, 3:
  438. {
  439. Inline_DoSearch(sSearch, 3, 11, sAddr);
  440. }
  441. case 2:
  442. {
  443. Inline_DoSearch(sSearch, 5, 15, sAddr);
  444. }
  445. }
  446. // This could be Linux (we just don't know) - test by extracting the
  447. // currently used OpCodes from another function.
  448. // Different optimisation levels produce different sensibilities of code.
  449. /*if (Inline_DoSearch(sSearch1, 3) == -1)
  450. {
  451. // Pass the number of extra instructions before this code block.
  452. Inline_DoSearch(sSearch2, 5);
  453. }*/
  454. /*new
  455. p0 = Inline_DoSearch(sSearch1),
  456. // I could actually detect compilation flags in this way!
  457. p1 = Inline_DoSearch(sSearch2);
  458. if (p0 == -1 && p1 != -1)
  459. {
  460. // Compiled with "-d3". That's interesting but ultimately pointless.
  461. // And I can't detect this if they have no inline functions.
  462. }*/
  463. }
  464. static stock Inline_DoSearch(sSearch[], neg, size, ignore)
  465. {
  466. P:4("Inline_DoSearch called");
  467. new
  468. //str[32],
  469. addr,
  470. data,
  471. func;
  472. static
  473. last = -1;
  474. //printf("FIND FUNC: %s", sSearch);
  475. //while (AMX_TraceCode(sSearch, addr, func, size))
  476. for ( ; AMX_TraceCode(sSearch, addr, func, size); addr -= AMX_HEADER_COD - 24)
  477. {
  478. if (func == ignore) continue;
  479. P:4("Inline_DoSearch: %d %d %d", addr, func, size);
  480. // Get the function return address (make sure "pri" is always non-zero).
  481. func = addr + ((size + 1) * 4);
  482. //printf("stored function at %x", func);
  483. // Get the address of the last parameter.
  484. addr += (AMX_HEADER_COD - (neg * 4));
  485. //printf("FOUND FUNC: %d", addr);
  486. // Get the value of the last parameter.
  487. #emit LREF.S.pri addr
  488. #emit STOR.S.pri data
  489. // PERFECT! This assembly code worked FIRST TIME to correctly display
  490. // both the address and contents of the loaded string! Amazingly it
  491. // worked for anonymous functions too...
  492. //#emit PUSH.S data
  493. //#emit POP.pri
  494. // Anyway, now we need to see if this is a named or anonymous function
  495. // and plan accordingly. We don't need all the complex code of the
  496. // previous inline version. If we get a function call which takes an
  497. // anonymous function, just assume it is the next one found in the list
  498. // of stored inline function addresses. This has the HUGE added
  499. // advantage of allowing small bits of extra code to appear between the
  500. // function call and the inline function - i.e. we can allow return
  501. // values and allsorts now (including having functions taking anonymous
  502. // functions themselves being used as parameters).
  503. //new
  504. // pos = strfind(
  505. static const
  506. scSearch[] = ":";
  507. new
  508. pos = 0;
  509. #emit PUSH.C 0
  510. #emit PUSH.C 0
  511. #emit PUSH.C scSearch
  512. #emit PUSH.S data
  513. #emit PUSH.C 16
  514. #emit SYSREQ.C strfind
  515. #emit STOR.S.pri pos
  516. #emit STACK 20
  517. //printf("pos = %d, %d", pos, last);
  518. if (pos != -1)
  519. {
  520. if (last == -1)
  521. {
  522. YSI_g_sFirstFunc = data;
  523. }
  524. else
  525. {
  526. #emit LOAD.S.pri data
  527. #emit SREF.pri last
  528. }
  529. // Equivalent to: "data[pos + 1] = -1;" (1 cell = 4 bytes).
  530. data += pos * 4 + 4;
  531. #emit CONST.pri 0xFFFFFFFF
  532. #emit SREF.S.pri data
  533. // Equivalent to: "data[pos + 2] = func;"
  534. last = data;
  535. data += 4;
  536. //printf("pos = %d, %d", data, func);
  537. #emit LOAD.S.pri func
  538. #emit SREF.S.pri data
  539. // Now find and compress the format specifier (backwards).
  540. // Now compress the format in to a single cell (up to 32 parameters).
  541. #emit LOAD.S.pri data
  542. #emit ADD.C 8//4
  543. #emit PUSH.pri
  544. #emit PUSH.C 4
  545. // Using "CALL Inline_DoFormat" doesn't work, so do the next best thing.
  546. #emit LCTRL 6
  547. #emit ADD.C 28
  548. #emit PUSH.pri
  549. #emit CONST.pri Inline_DoFormat
  550. #emit SCTRL 6
  551. //pp(data - 8, str);
  552. }
  553. // Move on to find the next value. 24 is larger than both 12 and 20,
  554. // but is still a little hard-coded to the known code types.
  555. }
  556. return last;
  557. }
  558. stock Inline_Loop(p0 = INLINE_LOOP_PATTERN_0, p1 = INLINE_LOOP_PATTERN_1, p2 = INLINE_LOOP_PATTERN_2, p3 = INLINE_LOOP_PATTERN_3, &y = 0, volatile const f[] = "")
  559. //stock Inline_Loop(p0, p1, p2, p3, &__yil, volatile const format[])
  560. {
  561. #pragma unused p0, p1, p2, p3
  562. //#emit LOAD.S.pri 4
  563. //#emit STOR.S.pri p0
  564. //printf("ret: %d %d", p0, YSI_g_sInInline);
  565. if (y)
  566. {
  567. /*#emit LOAD.S.alt 0
  568. #emit MOVE.pri
  569. #emit ADD.C 4
  570. #emit LOAD.I
  571. #emit XCHG
  572. #emit LOAD.I
  573. #emit STOR.S.pri p0
  574. #emit MOVE.pri
  575. #emit STOR.S.pri p1
  576. printf("%d %d", p0, p1);*/
  577. // Somehow I need to check
  578. #emit LOAD.S.alt 0
  579. #emit MOVE.pri
  580. #emit ADD.C 4
  581. #emit LOAD.I
  582. #emit XCHG
  583. #emit LOAD.I
  584. #emit SCTRL 5
  585. #emit MOVE.pri
  586. #emit SCTRL 6
  587. }
  588. y = 1;
  589. static const
  590. scSearch[] = ":";
  591. // This function needs to be modified to store the stack size at this point
  592. // and write it to the relevant slot (easy since the relevant slot is
  593. // passed). I know "volatile const" makes no sense, but "const" is for the
  594. // compiler, "volatile" is to show that really it does change.
  595. #emit LOAD.S.pri 0
  596. #emit ADD.C 8
  597. #emit LOAD.I
  598. #emit PUSH.pri
  599. // Get the local variable sizes. Need to allocate the data somewhere.
  600. #emit LCTRL 5
  601. #emit LOAD.S.alt 0
  602. // Subtract the parameters passed to this function.
  603. #emit ADD.C 36 // 6 * 4 + 12
  604. #emit SUB.alt
  605. #emit PUSH.pri
  606. // Do strfind.
  607. #emit PUSH.C 0
  608. #emit PUSH.C 0
  609. #emit PUSH.C scSearch
  610. #emit PUSH.S f
  611. #emit PUSH.C 16
  612. #emit SYSREQ.C strfind
  613. #emit STACK 20
  614. // Save the data.
  615. #emit CONST.alt 4
  616. #emit SMUL
  617. #emit ADD.C 12
  618. #emit LOAD.S.alt f
  619. #emit ADD
  620. #emit STOR.S.pri f
  621. #emit POP.alt
  622. #emit SHL.C.alt 6
  623. #emit POP.pri
  624. #emit SHR.C.pri 2
  625. #emit ADD
  626. #emit SREF.S.pri f
  627. return 0;
  628. }
  629. stock Callback_Get(callback:name, result[E_CALLBACK_DATA], expect = -1)
  630. {
  631. new
  632. func,
  633. num,
  634. pos;
  635. P:2("Callback_Get called: %s %04x%04x", _:name, expect >>> 16, expect & 0xFFFF);
  636. if (isnull(_:name))
  637. {
  638. // Anonymous inline. Need to find the next available inline function based
  639. // on the return address of the calling function.
  640. // Get the return address.
  641. #emit LOAD.S.pri 0
  642. #emit ADD.C 4
  643. #emit LOAD.I
  644. // Call the function.
  645. #emit PUSH.pri
  646. //#emit PUSH.S name
  647. #emit PUSH YSI_g_sFirstFunc
  648. #emit PUSH.C 8
  649. #emit LCTRL 6
  650. #emit ADD.C 28
  651. #emit PUSH.pri
  652. #emit CONST.pri Inline_FindAnonymous
  653. #emit SCTRL 6
  654. #emit STOR.S.pri func
  655. if (func == -1)
  656. {
  657. return 0;
  658. }
  659. // Save the data.
  660. func += 2 * 4;
  661. #emit LREF.S.pri func
  662. #emit STOR.S.pri pos
  663. result[E_CALLBACK_DATA_POINTER] = pos;
  664. // Save the function parameters.
  665. func += 4;
  666. #emit LREF.S.pri func
  667. #emit STOR.S.pri pos
  668. result[E_CALLBACK_DATA_FLAGS] = e_CALLBACK_FLAGS:pos;
  669. func += 4;
  670. #emit LREF.S.pri func
  671. #emit STOR.S.pri pos
  672. result[E_CALLBACK_DATA_FORMAT] = pos;
  673. //printf("%x %x", expect, pos);
  674. if (expect != -1 && pos != expect)
  675. {
  676. P:E("Format specifier didn't match on anonymous function");
  677. }
  678. new
  679. mask = 0x80000000;
  680. // Skip leading 1s.
  681. while (pos & mask)
  682. {
  683. mask >>>= 1;
  684. }
  685. // Skip delimiting 0.
  686. mask >>>= 1;
  687. while (mask)
  688. {
  689. if (pos & mask)
  690. {
  691. num += YSI_MAX_STRING;
  692. }
  693. else
  694. {
  695. ++num;
  696. }
  697. mask >>>= 1;
  698. }
  699. }
  700. else
  701. {
  702. pos = strfind(name, ":");
  703. P:5("Callback_Get: %d, %d, %d, %d, %04x%04x", _:name[pos + 1], _:name[pos + 2], _:name[pos + 3] >>> 8, _:name[pos + 3] & 0xFF, _:name[pos + 4] >>> 16, _:name[pos + 4] & 0xFFFF);
  704. if (pos == -1)
  705. {
  706. if (AMX_GetPublicPointer(0, pos, name))
  707. {
  708. // Public function, use standard callback techniques (well, psudo-
  709. // standard, just store the address and use SCTRL manipulation).
  710. result[E_CALLBACK_DATA_POINTER] = pos;
  711. result[E_CALLBACK_DATA_FLAGS] = e_CALLBACK_FLAGS_PUBLIC;
  712. result[E_CALLBACK_DATA_FORMAT] = expect;
  713. return 1;
  714. }
  715. else
  716. {
  717. P:5("Callback_Get: Not got");
  718. // Get the caller frame.
  719. #emit LOAD.S.pri 0
  720. // Get the caller return.
  721. #emit ADD.C 4
  722. #emit LOAD.I
  723. // Now find the closest item with the correct name. Hopefully 99% of
  724. // the time there will only be one function with this name anywhere
  725. // NEAR the return address, so we can use that one. Otherwise we will
  726. // just have to hope that the closest is correct (maybe add a check to
  727. // see if it's too close, and if so alert the user).
  728. #emit PUSH.pri
  729. #emit PUSH.S name
  730. #emit PUSH YSI_g_sFirstFunc
  731. #emit PUSH.C 12
  732. #emit LCTRL 6
  733. #emit ADD.C 28
  734. #emit PUSH.pri
  735. #emit CONST.pri Inline_FindFunction
  736. #emit SCTRL 6
  737. #emit STOR.S.pri func
  738. // So now "func" is the address of the handle to the nearest data we can
  739. // extract all the relevant data.
  740. if (func == -1)
  741. {
  742. P:5("Callback_Get: inline/public not found");
  743. return 0;
  744. }
  745. P:5("Callback_Get: inline/public found: %08x", func);
  746. // Save the function pointer.
  747. func += strlen(name) * 4 + 2 * 4;
  748. P:5("Callback_Get: inline/public found: %08x", func);
  749. //#emit LREF.S.pri func
  750. //pos = 444;
  751. #emit LOAD.S.pri func
  752. #emit LOAD.I
  753. #emit STOR.S.pri pos
  754. //printf("%d", pos);
  755. result[E_CALLBACK_DATA_POINTER] = pos;
  756. // Save the function parameters.
  757. func += 4;
  758. #emit LREF.S.pri func
  759. #emit STOR.S.pri pos
  760. //printf("%d", pos);
  761. result[E_CALLBACK_DATA_FLAGS] = e_CALLBACK_FLAGS:pos;
  762. // Save the function format.
  763. func += 4;
  764. //--pos;
  765. #emit LREF.S.pri func
  766. #emit STOR.S.pri pos
  767. //printf("%d", pos);
  768. result[E_CALLBACK_DATA_FORMAT] = pos;
  769. P:5("Callback_Get: Getting inline %s format", name);
  770. if (expect != -1 && pos != expect)
  771. {
  772. P:E("Format specifier didn't match on inline function %s: %04x%04x != %04x%04x", name, pos >>> 16, pos & 0xFFFF, expect >>> 16, expect & 0xFFFF);
  773. }
  774. new
  775. mask = 0x80000000;
  776. // Skip leading 1s.
  777. while (pos & mask)
  778. {
  779. mask >>>= 1;
  780. }
  781. // Skip delimiting 0.
  782. mask >>>= 1;
  783. while (mask)
  784. {
  785. if (pos & mask)
  786. {
  787. num += YSI_MAX_STRING;
  788. }
  789. else
  790. {
  791. ++num;
  792. }
  793. mask >>>= 1;
  794. }
  795. }
  796. }
  797. else
  798. {
  799. // Named and qualified inline function. Should also include the correct
  800. // addresses. By FAR the fastest method as we already have all the data.
  801. result[E_CALLBACK_DATA_POINTER] = name[pos + 2];
  802. result[E_CALLBACK_DATA_FLAGS] = e_CALLBACK_FLAGS:name[pos + 3];
  803. new
  804. form = name[pos + 4];
  805. result[E_CALLBACK_DATA_FORMAT] = form;
  806. P:5("Callback_Get: Getting public %s format", name);
  807. if (expect != -1 && form != expect)
  808. {
  809. P:E("Format specifier didn't match on inline function %s", name);
  810. }
  811. // Get the size of inline function parameters:
  812. new
  813. mask = 0x80000000;
  814. // Skip leading 1s.
  815. while (form & mask)
  816. {
  817. mask >>>= 1;
  818. }
  819. // Skip delimiting 0.
  820. mask >>>= 1;
  821. while (mask)
  822. {
  823. if (form & mask)
  824. {
  825. num += YSI_MAX_STRING;
  826. }
  827. else
  828. {
  829. ++num;
  830. }
  831. mask >>>= 1;
  832. }
  833. }
  834. }
  835. // Now we need to somehow store all this data somewhere (including, for
  836. // speed, the extra data involved in calling a function). Here "pos" is the
  837. // number of bytes pushed to the owning function.
  838. P:6("%04x%04x %04x%04x", _:result[E_CALLBACK_DATA_FLAGS] >>> 16, _:result[E_CALLBACK_DATA_FLAGS] & 0xFFFF, (num >>> 8), (num << 8) & 0xFFFF);
  839. result[E_CALLBACK_DATA_FLAGS] -= e_CALLBACK_FLAGS:(num << 8);
  840. pos = _:result[E_CALLBACK_DATA_FLAGS];
  841. // Get the size of the closure.
  842. func = (pos & 0xFF);
  843. pos = (pos >>> 8); // - num;
  844. func = func + pos + 3;
  845. new
  846. Alloc:alloc = malloc(func);
  847. if (alloc == NO_ALLOC)
  848. {
  849. return 0;
  850. }
  851. result[E_CALLBACK_DATA_ALLOC] = alloc;
  852. // Now we need to copy the data from the previous-but-one frame to this
  853. // allocated location. Copy the whole lot, including passed parameters.
  854. #emit LOAD.S.pri pos
  855. #emit SMUL.C 4
  856. #emit MOVE.alt
  857. #emit LOAD.S.pri 0
  858. #emit LOAD.I
  859. #emit SUB
  860. #emit STOR.S.pri name
  861. memcpy(YSI_gMallocMemory[_:alloc], name, 0, func * 4, func);
  862. return 1;
  863. }
  864. stock Callback_Release(const input[E_CALLBACK_DATA])
  865. {
  866. if (!(input[E_CALLBACK_DATA_FLAGS] & e_CALLBACK_FLAGS_PUBLIC))
  867. {
  868. // Publics don't have any stored data.
  869. free(input[E_CALLBACK_DATA_ALLOC]);
  870. }
  871. }
  872. stock Callback_Call(const result[E_CALLBACK_DATA], GLOBAL_TAG_TYPES:...)
  873. {
  874. // Call the function with the given data. We need some serious stack
  875. // manipulation skills in here to make it all work.
  876. //printf("Calling function at %d", _:result[E_CALLBACK_DATA_FLAGS]);
  877. if (result[E_CALLBACK_DATA_FLAGS] & e_CALLBACK_FLAGS_PUBLIC)
  878. {
  879. // I think I've got an even better way. NOPE! None of this code will
  880. // work because all the parameters are passed by reference, not by
  881. // value! This is VERY VERY bad! D'oh! Good thing I kept a copy of
  882. // the old code! Shame, this would have been very elegant. Sweet, it
  883. // seemed to work as well! Maybe I could just do some similar in-line
  884. // variable modifications.
  885. new
  886. par,
  887. pointer = result[E_CALLBACK_DATA_POINTER],
  888. mask = result[E_CALLBACK_DATA_FORMAT];
  889. // Destroy one parameter.
  890. //#emit PUSH.S 8
  891. #emit LOAD.S.alt 8
  892. #emit PUSH.alt
  893. //#emit ADD.C 0xFFFFFFFC
  894. //#emit PUSH.pri
  895. // Move the return address.
  896. #emit LOAD.S.pri 4
  897. #emit STOR.S.pri 8
  898. // Move the frame.
  899. #emit LOAD.S.pri 0
  900. #emit STOR.S.pri 4
  901. // Fix the parameters.
  902. #emit LCTRL 5
  903. #emit ADD
  904. #emit ADD.C 12
  905. #emit STOR.S.pri par
  906. // Get the jump address.
  907. //while (mask != ~1)
  908. // If no format has been provided, just guess and pass every parameter
  909. // by reference (as they are passed to here).
  910. while (mask != -1)
  911. {
  912. par -= 4;
  913. if (!(mask & 1))
  914. {
  915. #emit LREF.S.pri par
  916. #emit LOAD.I
  917. #emit SREF.S.pri par
  918. }
  919. mask >>= 1;
  920. }
  921. //#emit LOAD.S.pri 8
  922. #emit POP.pri
  923. #emit ADD.C 0xFFFFFFFC
  924. #emit STOR.S.pri 12
  925. //#emit ADD.C 4
  926. //#emit ADD.C 4
  927. //#emit MOVE.alt
  928. #emit LOAD.S.alt pointer
  929. // Mangle the stack (no variables from here).
  930. #emit LCTRL 5
  931. #emit ADD.C 4
  932. #emit SCTRL 4
  933. #emit SCTRL 5
  934. // Jump to new code (after "PROC").
  935. #emit MOVE.pri
  936. #emit ADD.C 4
  937. #emit SCTRL 6
  938. // Will never be called.
  939. //#emit RETN
  940. }
  941. else
  942. {
  943. new
  944. size = _:result[E_CALLBACK_DATA_FLAGS],
  945. num = 0,
  946. stack,
  947. mask = 0x80000000,
  948. addr,
  949. tmp;
  950. //YSI_g_sInInline = result[E_CALLBACK_DATA_POINTER];
  951. // ininline = YSI_g_sInInline;
  952. YSI_g_sInInline = result[E_CALLBACK_DATA_POINTER];
  953. //printf("Calling function at 0x%08x", YSI_g_sInInline);
  954. size = ((size & 0xFF) + (size >>> 8) + 3) * 4;
  955. #emit LCTRL 4
  956. #emit STOR.S.pri stack
  957. #emit LOAD.S.alt size
  958. #emit SUB
  959. #emit STOR.S.pri addr
  960. // Add more data for additional parameters.
  961. #emit SCTRL 4
  962. //#emit LCTRL 4
  963. size = result[E_CALLBACK_DATA_FORMAT];
  964. #emit LCTRL 5
  965. #emit ADD.C 16
  966. #emit STOR.S.pri tmp
  967. // OK, now the fun bit!
  968. while (size & mask)
  969. {
  970. mask >>>= 1;
  971. }
  972. mask >>>= 1;
  973. while (mask)
  974. {
  975. if (size & mask)
  976. {
  977. num += YSI_MAX_STRING;
  978. addr -= YSI_MAX_STRING * 4;
  979. //printf("copying string");
  980. #emit LOAD.S.pri addr
  981. #emit SCTRL 4
  982. // Copy the data.
  983. #emit PUSH.C 130
  984. #emit PUSH.C 520
  985. #emit PUSH.C 0
  986. #emit LREF.S.pri tmp
  987. #emit PUSH.pri
  988. #emit PUSH.S addr
  989. #emit PUSH.C 20
  990. #emit SYSREQ.C memcpy
  991. #emit STACK 24
  992. //printf("finished");
  993. }
  994. else
  995. {
  996. num += 1;
  997. addr -= 1 * 4;
  998. #emit LREF.S.pri tmp
  999. #emit LOAD.I
  1000. #emit PUSH.pri
  1001. }
  1002. mask >>>= 1;
  1003. tmp += 4;
  1004. }
  1005. #emit LCTRL 5
  1006. #emit STOR.S.pri tmp
  1007. num *= 4;
  1008. addr += num;
  1009. // "addr" now contains the params stack address, "stack" contains the
  1010. // starting stack address. This code technically pushes an incorrect
  1011. // destination size (it's 4x too big), but as the bytes to copy is
  1012. // smaller this is not important.
  1013. // Set the frame pointer.
  1014. size = _:result[E_CALLBACK_DATA_FLAGS];
  1015. #emit LOAD.S.pri size
  1016. #emit SHR.C.pri 8
  1017. #emit SHL.C.pri 2 // NOT SHR 6
  1018. #emit LOAD.S.alt addr
  1019. #emit ADD
  1020. #emit STOR.S.pri tmp
  1021. // Copy the data.
  1022. size = ((size & 0xFF) + (size >>> 8) + 3) * 4;
  1023. num = _:result[E_CALLBACK_DATA_ALLOC];
  1024. #emit LOAD.S.pri size
  1025. #emit PUSH.pri
  1026. #emit PUSH.pri
  1027. #emit PUSH.C 0
  1028. #emit CONST.alt YSI_gMallocMemory
  1029. #emit LOAD.S.pri num
  1030. #emit IDXADDR
  1031. #emit PUSH.pri
  1032. #emit PUSH.S addr
  1033. #emit PUSH.C 20
  1034. #emit SYSREQ.C memcpy
  1035. #emit STACK 24
  1036. // Store the return frame.
  1037. #emit LOAD.S.alt tmp
  1038. #emit LCTRL 5
  1039. #emit STOR.I
  1040. #emit MOVE.pri
  1041. #emit ADD.C 4
  1042. #emit MOVE.alt
  1043. // Get the return address and call the function.
  1044. #emit LCTRL 6
  1045. #emit ADD.C 48 // 8
  1046. #emit STOR.I // 12
  1047. #emit LOAD.alt YSI_g_sInInline // 20
  1048. #emit LOAD.S.pri tmp // 28
  1049. #emit SCTRL 5 // 36
  1050. #emit MOVE.pri // 40
  1051. #emit SCTRL 6 // 48
  1052. // Restore the stack.
  1053. //printf("one");
  1054. #emit LOAD.S.pri stack
  1055. #emit SCTRL 4
  1056. //printf("two");
  1057. //YSI_g_sInInline = ininline;
  1058. }
  1059. }
  1060. // HOPEFULLY will derive the compressed format specifier for a function, with
  1061. // anything not "s" zero.
  1062. //#define _S<%0> (-1&_:@Rx:@Ry:@Rw:@Rv:@Ru:(0,%0,0))
  1063. #define _F<%0> (-1&_:~@Rx:@Ry:@Rv:@Ru:@Rw:(1,%0))
  1064. #define @Rx:@Ry:@Rv:@Ru:@Rw:(%9,s%0) @Rx:@Ry:@Rv:@Ru:@Rw:((%9)<<1,%0)
  1065. #define @Ry:@Rv:@Ru:@Rw:(%9,i%0) @Rx:@Ry:@Rv:@Ru:@Rw:((%9)<<1|1,%0)
  1066. #define @Rv:@Ru:@Rw:(%9,d%0) @Rx:@Ry:@Rv:@Ru:@Rw:((%9)<<1|1,%0)
  1067. #define @Ru:@Rw:(%9,f%0) @Rx:@Ry:@Rv:@Ru:@Rw:((%9)<<1|1,%0)
  1068. #define @Rw:(%9,) (%9)
  1069. /*#define @Ru:(%0i,%1) ~(1<<%1)&@Rx:@Ry:@Rw:@Rv:@Ru:(%0,%1+1)
  1070. #define @Rv:@Ru:(%0d,%1) ~(1<<%1)&@Rx:@Ry:@Rw:@Rv:@Ru:(%0,%1+1)
  1071. #define @Rw:@Rv:@Ru:(%0f,%1) ~(1<<%1)&@Rx:@Ry:@Rw:@Rv:@Ru:(%0,%1+1)
  1072. #define @Rx:@Ry:@Rw:@Rv:@Ru:(%0s,%1) @Rx:@Ry:@Rw:@Rv:@Ru:(%0,%1+1)
  1073. #define @Ry:@Rw:@Rv:@Ru:(,%1) ~(1<<%1)*/
  1074. // This is very similar to Callback_Call, but takes an array of ADDRESSES
  1075. // instead of normal parameters. This is designed to help support some
  1076. // experimental OO code I was working on...
  1077. stock Callback_Array(const result[E_CALLBACK_DATA], const params[])
  1078. {
  1079. #pragma unused params
  1080. // Call the function with the given data. We need some serious stack
  1081. // manipulation skills in here to make it all work.
  1082. if (result[E_CALLBACK_DATA_FLAGS] & e_CALLBACK_FLAGS_PUBLIC)
  1083. {
  1084. // I think I've got an even better way. NOPE! None of this code will
  1085. // work because all the parameters are passed by reference, not by
  1086. // value! This is VERY VERY bad! D'oh! Good thing I kept a copy of
  1087. // the old code! Shame, this would have been very elegant. Sweet, it
  1088. // seemed to work as well! Maybe I could just do some similar in-line
  1089. // variable modifications.
  1090. new
  1091. par,
  1092. pointer = result[E_CALLBACK_DATA_POINTER],
  1093. mask = result[E_CALLBACK_DATA_FORMAT];
  1094. // Destroy one parameter.
  1095. //#emit PUSH.S 8
  1096. #emit LOAD.S.alt 8
  1097. #emit PUSH.alt
  1098. //#emit ADD.C 0xFFFFFFFC
  1099. //#emit PUSH.pri
  1100. // Move the return address.
  1101. #emit LOAD.S.pri 4
  1102. #emit STOR.S.pri 8
  1103. // Move the frame.
  1104. #emit LOAD.S.pri 0
  1105. #emit STOR.S.pri 4
  1106. // Fix the parameters.
  1107. #emit LCTRL 5
  1108. #emit ADD
  1109. #emit ADD.C 12
  1110. #emit STOR.S.pri par
  1111. // Get the jump address.
  1112. //while (mask != ~1)
  1113. // If no format has been provided, just guess and pass every parameter
  1114. // by reference (as they are passed to here).
  1115. while (mask != -1)
  1116. {
  1117. par -= 4;
  1118. if (!(mask & 1))
  1119. {
  1120. #emit LREF.S.pri par
  1121. #emit LOAD.I
  1122. #emit SREF.S.pri par
  1123. }
  1124. mask >>= 1;
  1125. }
  1126. //#emit LOAD.S.pri 8
  1127. #emit POP.pri
  1128. #emit ADD.C 0xFFFFFFFC
  1129. #emit STOR.S.pri 12
  1130. //#emit ADD.C 4
  1131. //#emit ADD.C 4
  1132. //#emit MOVE.alt
  1133. #emit LOAD.S.alt pointer
  1134. // Mangle the stack (no variables from here).
  1135. #emit LCTRL 5
  1136. #emit ADD.C 4
  1137. #emit SCTRL 4
  1138. #emit SCTRL 5
  1139. // Jump to new code (after "PROC").
  1140. #emit MOVE.pri
  1141. #emit ADD.C 4
  1142. #emit SCTRL 6
  1143. // Will never be called.
  1144. //#emit RETN
  1145. }
  1146. else
  1147. {
  1148. new
  1149. size = _:result[E_CALLBACK_DATA_FLAGS],
  1150. num = 0,
  1151. stack,
  1152. mask = 0x80000000,
  1153. addr,
  1154. tmp;
  1155. //YSI_g_sInInline = result[E_CALLBACK_DATA_POINTER];
  1156. // ininline = YSI_g_sInInline;
  1157. YSI_g_sInInline = result[E_CALLBACK_DATA_POINTER];
  1158. size = ((size & 0xFF) + (size >>> 8) + 3) * 4;
  1159. #emit LCTRL 4
  1160. #emit STOR.S.pri stack
  1161. #emit LOAD.S.alt size
  1162. #emit SUB
  1163. #emit STOR.S.pri addr
  1164. // Add more data for additional parameters.
  1165. #emit SCTRL 4
  1166. //#emit LCTRL 4
  1167. size = result[E_CALLBACK_DATA_FORMAT];
  1168. #emit LCTRL 5
  1169. #emit ADD.C 16
  1170. #emit LOAD.I
  1171. #emit STOR.S.pri tmp
  1172. // OK, now the fun bit!
  1173. while (size & mask)
  1174. {
  1175. mask >>>= 1;
  1176. }
  1177. mask >>>= 1;
  1178. while (mask)
  1179. {
  1180. if (size & mask)
  1181. {
  1182. num += YSI_MAX_STRING;
  1183. addr -= YSI_MAX_STRING * 4;
  1184. //printf("copying string");
  1185. #emit LOAD.S.pri addr
  1186. #emit SCTRL 4
  1187. // Copy the data.
  1188. #emit PUSH.C 130
  1189. #emit PUSH.C 520
  1190. #emit PUSH.C 0
  1191. #emit LREF.S.pri tmp
  1192. #emit PUSH.pri
  1193. #emit PUSH.S addr
  1194. #emit PUSH.C 20
  1195. #emit SYSREQ.C memcpy
  1196. #emit STACK 24
  1197. //printf("finished");
  1198. }
  1199. else
  1200. {
  1201. num += 1;
  1202. addr -= 1 * 4;
  1203. #emit LREF.S.pri tmp
  1204. #emit LOAD.I
  1205. #emit PUSH.pri
  1206. }
  1207. mask >>>= 1;
  1208. tmp += 4;
  1209. }
  1210. #emit LCTRL 5
  1211. #emit STOR.S.pri tmp
  1212. num *= 4;
  1213. addr += num;
  1214. // "addr" now contains the params stack address, "stack" contains the
  1215. // starting stack address. This code technically pushes an incorrect
  1216. // destination size (it's 4x too big), but as the bytes to copy is
  1217. // smaller this is not important.
  1218. // Set the frame pointer.
  1219. size = _:result[E_CALLBACK_DATA_FLAGS];
  1220. #emit LOAD.S.pri size
  1221. #emit SHR.C.pri 8
  1222. #emit SHL.C.pri 2 // NOT SHR 6
  1223. #emit LOAD.S.alt addr
  1224. #emit ADD
  1225. #emit STOR.S.pri tmp
  1226. // Copy the data.
  1227. size = ((size & 0xFF) + (size >>> 8) + 3) * 4;
  1228. num = _:result[E_CALLBACK_DATA_ALLOC];
  1229. #emit LOAD.S.pri size
  1230. #emit PUSH.pri
  1231. #emit PUSH.pri
  1232. #emit PUSH.C 0
  1233. #emit CONST.alt YSI_gMallocMemory
  1234. #emit LOAD.S.pri num
  1235. #emit IDXADDR
  1236. #emit PUSH.pri
  1237. #emit PUSH.S addr
  1238. #emit PUSH.C 20
  1239. #emit SYSREQ.C memcpy
  1240. #emit STACK 24
  1241. // Store the return frame.
  1242. #emit LOAD.S.alt tmp
  1243. #emit LCTRL 5
  1244. #emit STOR.I
  1245. #emit MOVE.pri
  1246. #emit ADD.C 4
  1247. #emit MOVE.alt
  1248. // Get the return address and call the function.
  1249. #emit LCTRL 6
  1250. #emit ADD.C 48 // 8
  1251. #emit STOR.I // 12
  1252. #emit LOAD.alt YSI_g_sInInline // 20
  1253. #emit LOAD.S.pri tmp // 28
  1254. #emit SCTRL 5 // 36
  1255. #emit MOVE.pri // 40
  1256. #emit SCTRL 6 // 48
  1257. // Restore the stack.
  1258. //printf("one");
  1259. #emit LOAD.S.pri stack
  1260. #emit SCTRL 4
  1261. //printf("two");
  1262. //YSI_g_sInInline = ininline;
  1263. }
  1264. }
  1265. // This is very similar to Callback_Call, but takes an allocated block of stack.
  1266. stock Callback_Block(const result[E_CALLBACK_DATA], const params[], num)
  1267. {
  1268. #pragma unused params
  1269. // Call the function with the given data. We need some serious stack
  1270. // manipulation skills in here to make it all work.
  1271. if (result[E_CALLBACK_DATA_FLAGS] & e_CALLBACK_FLAGS_PUBLIC)
  1272. {
  1273. // I think I've got an even better way. NOPE! None of this code will
  1274. // work because all the parameters are passed by reference, not by
  1275. // value! This is VERY VERY bad! D'oh! Good thing I kept a copy of
  1276. // the old code! Shame, this would have been very elegant. Sweet, it
  1277. // seemed to work as well! Maybe I could just do some similar in-line
  1278. // variable modifications.
  1279. new
  1280. par,
  1281. pointer = result[E_CALLBACK_DATA_POINTER],
  1282. mask = result[E_CALLBACK_DATA_FORMAT];
  1283. // Destroy one parameter.
  1284. //#emit PUSH.S 8
  1285. #emit LOAD.S.alt 8
  1286. #emit PUSH.alt
  1287. //#emit ADD.C 0xFFFFFFFC
  1288. //#emit PUSH.pri
  1289. // Move the return address.
  1290. #emit LOAD.S.pri 4
  1291. #emit STOR.S.pri 8
  1292. // Move the frame.
  1293. #emit LOAD.S.pri 0
  1294. #emit STOR.S.pri 4
  1295. // Fix the parameters.
  1296. #emit LCTRL 5
  1297. #emit ADD
  1298. #emit ADD.C 12
  1299. #emit STOR.S.pri par
  1300. // Get the jump address.
  1301. //while (mask != ~1)
  1302. // If no format has been provided, just guess and pass every parameter
  1303. // by reference (as they are passed to here).
  1304. while (mask != -1)
  1305. {
  1306. par -= 4;
  1307. if (!(mask & 1))
  1308. {
  1309. #emit LREF.S.pri par
  1310. #emit LOAD.I
  1311. #emit SREF.S.pri par
  1312. }
  1313. mask >>= 1;
  1314. }
  1315. //#emit LOAD.S.pri 8
  1316. #emit POP.pri
  1317. #emit ADD.C 0xFFFFFFFC
  1318. #emit STOR.S.pri 12
  1319. //#emit ADD.C 4
  1320. //#emit ADD.C 4
  1321. //#emit MOVE.alt
  1322. #emit LOAD.S.alt pointer
  1323. // Mangle the stack (no variables from here).
  1324. #emit LCTRL 5
  1325. #emit ADD.C 4
  1326. #emit SCTRL 4
  1327. #emit SCTRL 5
  1328. // Jump to new code (after "PROC").
  1329. #emit MOVE.pri
  1330. #emit ADD.C 4
  1331. #emit SCTRL 6
  1332. // Will never be called.
  1333. //#emit RETN
  1334. }
  1335. else
  1336. {
  1337. new
  1338. size = _:result[E_CALLBACK_DATA_FLAGS],
  1339. //num = 0,
  1340. stack,
  1341. //mask = 0x80000000,
  1342. addr,
  1343. tmp;
  1344. //YSI_g_sInInline = result[E_CALLBACK_DATA_POINTER];
  1345. // ininline = YSI_g_sInInline;
  1346. YSI_g_sInInline = result[E_CALLBACK_DATA_POINTER];
  1347. size = ((size & 0xFF) + (size >>> 8) + 3) * 4;
  1348. #emit LCTRL 4
  1349. #emit STOR.S.pri stack
  1350. #emit LOAD.S.alt size
  1351. #emit SUB
  1352. #emit STOR.S.pri addr
  1353. // Add more data for additional parameters.
  1354. #emit SCTRL 4
  1355. //#emit LCTRL 4
  1356. size = result[E_CALLBACK_DATA_FORMAT];
  1357. //#emit LCTRL 5
  1358. //#emit ADD.C 16
  1359. //#emit LOAD.I
  1360. //#emit STOR.S.pri tmp
  1361. // OK, now the fun bit!
  1362. //num = Malloc_SlotSize(params) - 2;
  1363. addr -= num * 4;
  1364. // Increase the stack size.
  1365. #emit LOAD.S.pri addr
  1366. #emit SCTRL 4
  1367. // Copy the data.
  1368. #emit LOAD.S.pri num
  1369. // Destination size.
  1370. #emit PUSH.pri
  1371. #emit SMUL.C 4
  1372. // Number of bytes.
  1373. #emit PUSH.pri
  1374. // 0.
  1375. #emit PUSH.C 0
  1376. #emit PUSH.S params
  1377. #emit PUSH.S addr
  1378. #emit PUSH.C 20
  1379. #emit SYSREQ.C memcpy
  1380. #emit STACK 24
  1381. //tmp =
  1382. /*while (size & mask)
  1383. {
  1384. mask >>>= 1;
  1385. }
  1386. mask >>>= 1;
  1387. while (mask)
  1388. {
  1389. if (size & mask)
  1390. {
  1391. num += YSI_MAX_STRING;
  1392. addr -= YSI_MAX_STRING * 4;
  1393. //printf("copying string");
  1394. #emit LOAD.S.pri addr
  1395. #emit SCTRL 4
  1396. // Copy the data.
  1397. #emit PUSH.C 130
  1398. #emit PUSH.C 520
  1399. #emit PUSH.C 0
  1400. #emit LREF.S.pri tmp
  1401. #emit PUSH.pri
  1402. #emit PUSH.S addr
  1403. #emit PUSH.C 20
  1404. #emit SYSREQ.C memcpy
  1405. #emit STACK 24
  1406. //printf("finished");
  1407. }
  1408. else
  1409. {
  1410. num += 1;
  1411. addr -= 1 * 4;
  1412. #emit LREF.S.pri tmp
  1413. #emit LOAD.I
  1414. #emit PUSH.pri
  1415. }
  1416. mask >>>= 1;
  1417. tmp += 4;
  1418. }*/
  1419. #emit LCTRL 5
  1420. #emit STOR.S.pri tmp
  1421. //num *= 4;
  1422. addr += num * 4;
  1423. // "addr" now contains the params stack address, "stack" contains the
  1424. // starting stack address. This code technically pushes an incorrect
  1425. // destination size (it's 4x too big), but as the bytes to copy is
  1426. // smaller this is not important.
  1427. // Set the frame pointer.
  1428. size = _:result[E_CALLBACK_DATA_FLAGS];
  1429. #emit LOAD.S.pri size
  1430. #emit SHR.C.pri 8
  1431. #emit SHL.C.pri 2 // NOT SHR 6
  1432. #emit LOAD.S.alt addr
  1433. #emit ADD
  1434. #emit STOR.S.pri tmp
  1435. // Copy the data.
  1436. size = ((size & 0xFF) + (size >>> 8) + 3) * 4;
  1437. num = _:result[E_CALLBACK_DATA_ALLOC];
  1438. #emit LOAD.S.pri size
  1439. #emit PUSH.pri
  1440. #emit PUSH.pri
  1441. #emit PUSH.C 0
  1442. #emit CONST.alt YSI_gMallocMemory
  1443. #emit LOAD.S.pri num
  1444. #emit IDXADDR
  1445. #emit PUSH.pri
  1446. #emit PUSH.S addr
  1447. #emit PUSH.C 20
  1448. #emit SYSREQ.C memcpy
  1449. #emit STACK 24
  1450. // Store the return frame.
  1451. #emit LOAD.S.alt tmp
  1452. #emit LCTRL 5
  1453. #emit STOR.I
  1454. #emit MOVE.pri
  1455. #emit ADD.C 4
  1456. #emit MOVE.alt
  1457. // Get the return address and call the function.
  1458. #emit LCTRL 6
  1459. #emit ADD.C 48 // 8
  1460. #emit STOR.I // 12
  1461. #emit LOAD.alt YSI_g_sInInline // 20
  1462. #emit LOAD.S.pri tmp // 28
  1463. #emit SCTRL 5 // 36
  1464. #emit MOVE.pri // 40
  1465. #emit SCTRL 6 // 48
  1466. // Restore the stack.
  1467. //printf("one");
  1468. #emit LOAD.S.pri stack
  1469. #emit SCTRL 4
  1470. //printf("two");
  1471. //YSI_g_sInInline = ininline;
  1472. }
  1473. }