y_inline.inc 40 KB

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