1
0

addressof_jit.inc 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. // Copyright (C) 2016 Y_Less
  2. //
  3. // Permission is hereby granted, free of charge, to any person obtaining a
  4. // copy of this software and associated documentation files (the "Software"),
  5. // to deal in the Software without restriction, including without limitation
  6. // the rights to use, copy, modify, merge, publish, distribute, sublicense,
  7. // and/or sell copies of the Software, and to permit persons to whom the
  8. // Software is furnished to do so, subject to the following conditions:
  9. //
  10. // The above copyright notice and this permission notice shall be included in
  11. // all copies or substantial portions of the Software.
  12. //
  13. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  14. // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  18. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  19. // DEALINGS IN THE SOFTWARE.
  20. #if defined ADDRESSOF_JIT_INC
  21. #endinput
  22. #endif
  23. #define ADDRESSOF_JIT_INC
  24. #include "addressof"
  25. #include "codescan"
  26. #include "asm"
  27. static stock
  28. bool:gAddressofResolved = false;
  29. // `addressof` works by reading data directly out of the stack to get a return
  30. // address, then reading information from that location in memory to get the
  31. // next `CALL` OpCode. This fails with the JIT because the return address is in
  32. // the JITed code, not in the original p-code. Instead, when the JIT is in use,
  33. // use `codescan` to convert runtime `addressof` calls to startup-time
  34. // resolutions. Actually, there's no reason why this should be restricted to
  35. // JIT only.
  36. static stock AddressofResolveFoundStart(scanner[CodeScanner]) {
  37. // Skip over now superfluous code.
  38. new ctx[AsmContext];
  39. CodeScanGetMatchAsm(scanner, ctx);
  40. new
  41. hdr[AMX_HDR];
  42. GetAmxHeader(hdr);
  43. AsmEmitJump(ctx, CodeScanGetMatchHole(scanner, 0) + GetAmxBaseAddress() + hdr[AMX_HDR_COD]);
  44. }
  45. static stock AddressofResolveFoundEnd(scanner[CodeScanner]) {
  46. // Write a `const` for the function address.
  47. new ctx[AsmContext];
  48. CodeScanGetMatchAsm(scanner, ctx, CodeScanGetMatchLength(scanner) - 2 * cellbytes);
  49. AsmEmitConstPri(ctx, CodeScanGetMatchHole(scanner, 0));
  50. }
  51. stock AddressofResolve() {
  52. if (gAddressofResolved)
  53. return;
  54. gAddressofResolved = true;
  55. // Scan through the entire assembly and replace calls to `addressof` with
  56. // just a constant. The generated assembly is amazingly consistent between
  57. // different optimisation levels:
  58. //
  59. // push.c 0 // Make `jump l.185`
  60. // call .O@A_
  61. // jzer 185 // Jump target.
  62. // push.c 0 // (tested function call).
  63. // call .MyFunc // (tested function call).
  64. // load.pri 2950
  65. // jzer 187
  66. // const.pri 1
  67. // jump 188
  68. // l.187
  69. // const.pri 2
  70. // l.188
  71. // jump 186
  72. // l.185
  73. // load.pri 2950 // Make `const.pri .MyFunc`
  74. // l.186
  75. //
  76. // We can actually use `addressof` (via `&`) in this code, since it should
  77. // NEVER be called after the JIT has started. We assert that.
  78. assert(!GetAmxJITBaseAddress());
  79. new scanner[CodeScanner];
  80. CodeScanInit(scanner);
  81. // Start.
  82. new csm1[CodeScanMatcher];
  83. CodeScanMatcherInit(csm1, &AddressofResolveFoundStart);
  84. CodeScanMatcherPattern(csm1,
  85. OP(PUSH_C, 0)
  86. OP(CALL, &AddressOfGetNextCall_)
  87. OP(JZER, ???)
  88. );
  89. CodeScanAddMatcher(scanner, csm1);
  90. // End.
  91. new csm2[CodeScanMatcher];
  92. CodeScanMatcherInit(csm2, &AddressofResolveFoundEnd);
  93. CodeScanMatcherPattern(csm2,
  94. OP(CALL, ???)
  95. OP(LOAD_PRI, ref(gAddressOfReturnVar_))
  96. OP(JZER, ???)
  97. OP(CONST_PRI, 1)
  98. OP(JUMP, ???)
  99. OP(CONST_PRI, 2)
  100. OP(JUMP, ???)
  101. OP(LOAD_PRI, ref(gAddressOfReturnVar_))
  102. );
  103. CodeScanAddMatcher(scanner, csm2);
  104. // End with heap.
  105. new csm3[CodeScanMatcher];
  106. CodeScanMatcherInit(csm3, &AddressofResolveFoundEnd);
  107. CodeScanMatcherPattern(csm3,
  108. OP(CALL, ???)
  109. OP(HEAP, ???)
  110. OP(LOAD_PRI, ref(gAddressOfReturnVar_))
  111. OP(JZER, ???)
  112. OP(CONST_PRI, 1)
  113. OP(JUMP, ???)
  114. OP(CONST_PRI, 2)
  115. OP(JUMP, ???)
  116. OP(LOAD_PRI, ref(gAddressOfReturnVar_))
  117. );
  118. CodeScanAddMatcher(scanner, csm3);
  119. // Run the scanner.
  120. CodeScanRun(scanner);
  121. }