indirection.inc 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974
  1. #if defined _INC_indirection
  2. #endinput
  3. #endif
  4. #define _INC_indirection
  5. #if !defined ADDRESSOF_INC
  6. #tryinclude "..\amx\addressof"
  7. #endif
  8. #if !defined ADDRESSOF_INC
  9. #tryinclude <amx_assembly\addressof>
  10. #endif
  11. #if !defined ADDRESSOF_INC
  12. #tryinclude "..\amx_assembly\addressof"
  13. #endif
  14. #if !defined ADDRESSOF_INC
  15. #tryinclude "..\..\amx_assembly\addressof"
  16. #endif
  17. #if !defined ADDRESSOF_INC
  18. #tryinclude "addressof"
  19. #endif
  20. #if !defined ADDRESSOF_INC
  21. #tryinclude <addressof>
  22. #endif
  23. #if !defined ADDRESSOF_INC
  24. #define AMX_INCLUDING_FAILED
  25. #endif
  26. #if !defined _ADDR@
  27. #define AMX_INCLUDING_FAILED
  28. #endif
  29. #if !defined ADDRESSOF_JIT_INC
  30. #tryinclude "..\amx\addressof_jit"
  31. #endif
  32. #if !defined ADDRESSOF_JIT_INC
  33. #tryinclude <amx_assembly\addressof_jit>
  34. #endif
  35. #if !defined ADDRESSOF_JIT_INC
  36. #tryinclude "..\amx_assembly\addressof_jit"
  37. #endif
  38. #if !defined ADDRESSOF_JIT_INC
  39. #tryinclude "..\..\amx_assembly\addressof_jit"
  40. #endif
  41. #if !defined ADDRESSOF_JIT_INC
  42. #tryinclude "addressof_jit"
  43. #endif
  44. #if !defined ADDRESSOF_JIT_INC
  45. #tryinclude <addressof_jit>
  46. #endif
  47. #if !defined ADDRESSOF_JIT_INC
  48. #define AMX_INCLUDING_FAILED
  49. #endif
  50. #if !defined AMX_HEADER_INC
  51. #tryinclude "..\amx\amx_header"
  52. #endif
  53. #if !defined AMX_HEADER_INC
  54. #tryinclude <amx_assembly\amx_header>
  55. #endif
  56. #if !defined AMX_HEADER_INC
  57. #tryinclude "..\amx_assembly\amx_header"
  58. #endif
  59. #if !defined AMX_HEADER_INC
  60. #tryinclude "..\..\amx_assembly\amx_header"
  61. #endif
  62. #if !defined AMX_HEADER_INC
  63. #tryinclude "amx_header"
  64. #endif
  65. #if !defined AMX_HEADER_INC
  66. #tryinclude <amx_header>
  67. #endif
  68. #if !defined AMX_HEADER_INC
  69. #define AMX_INCLUDING_FAILED
  70. #endif
  71. #if defined AMX_INCLUDING_FAILED
  72. #error Could not include "https://github.com/Zeex/amx_assembly" - ensure its files are in "include\amx_assembly\"
  73. #elseif !defined AddressofResolve
  74. #error Please update "https://github.com/Zeex/amx_assembly" to the latest version.
  75. #endif
  76. #if defined CUSTOM_TAG_TYPES
  77. #define GLOBAL_TAG_TYPES {_,Language,Bit,Text,Menu,Style,XML,Bintree,Group,Timer,File,Float,Text3D,CUSTOM_TAG_TYPES}
  78. #else
  79. #define GLOBAL_TAG_TYPES {_,Language,Bit,Text,Menu,Style,XML,Bintree,Group,Timer,File,Float,Text3D}
  80. #endif
  81. enum E_INDIRECTION
  82. {
  83. E_INDIRECTION_ALWAYS_NULL, // So we can tell this is not a string.
  84. E_INDIRECTION_HANDER, // Called by `@` to handle this pointer.
  85. E_INDIRECTION_CLAIM, // Called by `Indirect_Claim`.
  86. E_INDIRECTION_RELEASE, // Called by `Indirect_Release`.
  87. E_INDIRECTION_METADATA, // Only used by end-users.
  88. }
  89. stock
  90. INDIRECTION_DATA,
  91. INDIRECTION_TAG;
  92. static stock
  93. gsCodSize; // The size of `COD`.
  94. #if !defined YSI_MAX_STRING
  95. #define YSI_MAX_STRING (144)
  96. #endif
  97. #define string:
  98. #define void:
  99. #if !defined TAGOF
  100. #if ((__Pawn & 0x0F) >= 0x0A) || ((__Pawn & 0xF0) >= 0xA0)
  101. #define TAGOF(%0);
  102. // Defer `tagof` on things with colons slightly to remove anything after
  103. // it. This lets us do `tagof (Float:i)` with no problem, since the `i`
  104. // is removed.
  105. #define TAGOF@[%0] %0:
  106. #define tagof(%0:%1)NO_TAGOF$ tagof(TAGOF@[%0])
  107. #else
  108. #define TAGOF(%0); stock const %0:TAGOF@%0;
  109. #define TAGOF@%0\32; TAGOF@
  110. #define tagof(%0:%1)NO_TAGOF$ (tagof(TAGOF@%0))
  111. #endif
  112. #define TAGOF@F@_@%0\32; TAGOF@F@_@
  113. #define SPECIFIER(%0) TAGOF(F@_@%0)
  114. #define NO_TAGOF$
  115. TAGOF(Float);
  116. TAGOF(File);
  117. #endif
  118. // Technically the function tags are not always `F@_@`. The third character can
  119. // be anything, and is reserved for representing the return type. However, it
  120. // is currently not used. DO NOT consume spaces after `F@_@` since this will
  121. // break functions with no parameters since their tag is just `F@_@:` (or
  122. // `F@_@_`). Function tags could be weak, which means if you pass a pointer to
  123. // a function that wants a different type, or pass an untyped pointer to a
  124. // function that wants any type, you will get a mismatch warning. However, you
  125. // can pass a typed pointer to a function that doesn't expect any type for
  126. // backwards-compatability reasons. I decided against this though - make them
  127. // strong and give warnings on all old code!
  128. #define Func:%0<%1> F@_@%1:%0
  129. // Examples of predeclarations of specifier types. These fix a bug in the old
  130. // compiler where you can't (always) do `tagof (Float:)`. This is relevant here
  131. // since the specifiers are passed as `F@_@i:Func`, so we need `tagof (F@_@i:)`
  132. // to get at the specifier. However, since that doesn't work, we instead need
  133. // `tagof (TAGOF@F@_@i)` with `stock const F@_@i:TAGOF@F@_@i`. I.e. we need a
  134. // variable using the tag to get the tag from, instead of getting it directly.
  135. SPECIFIER(i);
  136. SPECIFIER(s);
  137. // This is for getting excess parameters on non-strings.
  138. #define _:%0,) _:%0)
  139. // I did consider an alternate method of making `@` do this:
  140. //
  141. // #define @.%0(%1) Indirect_Data(%0),Indirect_Call(%1)
  142. //
  143. // But that would fail when an `@` call contained another `@` call:
  144. //
  145. // @.Func1(@.Func2(42, 43));
  146. //
  147. // It would save the stack manipulation though (not convinced it would be less
  148. // code though with the generation of multiple function calls).
  149. #define @%0(%1) (Indirect_Call(_:INDIRECT_DOT:%0,_:(tagof(%0)NO_TAGOF$),%1))
  150. #define Indirect_Call(_:INDIRECT_DOT:%9&%0,_:(tagof(%9)NO_TAGOF$),%2) Indirect_Call(_:TAGOF_ADDRESSOF:addressof(%0),_:0,%2)
  151. #define INDIRECT_DOT:.%0,_:(tagof(.%0)NO_TAGOF$) %0,_:(tagof(%0)NO_TAGOF$)
  152. #define TAGOF_ADDRESSOF:addressof(%0<%2>),_:0, addressof(%0<%2>),_:tagof(F@_@%2:)NO_TAGOF$,
  153. // Can now do:
  154. //
  155. // @.var(params)
  156. // @&func<iis>(params)
  157. // @.&func(params)
  158. //
  159. #if !defined __PawnBuild
  160. forward __Indirect_FuncInc__();
  161. public __Indirect_FuncInc__()
  162. {
  163. memcpy("", "", 0, 0, 0);
  164. funcidx("");
  165. }
  166. #endif
  167. stock Indirect_Call(func, tag, GLOBAL_TAG_TYPES:...)
  168. {
  169. static
  170. addr;
  171. #pragma unused tag
  172. if (!func)
  173. {
  174. return 0;
  175. }
  176. {}
  177. // The COD and DAT segments are different, so `func` pointing in to DAT
  178. // relative to COD will not be a valid pointer, and THAT you can detect!
  179. //
  180. // Get the previous frame. This undoes the effects of our `PROC` so the
  181. // called function must have a proper `PROC`.
  182. #emit ADDR.pri 20
  183. #emit STOR.pri addr
  184. #emit POP.pri
  185. #emit SCTRL 5
  186. // Get the return address.
  187. #emit POP.alt
  188. // Get the parameter count.
  189. #emit POP.pri
  190. // Reduce the parameter count.
  191. #emit ADD.C 0xFFFFFFF8
  192. // Store the return address.
  193. #emit SWAP.alt
  194. #emit STOR.alt INDIRECTION_DATA
  195. #emit POP.alt
  196. // Store the new parameter count.
  197. #emit SWAP.pri
  198. #emit STOR.pri INDIRECTION_TAG
  199. #emit PUSH.alt
  200. // Check the pointer type. If it is in the `COD` area, jump straight to it
  201. // with the tag for parameter types (if it isn't 0). Otherwise, use the
  202. // `func` from `DAT` as a pointer to a handler.
  203. if (INDIRECTION_DATA >= gsCodSize)
  204. {
  205. // Get the data at `func - COD`.
  206. #emit LOAD.pri INDIRECTION_DATA
  207. #emit LOAD.alt gsCodSize
  208. #emit SUB
  209. #emit MOVE.alt
  210. #emit LOAD.I
  211. #emit STOR.pri INDIRECTION_DATA
  212. if (!INDIRECTION_DATA)
  213. {
  214. // Get the function at `func - COD + 4`.
  215. #emit CONST.pri 4
  216. #emit ADD
  217. #emit LOAD.I
  218. // Call it, passing `func` as a proper pointer, NOT skipping `PROC`.
  219. #emit STOR.alt INDIRECTION_DATA
  220. #emit SCTRL 6
  221. // NEVER RETURNS PAST HERE.
  222. }
  223. {}
  224. // `INDIRECTION_DATA` is now a pointer to a string of a function name.
  225. // Resolve it via index lookup.
  226. #emit PUSH.alt
  227. #emit PUSH.C 4
  228. #emit SYSREQ.C funcidx
  229. #emit STACK 8
  230. #emit STOR.pri INDIRECTION_DATA
  231. if (INDIRECTION_DATA == -1)
  232. {
  233. #emit PROC
  234. #emit RETN
  235. }
  236. {}
  237. // Get the address from the index.
  238. INDIRECTION_DATA = GetPublicAddressFromIndex(INDIRECTION_DATA);
  239. }
  240. if (INDIRECTION_TAG)
  241. {
  242. static
  243. i,
  244. lTag[32];
  245. // Skip the `F@_@` prefix.
  246. GetTagNameFromID(INDIRECTION_TAG, lTag);
  247. if (lTag[0]) for (i = 4; ; )
  248. {
  249. switch (lTag[i++])
  250. {
  251. case 'i', 'd', 't', 'f', 'c':
  252. {
  253. // Resolve non-reference parameters.
  254. #emit LREF.pri addr
  255. #emit LOAD.I
  256. #emit SREF.pri addr
  257. }
  258. case '\0', 'x':
  259. break;
  260. }
  261. addr += 4;
  262. }
  263. }
  264. {}
  265. // No handler, and no tag data. Just jump to it and hope (hope it has a `PROC` too).
  266. #emit LOAD.pri INDIRECTION_DATA
  267. #emit SCTRL 6
  268. return 0;
  269. }
  270. // Not `Indirect_CallString` to make use of the `string:` macro.
  271. stock string:Indirect_Callstring(func, tag, GLOBAL_TAG_TYPES:...)
  272. {
  273. static
  274. addr;
  275. #pragma unused tag
  276. if (!func)
  277. {
  278. // Get the offset to the secret return parameter.
  279. #emit LOAD.S.pri 8
  280. #emit ADDR.alt 12
  281. #emit ADD
  282. #emit LOAD.I
  283. #emit MOVE.alt
  284. #emit ZERO.pri
  285. #emit STOR.I
  286. #emit RETN
  287. new ret[YSI_MAX_STRING];
  288. return ret;
  289. }
  290. {}
  291. #emit ADDR.pri 20
  292. #emit STOR.pri addr
  293. #emit POP.pri
  294. #emit SCTRL 5
  295. // Get the return address.
  296. #emit POP.alt
  297. // Get the parameter count.
  298. #emit POP.pri
  299. // Reduce the parameter count.
  300. #emit ADD.C 0xFFFFFFF8
  301. // Store the return address.
  302. #emit SWAP.alt
  303. #emit STOR.alt INDIRECTION_DATA
  304. #emit POP.alt
  305. // Store the new parameter count.
  306. #emit SWAP.pri
  307. #emit STOR.pri INDIRECTION_TAG
  308. #emit PUSH.alt
  309. // Check the pointer type. If it is in the `COD` area, jump straight to it
  310. // with the tag for parameter types (if it isn't 0). Otherwise, use the
  311. // `func` from `DAT` as a pointer to a handler.
  312. if (INDIRECTION_DATA >= gsCodSize)
  313. {
  314. // Get the data at `func - COD`.
  315. #emit LOAD.pri INDIRECTION_DATA
  316. #emit LOAD.alt gsCodSize
  317. #emit SUB
  318. #emit MOVE.alt
  319. #emit LOAD.I
  320. #emit STOR.pri INDIRECTION_DATA
  321. if (!INDIRECTION_DATA)
  322. {
  323. // Get the function at `func - COD + 4`.
  324. #emit CONST.pri 4
  325. #emit ADD
  326. #emit LOAD.I
  327. // Call it, passing `func` as a proper pointer, NOT skipping `PROC`.
  328. #emit STOR.alt INDIRECTION_DATA
  329. #emit SCTRL 6
  330. // NEVER RETURNS PAST HERE.
  331. }
  332. {}
  333. // `INDIRECTION_DATA` is now a pointer to a string of a function name.
  334. // Resolve it via index lookup.
  335. #emit PUSH.alt
  336. #emit PUSH.C 4
  337. #emit SYSREQ.C funcidx
  338. #emit STACK 8
  339. #emit STOR.pri INDIRECTION_DATA
  340. if (INDIRECTION_DATA == -1)
  341. {
  342. #emit PROC
  343. #emit RETN
  344. }
  345. {}
  346. // Get the address from the index.
  347. INDIRECTION_DATA = GetPublicAddressFromIndex(INDIRECTION_DATA);
  348. }
  349. if (INDIRECTION_TAG)
  350. {
  351. static
  352. i,
  353. lTag[32];
  354. // Skip the `F@_@` prefix.
  355. GetTagNameFromID(INDIRECTION_TAG, lTag);
  356. if (lTag[0]) for (i = 4; ; )
  357. {
  358. switch (lTag[i++])
  359. {
  360. case 'i', 'd', 't', 'f', 'c':
  361. {
  362. // Resolve non-reference parameters.
  363. #emit LREF.pri addr
  364. #emit LOAD.I
  365. #emit SREF.pri addr
  366. }
  367. case '\0', 'x':
  368. break;
  369. }
  370. addr += 4;
  371. }
  372. }
  373. {}
  374. // No handler, and no tag data. Just jump to it and hope.
  375. #emit LOAD.pri INDIRECTION_DATA
  376. #emit SCTRL 6
  377. // Never called. Don't use "static" because it would allocate real memory
  378. // in advance. Instead, this will want to allocate on the stack but never
  379. // get hit to do so.
  380. new ret[YSI_MAX_STRING];
  381. return ret;
  382. }
  383. // Not `Indirect_Callvoid` to make use of the `void:` macro.
  384. stock void:Indirect_Callvoid(func, tag, GLOBAL_TAG_TYPES:...)
  385. {
  386. static
  387. addr;
  388. #pragma unused tag
  389. if (!func)
  390. {
  391. return;
  392. }
  393. {}
  394. #emit ADDR.pri 20
  395. #emit STOR.pri addr
  396. #emit POP.pri
  397. #emit SCTRL 5
  398. // Get the return address.
  399. #emit POP.alt
  400. // Get the parameter count.
  401. #emit POP.pri
  402. // Reduce the parameter count.
  403. #emit ADD.C 0xFFFFFFF8
  404. // Store the return address.
  405. #emit SWAP.alt
  406. #emit STOR.alt INDIRECTION_DATA
  407. #emit POP.alt
  408. // Store the new parameter count.
  409. #emit SWAP.pri
  410. #emit STOR.pri INDIRECTION_TAG
  411. #emit PUSH.alt
  412. // Check the pointer type. If it is in the `COD` area, jump straight to it
  413. // with the tag for parameter types (if it isn't 0). Otherwise, use the
  414. // `func` from `DAT` as a pointer to a handler.
  415. if (INDIRECTION_DATA >= gsCodSize)
  416. {
  417. // Get the data at `func - COD`.
  418. #emit LOAD.pri INDIRECTION_DATA
  419. #emit LOAD.alt gsCodSize
  420. #emit SUB
  421. #emit MOVE.alt
  422. #emit LOAD.I
  423. #emit STOR.pri INDIRECTION_DATA
  424. if (!INDIRECTION_DATA)
  425. {
  426. // Get the function at `func - COD + 4`.
  427. #emit CONST.pri 4
  428. #emit ADD
  429. #emit LOAD.I
  430. // Call it, passing `func` as a proper pointer, NOT skipping `PROC`.
  431. #emit STOR.alt INDIRECTION_DATA
  432. #emit SCTRL 6
  433. // NEVER RETURNS PAST HERE.
  434. }
  435. {}
  436. // `INDIRECTION_DATA` is now a pointer to a string of a function name.
  437. // Resolve it via index lookup.
  438. #emit PUSH.alt
  439. #emit PUSH.C 4
  440. #emit SYSREQ.C funcidx
  441. #emit STACK 8
  442. #emit STOR.pri INDIRECTION_DATA
  443. if (INDIRECTION_DATA == -1)
  444. {
  445. #emit PROC
  446. #emit RETN
  447. }
  448. {}
  449. // Get the address from the index.
  450. INDIRECTION_DATA = GetPublicAddressFromIndex(INDIRECTION_DATA);
  451. }
  452. if (INDIRECTION_TAG)
  453. {
  454. static
  455. i,
  456. lTag[32];
  457. // Skip the `F@_@` prefix.
  458. GetTagNameFromID(INDIRECTION_TAG, lTag);
  459. if (lTag[0]) for (i = 4; ; )
  460. {
  461. switch (lTag[i++])
  462. {
  463. case 'i', 'd', 't', 'f', 'c':
  464. {
  465. // Resolve non-reference parameters.
  466. #emit LREF.pri addr
  467. #emit LOAD.I
  468. #emit SREF.pri addr
  469. }
  470. case '\0', 'x':
  471. break;
  472. }
  473. addr += 4;
  474. }
  475. }
  476. {}
  477. // No handler, and no tag data. Just jump to it and hope.
  478. #emit LOAD.pri INDIRECTION_DATA
  479. #emit SCTRL 6
  480. // Don't return anything.
  481. }
  482. stock Indirect_Array(func, tag, const params[], size = sizeof (params))
  483. {
  484. static
  485. ret,
  486. src;
  487. #pragma unused func, tag, params, size
  488. // Get the previous frame. This undoes the effects of our `PROC` so the
  489. // called function must have a proper `PROC`.
  490. #emit POP.pri
  491. #emit SCTRL 5
  492. // Get the return address.
  493. #emit POP.pri
  494. #emit STOR.pri ret
  495. // Remove the parameter count.
  496. #emit POP.pri
  497. // Get the target tag.
  498. #emit POP.pri
  499. #emit STOR.pri INDIRECTION_DATA
  500. // Get the target function.
  501. #emit POP.pri
  502. #emit STOR.pri INDIRECTION_TAG
  503. // Get the source data.
  504. #emit POP.alt
  505. #emit STOR.alt src
  506. // Get the size.
  507. #emit POP.alt
  508. #emit SHL.C.alt 2
  509. // #emit STOR.alt cnt
  510. // We cannot just adjust the stack size while the other parameters are still
  511. // on it, since the new stack might be smaller than the old one, and dealing
  512. // with that in a simple way is not possible. Well, it is possible - it's
  513. // what we are doing! Copy the parameters.
  514. #emit LCTRL 4
  515. #emit SUB
  516. #emit SCTRL 4
  517. #emit PUSH.alt
  518. #emit PUSH.alt
  519. #emit PUSH.C 0
  520. #emit PUSH src
  521. #emit STOR.pri src
  522. #emit PUSH.pri
  523. #emit PUSH.C 20
  524. #emit SYSREQ.C memcpy
  525. #emit MOVE.pri
  526. #emit STACK 24
  527. #emit PUSH.pri
  528. #emit PUSH ret
  529. //
  530. // Check the pointer type. If it is in the `COD` area, jump straight to it
  531. // with the tag for parameter types (if it isn't 0). Otherwise, use the
  532. // `func` from `DAT` as a pointer to a handler.
  533. if (INDIRECTION_DATA >= gsCodSize)
  534. {
  535. // Get the data at `func - COD`.
  536. #emit LOAD.pri INDIRECTION_DATA
  537. #emit LOAD.alt gsCodSize
  538. #emit SUB
  539. #emit MOVE.alt
  540. #emit LOAD.I
  541. #emit STOR.pri INDIRECTION_DATA
  542. if (!INDIRECTION_DATA)
  543. {
  544. #emit STOR.alt INDIRECTION_DATA
  545. // Get the function at `func - COD + 4`.
  546. #emit LOAD.pri INDIRECTION_DATA
  547. #emit ADD.C 4
  548. #emit LOAD.I
  549. // Call it, passing `func` as a proper pointer, NOT skipping `PROC`.
  550. #emit SCTRL 6
  551. // NEVER RETURNS PAST HERE.
  552. }
  553. {}
  554. // `INDIRECTION_DATA` is now a pointer to a string of a function name.
  555. // Resolve it via index lookup.
  556. #emit PUSH.alt
  557. #emit PUSH.C 4
  558. #emit SYSREQ.C funcidx
  559. #emit STACK 8
  560. #emit STOR.pri INDIRECTION_DATA
  561. if (INDIRECTION_DATA == -1)
  562. {
  563. // Failure.
  564. #emit PROC
  565. #emit RETN
  566. }
  567. {}
  568. // Get the address from the index.
  569. INDIRECTION_DATA = GetPublicAddressFromIndex(INDIRECTION_DATA);
  570. }
  571. if (INDIRECTION_TAG)
  572. {
  573. static
  574. i,
  575. lTag[32];
  576. // Skip the `F@_@` prefix.
  577. GetTagNameFromID(INDIRECTION_TAG, lTag);
  578. if (lTag[0]) for (i = 4; ; )
  579. {
  580. switch (lTag[i++])
  581. {
  582. case 'i', 'd', 't', 'f', 'c':
  583. {
  584. // Resolve non-reference parameters.
  585. #emit LREF.pri src
  586. #emit LOAD.I
  587. #emit SREF.pri src
  588. }
  589. case '\0', 'x':
  590. break;
  591. }
  592. src += 4;
  593. }
  594. }
  595. {}
  596. // No handler, and no tag data. Just jump to it and hope (hope it has a `PROC` too).
  597. #emit LOAD.pri INDIRECTION_DATA
  598. #emit SCTRL 6
  599. return 0;
  600. }
  601. /*-------------------------------------------------------------------------*//**
  602. * <param name="func">The function pointer with attached metadata.</param>
  603. * <remarks>
  604. * Gets extra data from the pointer.
  605. * </remarks>
  606. *//*------------------------------------------------------------------------**/
  607. stock Indirect_GetMeta_(func)
  608. {
  609. if (func >= gsCodSize)
  610. {
  611. // Get the data at `func - COD`.
  612. #emit LOAD.S.pri func
  613. #emit LOAD.alt gsCodSize
  614. #emit SUB
  615. #emit MOVE.alt
  616. #emit LOAD.I
  617. #emit STOR.S.pri func
  618. if (func)
  619. {
  620. // Probably a string.
  621. return 0;
  622. }
  623. {}
  624. // I'm relying on `alt` not changing here...
  625. // Get the function at `func - COD + 16`.
  626. #emit CONST.pri 16
  627. #emit ADD
  628. #emit LOAD.I
  629. #emit RETN
  630. }
  631. return 0;
  632. }
  633. #define Indirect_GetMeta(%0) Indirect_GetMeta_(_:%0)
  634. /*-------------------------------------------------------------------------*//**
  635. * <param name="func">The function pointer to attach metadata to.</param>
  636. * <param name="data">The metadata.</param>
  637. *//*------------------------------------------------------------------------**/
  638. stock Indirect_SetMeta_(func, data)
  639. {
  640. if (func >= gsCodSize)
  641. {
  642. // Get the data at `func - COD`.
  643. #emit LOAD.S.pri func
  644. #emit LOAD.alt gsCodSize
  645. #emit SUB
  646. #emit MOVE.alt
  647. #emit LOAD.I
  648. #emit STOR.S.pri func
  649. if (func)
  650. {
  651. // Probably a string.
  652. return;
  653. }
  654. {}
  655. // I'm relying on `alt` not changing here...
  656. // Get the function at `func - COD + 16`.
  657. #emit CONST.pri 16
  658. #emit ADD
  659. #emit LOAD.S.alt data
  660. #emit XCHG
  661. #emit STOR.I
  662. }
  663. }
  664. #define Indirect_SetMeta(%0) Indirect_SetMeta_(_:%0)
  665. /*-------------------------------------------------------------------------*//**
  666. * <param name="func">The function pointer you want to use later.</param>
  667. * <remarks>
  668. * If a function pointer is used within one function, that is not a problem.
  669. * However, if you want to store the function pointer for use later, you must
  670. * first "claim" it, so that any associated data is not cleared when the
  671. * parent function ends (i.e. the function that called your function). After
  672. * use it must be released, and the number of claims must match the number of
  673. * releases.
  674. * </remarks>
  675. *//*------------------------------------------------------------------------**/
  676. stock Indirect_Claim_(func)
  677. {
  678. if (func >= gsCodSize)
  679. {
  680. // Get the data at `func - COD`.
  681. #emit LOAD.S.pri func
  682. #emit LOAD.alt gsCodSize
  683. #emit SUB
  684. #emit MOVE.alt
  685. #emit LOAD.I
  686. #emit STOR.S.pri func
  687. //#emit JZER.rel 4
  688. //#emit RETN
  689. if (func)
  690. {
  691. // Probably a string.
  692. return;
  693. }
  694. {}
  695. // I'm relying on `alt` not changing here...
  696. #emit STOR.S.alt func
  697. #emit POP.pri
  698. #emit SCTRL 5
  699. // Get the function at `func - COD + 8`.
  700. #emit CONST.pri 8
  701. #emit ADD
  702. #emit LOAD.I
  703. #emit SCTRL 6
  704. }
  705. }
  706. #define Indirect_Claim(%0) Indirect_Claim_(_:%0)
  707. /*-------------------------------------------------------------------------*//**
  708. * <param name="func">The function pointer you had previously stored.</param>
  709. * <remarks>
  710. * If a function pointer is used within one function, that is not a problem.
  711. * However, if you want to store the function pointer for use later, you must
  712. * first "claim" it, so that any associated data is not cleared when the
  713. * parent function ends (i.e. the function that called your function). After
  714. * use it must be released, and the number of claims must match the number of
  715. * releases.
  716. * </remarks>
  717. *//*------------------------------------------------------------------------**/
  718. stock Indirect_Release_(func)
  719. {
  720. if (func >= gsCodSize)
  721. {
  722. // Get the data at `func - COD`.
  723. #emit LOAD.S.pri func
  724. #emit LOAD.alt gsCodSize
  725. #emit SUB
  726. #emit MOVE.alt
  727. #emit LOAD.I
  728. #emit STOR.S.pri func
  729. //#emit JZER.rel 4
  730. //#emit RETN
  731. if (func)
  732. {
  733. // Probably a string.
  734. return;
  735. }
  736. {}
  737. // I'm relying on `alt` not changing here. I wouldn't need to if I
  738. // could use jumps in assembly.
  739. #emit STOR.S.alt func
  740. #emit POP.pri
  741. #emit SCTRL 5
  742. // Get the function at `func - COD + 12`.
  743. #emit CONST.pri 12
  744. #emit ADD
  745. #emit LOAD.I
  746. #emit SCTRL 6
  747. }
  748. }
  749. #define Indirect_Release(%0) Indirect_Release_(_:%0)
  750. /*-------------------------------------------------------------------------*//**
  751. * <param name="id">The ID of the tag to get the specifiers from the name of.
  752. * </param>
  753. * <param name="dest">Where to store the name.</param>
  754. * <remarks>
  755. * Functions are tagged with a special tag containing their specifiers. Get
  756. * the string value of that tag from the AMX header.
  757. * </remarks>
  758. *//*------------------------------------------------------------------------**/
  759. stock Indirect_Tag(id, dest[32])
  760. {
  761. static
  762. lTag[32];
  763. GetTagNameFromID(id, lTag),
  764. dest[0] = '\0';
  765. if (lTag[0])
  766. strcat(dest, lTag[4]);
  767. }
  768. /*-------------------------------------------------------------------------*//**
  769. * <param name="">The array to convert to an offset pointer.</param>
  770. * <remarks>
  771. * Strings and arrays are passed relative to `COD` not `DAT` so they can be
  772. * distinguished from normal function pointers. This function does the offset.
  773. * </remarks>
  774. *//*------------------------------------------------------------------------**/
  775. stock Indirect_Ref_(...)
  776. {
  777. assert(numargs() == 1);
  778. #emit LOAD.S.pri 12
  779. #emit LOAD.alt gsCodSize
  780. #emit ADD
  781. #emit RETN
  782. return 0;
  783. }
  784. #define Indirect_Ref(%0) Indirect_Ref_(_:(%0))
  785. /*-------------------------------------------------------------------------*//**
  786. * <param name="">The array to convert to an offset pointer.</param>
  787. * <remarks>
  788. * Strings and arrays are passed relative to `COD` not `DAT` so they can be
  789. * distinguished from normal function pointers. This function does the offset.
  790. * </remarks>
  791. *//*------------------------------------------------------------------------**/
  792. stock Indirect_Ptr_(ptr)
  793. {
  794. #pragma unused ptr
  795. assert(numargs() == 1);
  796. #emit LOAD.S.pri 12
  797. #emit LOAD.alt gsCodSize
  798. #emit ADD
  799. #emit RETN
  800. return 0;
  801. }
  802. #define Indirect_Ptr(%0) Indirect_Ptr_(_:(%0))
  803. /*-------------------------------------------------------------------------*//**
  804. * <param name="">The array to convert to an offset pointer.</param>
  805. * <remarks>
  806. * Strings and arrays are passed relative to `COD` not `DAT` so they can be
  807. * distinguished from normal function pointers. This function does the offset.
  808. * </remarks>
  809. *//*------------------------------------------------------------------------**/
  810. stock Indirect_DeRef_(...)
  811. {
  812. assert(numargs() == 1);
  813. #emit LOAD.S.pri 12
  814. #emit LOAD.alt gsCodSize
  815. #emit SUB
  816. #emit RETN
  817. return 0;
  818. }
  819. #define Indirect_DeRef(%0) Indirect_DeRef_(_:(%0))
  820. /*-------------------------------------------------------------------------*//**
  821. * <param name="">The array to convert to an offset pointer.</param>
  822. * <remarks>
  823. * Strings and arrays are passed relative to `COD` not `DAT` so they can be
  824. * distinguished from normal function pointers. This function does the offset.
  825. * </remarks>
  826. *//*------------------------------------------------------------------------**/
  827. stock Indirect_DePtr_(ptr)
  828. {
  829. #pragma unused ptr
  830. assert(numargs() == 1);
  831. #emit LOAD.S.pri 12
  832. #emit LOAD.alt gsCodSize
  833. #emit SUB
  834. #emit RETN
  835. return 0;
  836. }
  837. #define Indirect_DePtr(%0) Indirect_DePtr_(_:(%0))
  838. #if !defined _ALS_OnJITCompile
  839. forward OnJITCompile();
  840. #endif
  841. /*-------------------------------------------------------------------------*//**
  842. * <remarks>
  843. * A generic public wrapper for calling inline functions.
  844. * </remarks>
  845. *//*------------------------------------------------------------------------**/
  846. forward Indirect_FromCallback(Func:cb<>, bool:release);
  847. public Indirect_FromCallback(Func:cb<>, bool:release)
  848. {
  849. new ret = @.cb();
  850. if (release)
  851. Indirect_Release(cb);
  852. return ret;
  853. }
  854. /*-------------------------------------------------------------------------*//**
  855. * <remarks>
  856. * Get the size of the COD AMX segment.
  857. * </remarks>
  858. *//*------------------------------------------------------------------------**/
  859. Indirect_Init()
  860. {
  861. if (!gsCodSize)
  862. {
  863. AddressofResolve();
  864. new
  865. amxhdr[AMX_HDR];
  866. GetAmxHeader(amxhdr);
  867. gsCodSize = amxhdr[AMX_HDR_DAT] - amxhdr[AMX_HDR_COD];
  868. }
  869. }
  870. public OnJITCompile()
  871. {
  872. Indirect_Init();
  873. #if defined Indirection_OnJITCompile
  874. return Indirection_OnJITCompile();
  875. #else
  876. return 1;
  877. #endif
  878. }
  879. public OnFilterScriptInit()
  880. {
  881. Indirect_Init();
  882. #if defined Indirection_OnFilterScriptInit
  883. Indirection_OnFilterScriptInit();
  884. #endif
  885. return 1;
  886. }
  887. public OnGameModeInit()
  888. {
  889. Indirect_Init();
  890. #if defined Indirection_OnGameModeInit
  891. Indirection_OnGameModeInit();
  892. #endif
  893. return 1;
  894. }
  895. #if defined Indirection_OnJITCompile
  896. forward Indirection_OnJITCompile();
  897. #endif
  898. #if defined _ALS_OnJITCompile
  899. #undef OnJITCompile
  900. #else
  901. #define _ALS_OnJITCompile
  902. #endif
  903. #define OnJITCompile(%0) Indirection_OnJITCompile(%0)
  904. #if defined Indirection_OnFilterScriptInit
  905. forward Indirection_OnFilterScriptInit();
  906. #endif
  907. #if defined _ALS_OnFilterScriptInit
  908. #undef OnFilterScriptInit
  909. #else
  910. #define _ALS_OnFilterScriptInit
  911. #endif
  912. #define OnFilterScriptInit(%0) Indirection_OnFilterScriptInit(%0)
  913. #if defined Indirection_OnGameModeInit
  914. forward Indirection_OnGameModeInit();
  915. #endif
  916. #if defined _ALS_OnGameModeInit
  917. #undef OnGameModeInit
  918. #else
  919. #define _ALS_OnGameModeInit
  920. #endif
  921. #define OnGameModeInit(%0) Indirection_OnGameModeInit(%0)