y_inline.inc 34 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202
  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(INLINE_LOOP_PATTERNS,%0__,%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(INLINE_LOOP_PATTERNS,__anonVar,":...:"#);)
  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. static
  312. // Default settings.
  313. sSearch1[] =
  314. {
  315. AMX_PUSH_C, INLINE_LOOP_PATTERN_3,
  316. AMX_PUSH_C, INLINE_LOOP_PATTERN_2,
  317. AMX_PUSH_C, INLINE_LOOP_PATTERN_1,
  318. AMX_PUSH_C, INLINE_LOOP_PATTERN_0,
  319. AMX_PUSH_C, 0x18,
  320. AMX_CALL
  321. },
  322. // Debug settings.
  323. sSearch2[] =
  324. {
  325. AMX_CONST_PRI, INLINE_LOOP_PATTERN_3,
  326. AMX_PUSH_PRI,
  327. AMX_CONST_PRI, INLINE_LOOP_PATTERN_2,
  328. AMX_PUSH_PRI,
  329. AMX_CONST_PRI, INLINE_LOOP_PATTERN_1,
  330. AMX_PUSH_PRI,
  331. AMX_CONST_PRI, INLINE_LOOP_PATTERN_0,
  332. AMX_PUSH_PRI,
  333. AMX_PUSH_C, 0x18,
  334. AMX_CALL
  335. };
  336. // Different optimisation levels produce different sensibilities of code.
  337. if (Inline_DoSearch(sSearch1, 3) == -1)
  338. {
  339. // Pass the number of extra instructions before this code block.
  340. Inline_DoSearch(sSearch2, 5);
  341. }
  342. /*new
  343. p0 = Inline_DoSearch(sSearch1),
  344. // I could actually detect compilation flags in this way!
  345. p1 = Inline_DoSearch(sSearch2);
  346. if (p0 == -1 && p1 != -1)
  347. {
  348. // Compiled with "-d3". That's interesting but ultimately pointless.
  349. // And I can't detect this if they have no inline functions.
  350. }*/
  351. }
  352. //pp(d, str[])
  353. //{
  354. // #emit LOAD.S.pri d
  355. // #emit STOR.S.pri str
  356. // printf("data = %08x, %x,%x,%x,%x,%x,%x", d, str[0], str[1], str[2], str[3], str[4], str[5]);
  357. //}
  358. static stock Inline_DoSearch(sSearch[], neg, size = sizeof (sSearch))
  359. {
  360. new
  361. //str[32],
  362. addr,
  363. data,
  364. func;
  365. static
  366. last = -1;
  367. //printf("FIND FUNC: %s", sSearch);
  368. while (AMX_TraceCode(sSearch, addr, func, size))
  369. {
  370. // Get the function return address (make sure "pri" is always non-zero).
  371. func = addr + ((size + 1) * 4);
  372. //printf("stored function at %x", func);
  373. // Get the address of the last parameter.
  374. addr += (AMX_HEADER_COD - (neg * 4));
  375. //printf("FOUND FUNC: %d", addr);
  376. // Get the value of the last parameter.
  377. #emit LREF.S.pri addr
  378. #emit STOR.S.pri data
  379. // PERFECT! This assembly code worked FIRST TIME to correctly display
  380. // both the address and contents of the loaded string! Amazingly it
  381. // worked for anonymous functions too...
  382. //#emit PUSH.S data
  383. //#emit POP.pri
  384. // Anyway, now we need to see if this is a named or anonymous function
  385. // and plan accordingly. We don't need all the complex code of the
  386. // previous inline version. If we get a function call which takes an
  387. // anonymous function, just assume it is the next one found in the list
  388. // of stored inline function addresses. This has the HUGE added
  389. // advantage of allowing small bits of extra code to appear between the
  390. // function call and the inline function - i.e. we can allow return
  391. // values and allsorts now (including having functions taking anonymous
  392. // functions themselves being used as parameters).
  393. //new
  394. // pos = strfind(
  395. static const
  396. scSearch[] = ":";
  397. new
  398. pos = 0;
  399. #emit PUSH.C 0
  400. #emit PUSH.C 0
  401. #emit PUSH.C scSearch
  402. #emit PUSH.S data
  403. #emit PUSH.C 16
  404. #emit SYSREQ.C strfind
  405. #emit STOR.S.pri pos
  406. #emit STACK 20
  407. //printf("pos = %d, %d", pos, last);
  408. if (pos != -1)
  409. {
  410. if (last == -1)
  411. {
  412. YSI_g_sFirstFunc = data;
  413. }
  414. else
  415. {
  416. #emit LOAD.S.pri data
  417. #emit SREF.pri last
  418. }
  419. // Equivalent to: "data[pos + 1] = -1;" (1 cell = 4 bytes).
  420. data += pos * 4 + 4;
  421. #emit CONST.pri 0xFFFFFFFF
  422. #emit SREF.S.pri data
  423. // Equivalent to: "data[pos + 2] = func;"
  424. last = data;
  425. data += 4;
  426. //printf("pos = %d, %d", data, func);
  427. #emit LOAD.S.pri func
  428. #emit SREF.S.pri data
  429. // Now find and compress the format specifier (backwards).
  430. // Now compress the format in to a single cell (up to 32 parameters).
  431. #emit LOAD.S.pri data
  432. #emit ADD.C 8//4
  433. #emit PUSH.pri
  434. #emit PUSH.C 4
  435. // Using "CALL Inline_DoFormat" doesn't work, so do the next best thing.
  436. #emit LCTRL 6
  437. #emit ADD.C 28
  438. #emit PUSH.pri
  439. #emit CONST.pri Inline_DoFormat
  440. #emit SCTRL 6
  441. //pp(data - 8, str);
  442. }
  443. // Move on to find the next value. 24 is larger than both 12 and 20,
  444. // but is still a little hard-coded to the known code types.
  445. addr -= (AMX_HEADER_COD - 24);
  446. }
  447. return last;
  448. }
  449. stock Inline_Loop(p0, p1, p2, p3, &__yil, volatile const format[])
  450. {
  451. #pragma unused p0, p1, p2, p3
  452. //#emit LOAD.S.pri 4
  453. //#emit STOR.S.pri p0
  454. //printf("ret: %d %d", p0, YSI_g_sInInline);
  455. if (__yil)
  456. {
  457. /*#emit LOAD.S.alt 0
  458. #emit MOVE.pri
  459. #emit ADD.C 4
  460. #emit LOAD.I
  461. #emit XCHG
  462. #emit LOAD.I
  463. #emit STOR.S.pri p0
  464. #emit MOVE.pri
  465. #emit STOR.S.pri p1
  466. printf("%d %d", p0, p1);*/
  467. // Somehow I need to check
  468. #emit LOAD.S.alt 0
  469. #emit MOVE.pri
  470. #emit ADD.C 4
  471. #emit LOAD.I
  472. #emit XCHG
  473. #emit LOAD.I
  474. #emit SCTRL 5
  475. #emit MOVE.pri
  476. #emit SCTRL 6
  477. }
  478. __yil = 1;
  479. static const
  480. scSearch[] = ":";
  481. // This function needs to be modified to store the stack size at this point
  482. // and write it to the relevant slot (easy since the relevant slot is
  483. // passed). I know "volatile const" makes no sense, but "const" is for the
  484. // compiler, "volatile" is to show that really it does change.
  485. #emit LOAD.S.pri 0
  486. #emit ADD.C 8
  487. #emit LOAD.I
  488. #emit PUSH.pri
  489. // Get the local variable sizes. Need to allocate the data somewhere. First
  490. #emit LCTRL 5
  491. #emit LOAD.S.alt 0
  492. // Subtract the parameters passed to this function.
  493. #emit ADD.C 36 // 6 * 4 + 12
  494. #emit SUB.alt
  495. #emit PUSH.pri
  496. // Do strfind.
  497. #emit PUSH.C 0
  498. #emit PUSH.C 0
  499. #emit PUSH.C scSearch
  500. #emit PUSH.S format
  501. #emit PUSH.C 16
  502. #emit SYSREQ.C strfind
  503. #emit STACK 20
  504. // Save the data.
  505. #emit CONST.alt 4
  506. #emit SMUL
  507. #emit ADD.C 12
  508. #emit LOAD.S.alt format
  509. #emit ADD
  510. #emit STOR.S.pri format
  511. #emit POP.alt
  512. #emit SHL.C.alt 6
  513. #emit POP.pri
  514. #emit SHR.C.pri 2
  515. #emit ADD
  516. #emit SREF.S.pri format
  517. return 0;
  518. }
  519. stock Callback_Get(callback:name, result[E_CALLBACK_DATA], expect = -1)
  520. {
  521. new
  522. func,
  523. num,
  524. pos;
  525. P:2("Callback_Get called: %s %04x%04x", _:name, expect >>> 16, expect & 0xFFFF);
  526. if (isnull(_:name))
  527. {
  528. // Anonymous inline. Need to find the next available inline function based
  529. // on the return address of the calling function.
  530. // Get the return address.
  531. #emit LOAD.S.pri 0
  532. #emit ADD.C 4
  533. #emit LOAD.I
  534. // Call the function.
  535. #emit PUSH.pri
  536. //#emit PUSH.S name
  537. #emit PUSH YSI_g_sFirstFunc
  538. #emit PUSH.C 8
  539. #emit LCTRL 6
  540. #emit ADD.C 28
  541. #emit PUSH.pri
  542. #emit CONST.pri Inline_FindAnonymous
  543. #emit SCTRL 6
  544. #emit STOR.S.pri func
  545. if (func == -1)
  546. {
  547. return 0;
  548. }
  549. // Save the data.
  550. func += 2 * 4;
  551. #emit LREF.S.pri func
  552. #emit STOR.S.pri pos
  553. result[E_CALLBACK_DATA_POINTER] = pos;
  554. // Save the function parameters.
  555. func += 4;
  556. #emit LREF.S.pri func
  557. #emit STOR.S.pri pos
  558. result[E_CALLBACK_DATA_FLAGS] = e_CALLBACK_FLAGS:pos;
  559. func += 4;
  560. #emit LREF.S.pri func
  561. #emit STOR.S.pri pos
  562. result[E_CALLBACK_DATA_FORMAT] = pos;
  563. //printf("%x %x", expect, pos);
  564. if (expect != -1 && pos != expect)
  565. {
  566. P:E("Format specifier didn't match on anonymous function");
  567. }
  568. new
  569. mask = 0x80000000;
  570. // Skip leading 1s.
  571. while (pos & mask)
  572. {
  573. mask >>>= 1;
  574. }
  575. // Skip delimiting 0.
  576. mask >>>= 1;
  577. while (mask)
  578. {
  579. if (pos & mask)
  580. {
  581. num += YSI_MAX_STRING;
  582. }
  583. else
  584. {
  585. ++num;
  586. }
  587. mask >>>= 1;
  588. }
  589. }
  590. else
  591. {
  592. pos = strfind(name, ":");
  593. 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);
  594. if (pos == -1)
  595. {
  596. if (AMX_GetPublicPointer(0, pos, name))
  597. {
  598. // Public function, use standard callback techniques (well, psudo-
  599. // standard, just store the address and use SCTRL manipulation).
  600. result[E_CALLBACK_DATA_POINTER] = pos;
  601. result[E_CALLBACK_DATA_FLAGS] = e_CALLBACK_FLAGS_PUBLIC;
  602. result[E_CALLBACK_DATA_FORMAT] = expect;
  603. return 1;
  604. }
  605. else
  606. {
  607. P:5("Callback_Get: Not got");
  608. // Get the caller frame.
  609. #emit LOAD.S.pri 0
  610. // Get the caller return.
  611. #emit ADD.C 4
  612. #emit LOAD.I
  613. // Now find the closest item with the correct name. Hopefully 99% of
  614. // the time there will only be one function with this name anywhere
  615. // NEAR the return address, so we can use that one. Otherwise we will
  616. // just have to hope that the closest is correct (maybe add a check to
  617. // see if it's too close, and if so alert the user).
  618. #emit PUSH.pri
  619. #emit PUSH.S name
  620. #emit PUSH YSI_g_sFirstFunc
  621. #emit PUSH.C 12
  622. #emit LCTRL 6
  623. #emit ADD.C 28
  624. #emit PUSH.pri
  625. #emit CONST.pri Inline_FindFunction
  626. #emit SCTRL 6
  627. #emit STOR.S.pri func
  628. // So now "func" is the address of the handle to the nearest data we can
  629. // extract all the relevant data.
  630. if (func == -1)
  631. {
  632. P:5("Callback_Get: inline/public not found");
  633. return 0;
  634. }
  635. P:5("Callback_Get: inline/public found: %08x", func);
  636. // Save the function pointer.
  637. func += strlen(name) * 4 + 2 * 4;
  638. P:5("Callback_Get: inline/public found: %08x", func);
  639. //#emit LREF.S.pri func
  640. //pos = 444;
  641. #emit LOAD.S.pri func
  642. #emit LOAD.I
  643. #emit STOR.S.pri pos
  644. //printf("%d", pos);
  645. result[E_CALLBACK_DATA_POINTER] = pos;
  646. // Save the function parameters.
  647. func += 4;
  648. #emit LREF.S.pri func
  649. #emit STOR.S.pri pos
  650. //printf("%d", pos);
  651. result[E_CALLBACK_DATA_FLAGS] = e_CALLBACK_FLAGS:pos;
  652. // Save the function format.
  653. func += 4;
  654. //--pos;
  655. #emit LREF.S.pri func
  656. #emit STOR.S.pri pos
  657. //printf("%d", pos);
  658. result[E_CALLBACK_DATA_FORMAT] = pos;
  659. if (expect != -1 && pos != expect)
  660. {
  661. P:E("Format specifier didn't match on inline function %s: %04x%04x != %04x%04x", name, pos >>> 16, pos & 0xFFFF, expect >>> 16, expect & 0xFFFF);
  662. }
  663. new
  664. mask = 0x80000000;
  665. // Skip leading 1s.
  666. while (pos & mask)
  667. {
  668. mask >>>= 1;
  669. }
  670. // Skip delimiting 0.
  671. mask >>>= 1;
  672. while (mask)
  673. {
  674. if (pos & mask)
  675. {
  676. num += YSI_MAX_STRING;
  677. }
  678. else
  679. {
  680. ++num;
  681. }
  682. mask >>>= 1;
  683. }
  684. }
  685. }
  686. else
  687. {
  688. // Named and qualified inline function. Should also include the correct
  689. // addresses. By FAR the fastest method as we already have all the data.
  690. result[E_CALLBACK_DATA_POINTER] = name[pos + 2];
  691. result[E_CALLBACK_DATA_FLAGS] = e_CALLBACK_FLAGS:name[pos + 3];
  692. new
  693. form = name[pos + 4];
  694. result[E_CALLBACK_DATA_FORMAT] = form;
  695. if (expect != -1 && form != expect)
  696. {
  697. P:E("Format specifier didn't match on inline function %s", name);
  698. }
  699. // Get the size of inline function parameters:
  700. new
  701. mask = 0x80000000;
  702. // Skip leading 1s.
  703. while (form & mask)
  704. {
  705. mask >>>= 1;
  706. }
  707. // Skip delimiting 0.
  708. mask >>>= 1;
  709. while (mask)
  710. {
  711. if (form & mask)
  712. {
  713. num += YSI_MAX_STRING;
  714. }
  715. else
  716. {
  717. ++num;
  718. }
  719. mask >>>= 1;
  720. }
  721. }
  722. }
  723. // Now we need to somehow store all this data somewhere (including, for
  724. // speed, the extra data involved in calling a function). Here "pos" is the
  725. // number of bytes pushed to the owning function.
  726. result[E_CALLBACK_DATA_FLAGS] -= e_CALLBACK_FLAGS:(num << 8);
  727. pos = _:result[E_CALLBACK_DATA_FLAGS];
  728. // Get the size of the closure.
  729. func = (pos & 0xFF);
  730. pos = (pos >>> 8); // - num;
  731. func = func + pos + 3;
  732. new
  733. Alloc:alloc = malloc(func);
  734. if (alloc == NO_ALLOC)
  735. {
  736. return 0;
  737. }
  738. result[E_CALLBACK_DATA_ALLOC] = alloc;
  739. // Now we need to copy the data from the previous-but-one frame to this
  740. // allocated location. Copy the whole lot, including passed parameters.
  741. #emit LOAD.S.pri pos
  742. #emit SMUL.C 4
  743. #emit MOVE.alt
  744. #emit LOAD.S.pri 0
  745. #emit LOAD.I
  746. #emit SUB
  747. #emit STOR.S.pri name
  748. memcpy(YSI_gMallocMemory[_:alloc], name, 0, func * 4, func);
  749. return 1;
  750. }
  751. stock Callback_Release(const input[E_CALLBACK_DATA])
  752. {
  753. if (!(input[E_CALLBACK_DATA_FLAGS] & e_CALLBACK_FLAGS_PUBLIC))
  754. {
  755. // Publics don't have any stored data.
  756. free(input[E_CALLBACK_DATA_ALLOC]);
  757. }
  758. }
  759. stock Callback_Call(const result[E_CALLBACK_DATA], GLOBAL_TAG_TYPES:...)
  760. {
  761. // Call the function with the given data. We need some serious stack
  762. // manipulation skills in here to make it all work.
  763. if (result[E_CALLBACK_DATA_FLAGS] & e_CALLBACK_FLAGS_PUBLIC)
  764. {
  765. // I think I've got an even better way. NOPE! None of this code will
  766. // work because all the parameters are passed by reference, not by
  767. // value! This is VERY VERY bad! D'oh! Good thing I kept a copy of
  768. // the old code! Shame, this would have been very elegant. Sweet, it
  769. // seemed to work as well! Maybe I could just do some similar in-line
  770. // variable modifications.
  771. new
  772. par,
  773. pointer = result[E_CALLBACK_DATA_POINTER],
  774. mask = result[E_CALLBACK_DATA_FORMAT];
  775. // Destroy one parameter.
  776. //#emit PUSH.S 8
  777. #emit LOAD.S.alt 8
  778. #emit PUSH.alt
  779. //#emit ADD.C 0xFFFFFFFC
  780. //#emit PUSH.pri
  781. // Move the return address.
  782. #emit LOAD.S.pri 4
  783. #emit STOR.S.pri 8
  784. // Move the frame.
  785. #emit LOAD.S.pri 0
  786. #emit STOR.S.pri 4
  787. // Fix the parameters.
  788. #emit LCTRL 5
  789. #emit ADD
  790. #emit ADD.C 12
  791. #emit STOR.S.pri par
  792. // Get the jump address.
  793. //while (mask != ~1)
  794. // If no format has been provided, just guess and pass every parameter
  795. // by reference (as they are passed to here).
  796. while (mask != -1)
  797. {
  798. par -= 4;
  799. if (!(mask & 1))
  800. {
  801. #emit LREF.S.pri par
  802. #emit LOAD.I
  803. #emit SREF.S.pri par
  804. }
  805. mask >>= 1;
  806. }
  807. //#emit LOAD.S.pri 8
  808. #emit POP.pri
  809. #emit ADD.C 0xFFFFFFFC
  810. #emit STOR.S.pri 12
  811. //#emit ADD.C 4
  812. //#emit ADD.C 4
  813. //#emit MOVE.alt
  814. #emit LOAD.S.alt pointer
  815. // Mangle the stack (no variables from here).
  816. #emit LCTRL 5
  817. #emit ADD.C 4
  818. #emit SCTRL 4
  819. #emit SCTRL 5
  820. // Jump to new code (after "PROC").
  821. #emit MOVE.pri
  822. #emit ADD.C 4
  823. #emit SCTRL 6
  824. // Will never be called.
  825. //#emit RETN
  826. }
  827. else
  828. {
  829. new
  830. size = _:result[E_CALLBACK_DATA_FLAGS],
  831. num = 0,
  832. stack,
  833. mask = 0x80000000,
  834. addr,
  835. tmp;
  836. //YSI_g_sInInline = result[E_CALLBACK_DATA_POINTER];
  837. // ininline = YSI_g_sInInline;
  838. YSI_g_sInInline = result[E_CALLBACK_DATA_POINTER];
  839. size = ((size & 0xFF) + (size >>> 8) + 3) * 4;
  840. #emit LCTRL 4
  841. #emit STOR.S.pri stack
  842. #emit LOAD.S.alt size
  843. #emit SUB
  844. #emit STOR.S.pri addr
  845. // Add more data for additional parameters.
  846. #emit SCTRL 4
  847. //#emit LCTRL 4
  848. size = result[E_CALLBACK_DATA_FORMAT];
  849. #emit LCTRL 5
  850. #emit ADD.C 16
  851. #emit STOR.S.pri tmp
  852. // OK, now the fun bit!
  853. while (size & mask)
  854. {
  855. mask >>>= 1;
  856. }
  857. mask >>>= 1;
  858. while (mask)
  859. {
  860. if (size & mask)
  861. {
  862. num += YSI_MAX_STRING;
  863. addr -= YSI_MAX_STRING * 4;
  864. //printf("copying string");
  865. #emit LOAD.S.pri addr
  866. #emit SCTRL 4
  867. // Copy the data.
  868. #emit PUSH.C 130
  869. #emit PUSH.C 520
  870. #emit PUSH.C 0
  871. #emit LREF.S.pri tmp
  872. #emit PUSH.pri
  873. #emit PUSH.S addr
  874. #emit PUSH.C 20
  875. #emit SYSREQ.C memcpy
  876. #emit STACK 24
  877. //printf("finished");
  878. }
  879. else
  880. {
  881. num += 1;
  882. addr -= 1 * 4;
  883. #emit LREF.S.pri tmp
  884. #emit LOAD.I
  885. #emit PUSH.pri
  886. }
  887. mask >>>= 1;
  888. tmp += 4;
  889. }
  890. #emit LCTRL 5
  891. #emit STOR.S.pri tmp
  892. num *= 4;
  893. addr += num;
  894. // "addr" now contains the params stack address, "stack" contains the
  895. // starting stack address. This code technically pushes an incorrect
  896. // destination size (it's 4x too big), but as the bytes to copy is
  897. // smaller this is not important.
  898. // Set the frame pointer.
  899. size = _:result[E_CALLBACK_DATA_FLAGS];
  900. #emit LOAD.S.pri size
  901. #emit SHR.C.pri 8
  902. #emit SHL.C.pri 2 // NOT SHR 6
  903. #emit LOAD.S.alt addr
  904. #emit ADD
  905. #emit STOR.S.pri tmp
  906. // Copy the data.
  907. size = ((size & 0xFF) + (size >>> 8) + 3) * 4;
  908. num = _:result[E_CALLBACK_DATA_ALLOC];
  909. #emit LOAD.S.pri size
  910. #emit PUSH.pri
  911. #emit PUSH.pri
  912. #emit PUSH.C 0
  913. #emit CONST.alt YSI_gMallocMemory
  914. #emit LOAD.S.pri num
  915. #emit IDXADDR
  916. #emit PUSH.pri
  917. #emit PUSH.S addr
  918. #emit PUSH.C 20
  919. #emit SYSREQ.C memcpy
  920. #emit STACK 24
  921. // Store the return frame.
  922. #emit LOAD.S.alt tmp
  923. #emit LCTRL 5
  924. #emit STOR.I
  925. #emit MOVE.pri
  926. #emit ADD.C 4
  927. #emit MOVE.alt
  928. // Get the return address and call the function.
  929. #emit LCTRL 6
  930. #emit ADD.C 48 // 8
  931. #emit STOR.I // 12
  932. #emit LOAD.alt YSI_g_sInInline // 20
  933. #emit LOAD.S.pri tmp // 28
  934. #emit SCTRL 5 // 36
  935. #emit MOVE.pri // 40
  936. #emit SCTRL 6 // 48
  937. // Restore the stack.
  938. //printf("one");
  939. #emit LOAD.S.pri stack
  940. #emit SCTRL 4
  941. //printf("two");
  942. //YSI_g_sInInline = ininline;
  943. }
  944. }
  945. // HOPEFULLY will derive the compressed format specifier for a function, with
  946. // anything not "s" zero.
  947. //#define _S<%0> (-1&_:@Rx:@Ry:@Rw:@Rv:@Ru:(0,%0,0))
  948. #define _F<%0> (-1&_:~@Rx:@Ry:@Rv:@Ru:@Rw:(1,%0))
  949. #define @Rx:@Ry:@Rv:@Ru:@Rw:(%9,s%0) @Rx:@Ry:@Rv:@Ru:@Rw:((%9)<<1,%0)
  950. #define @Ry:@Rv:@Ru:@Rw:(%9,i%0) @Rx:@Ry:@Rv:@Ru:@Rw:((%9)<<1|1,%0)
  951. #define @Rv:@Ru:@Rw:(%9,d%0) @Rx:@Ry:@Rv:@Ru:@Rw:((%9)<<1|1,%0)
  952. #define @Ru:@Rw:(%9,f%0) @Rx:@Ry:@Rv:@Ru:@Rw:((%9)<<1|1,%0)
  953. #define @Rw:(%9,) (%9)
  954. /*#define @Ru:(%0i,%1) ~(1<<%1)&@Rx:@Ry:@Rw:@Rv:@Ru:(%0,%1+1)
  955. #define @Rv:@Ru:(%0d,%1) ~(1<<%1)&@Rx:@Ry:@Rw:@Rv:@Ru:(%0,%1+1)
  956. #define @Rw:@Rv:@Ru:(%0f,%1) ~(1<<%1)&@Rx:@Ry:@Rw:@Rv:@Ru:(%0,%1+1)
  957. #define @Rx:@Ry:@Rw:@Rv:@Ru:(%0s,%1) @Rx:@Ry:@Rw:@Rv:@Ru:(%0,%1+1)
  958. #define @Ry:@Rw:@Rv:@Ru:(,%1) ~(1<<%1)*/
  959. // This is very similar to Callback_Call, but takes an array of parameters
  960. // instead of normal parameters. This is designed to help support some
  961. // experimental OO code I was working on...
  962. stock Callback_Array(const result[E_CALLBACK_DATA], const params[])
  963. {
  964. #pragma unused params
  965. // Call the function with the given data. We need some serious stack
  966. // manipulation skills in here to make it all work.
  967. if (result[E_CALLBACK_DATA_FLAGS] & e_CALLBACK_FLAGS_PUBLIC)
  968. {
  969. // I think I've got an even better way. NOPE! None of this code will
  970. // work because all the parameters are passed by reference, not by
  971. // value! This is VERY VERY bad! D'oh! Good thing I kept a copy of
  972. // the old code! Shame, this would have been very elegant. Sweet, it
  973. // seemed to work as well! Maybe I could just do some similar in-line
  974. // variable modifications.
  975. new
  976. par,
  977. pointer = result[E_CALLBACK_DATA_POINTER],
  978. mask = result[E_CALLBACK_DATA_FORMAT];
  979. // Destroy one parameter.
  980. //#emit PUSH.S 8
  981. #emit LOAD.S.alt 8
  982. #emit PUSH.alt
  983. //#emit ADD.C 0xFFFFFFFC
  984. //#emit PUSH.pri
  985. // Move the return address.
  986. #emit LOAD.S.pri 4
  987. #emit STOR.S.pri 8
  988. // Move the frame.
  989. #emit LOAD.S.pri 0
  990. #emit STOR.S.pri 4
  991. // Fix the parameters.
  992. #emit LCTRL 5
  993. #emit ADD
  994. #emit ADD.C 12
  995. #emit STOR.S.pri par
  996. // Get the jump address.
  997. //while (mask != ~1)
  998. // If no format has been provided, just guess and pass every parameter
  999. // by reference (as they are passed to here).
  1000. while (mask != -1)
  1001. {
  1002. par -= 4;
  1003. if (!(mask & 1))
  1004. {
  1005. #emit LREF.S.pri par
  1006. #emit LOAD.I
  1007. #emit SREF.S.pri par
  1008. }
  1009. mask >>= 1;
  1010. }
  1011. //#emit LOAD.S.pri 8
  1012. #emit POP.pri
  1013. #emit ADD.C 0xFFFFFFFC
  1014. #emit STOR.S.pri 12
  1015. //#emit ADD.C 4
  1016. //#emit ADD.C 4
  1017. //#emit MOVE.alt
  1018. #emit LOAD.S.alt pointer
  1019. // Mangle the stack (no variables from here).
  1020. #emit LCTRL 5
  1021. #emit ADD.C 4
  1022. #emit SCTRL 4
  1023. #emit SCTRL 5
  1024. // Jump to new code (after "PROC").
  1025. #emit MOVE.pri
  1026. #emit ADD.C 4
  1027. #emit SCTRL 6
  1028. // Will never be called.
  1029. //#emit RETN
  1030. }
  1031. else
  1032. {
  1033. new
  1034. size = _:result[E_CALLBACK_DATA_FLAGS],
  1035. num = 0,
  1036. stack,
  1037. mask = 0x80000000,
  1038. addr,
  1039. tmp;
  1040. //YSI_g_sInInline = result[E_CALLBACK_DATA_POINTER];
  1041. // ininline = YSI_g_sInInline;
  1042. YSI_g_sInInline = result[E_CALLBACK_DATA_POINTER];
  1043. size = ((size & 0xFF) + (size >>> 8) + 3) * 4;
  1044. #emit LCTRL 4
  1045. #emit STOR.S.pri stack
  1046. #emit LOAD.S.alt size
  1047. #emit SUB
  1048. #emit STOR.S.pri addr
  1049. // Add more data for additional parameters.
  1050. #emit SCTRL 4
  1051. //#emit LCTRL 4
  1052. size = result[E_CALLBACK_DATA_FORMAT];
  1053. #emit LCTRL 5
  1054. #emit ADD.C 16
  1055. #emit LOAD.I
  1056. #emit STOR.S.pri tmp
  1057. // OK, now the fun bit!
  1058. while (size & mask)
  1059. {
  1060. mask >>>= 1;
  1061. }
  1062. mask >>>= 1;
  1063. while (mask)
  1064. {
  1065. if (size & mask)
  1066. {
  1067. num += YSI_MAX_STRING;
  1068. addr -= YSI_MAX_STRING * 4;
  1069. //printf("copying string");
  1070. #emit LOAD.S.pri addr
  1071. #emit SCTRL 4
  1072. // Copy the data.
  1073. #emit PUSH.C 130
  1074. #emit PUSH.C 520
  1075. #emit PUSH.C 0
  1076. #emit LREF.S.pri tmp
  1077. #emit PUSH.pri
  1078. #emit PUSH.S addr
  1079. #emit PUSH.C 20
  1080. #emit SYSREQ.C memcpy
  1081. #emit STACK 24
  1082. //printf("finished");
  1083. }
  1084. else
  1085. {
  1086. num += 1;
  1087. addr -= 1 * 4;
  1088. #emit LREF.S.pri tmp
  1089. #emit LOAD.I
  1090. #emit PUSH.pri
  1091. }
  1092. mask >>>= 1;
  1093. tmp += 4;
  1094. }
  1095. #emit LCTRL 5
  1096. #emit STOR.S.pri tmp
  1097. num *= 4;
  1098. addr += num;
  1099. // "addr" now contains the params stack address, "stack" contains the
  1100. // starting stack address. This code technically pushes an incorrect
  1101. // destination size (it's 4x too big), but as the bytes to copy is
  1102. // smaller this is not important.
  1103. // Set the frame pointer.
  1104. size = _:result[E_CALLBACK_DATA_FLAGS];
  1105. #emit LOAD.S.pri size
  1106. #emit SHR.C.pri 8
  1107. #emit SHL.C.pri 2 // NOT SHR 6
  1108. #emit LOAD.S.alt addr
  1109. #emit ADD
  1110. #emit STOR.S.pri tmp
  1111. // Copy the data.
  1112. size = ((size & 0xFF) + (size >>> 8) + 3) * 4;
  1113. num = _:result[E_CALLBACK_DATA_ALLOC];
  1114. #emit LOAD.S.pri size
  1115. #emit PUSH.pri
  1116. #emit PUSH.pri
  1117. #emit PUSH.C 0
  1118. #emit CONST.alt YSI_gMallocMemory
  1119. #emit LOAD.S.pri num
  1120. #emit IDXADDR
  1121. #emit PUSH.pri
  1122. #emit PUSH.S addr
  1123. #emit PUSH.C 20
  1124. #emit SYSREQ.C memcpy
  1125. #emit STACK 24
  1126. // Store the return frame.
  1127. #emit LOAD.S.alt tmp
  1128. #emit LCTRL 5
  1129. #emit STOR.I
  1130. #emit MOVE.pri
  1131. #emit ADD.C 4
  1132. #emit MOVE.alt
  1133. // Get the return address and call the function.
  1134. #emit LCTRL 6
  1135. #emit ADD.C 48 // 8
  1136. #emit STOR.I // 12
  1137. #emit LOAD.alt YSI_g_sInInline // 20
  1138. #emit LOAD.S.pri tmp // 28
  1139. #emit SCTRL 5 // 36
  1140. #emit MOVE.pri // 40
  1141. #emit SCTRL 6 // 48
  1142. // Restore the stack.
  1143. //printf("one");
  1144. #emit LOAD.S.pri stack
  1145. #emit SCTRL 4
  1146. //printf("two");
  1147. //YSI_g_sInInline = ininline;
  1148. }
  1149. }