| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133 |
- // Copyright (C) 2016 Y_Less
- //
- // Permission is hereby granted, free of charge, to any person obtaining a
- // copy of this software and associated documentation files (the "Software"),
- // to deal in the Software without restriction, including without limitation
- // the rights to use, copy, modify, merge, publish, distribute, sublicense,
- // and/or sell copies of the Software, and to permit persons to whom the
- // Software is furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- // DEALINGS IN THE SOFTWARE.
- #if defined ADDRESSOF_JIT_INC
- #endinput
- #endif
- #define ADDRESSOF_JIT_INC
- #include "addressof"
- #include "codescan"
- #include "asm"
- static stock
- bool:gAddressofResolved = false;
- // `addressof` works by reading data directly out of the stack to get a return
- // address, then reading information from that location in memory to get the
- // next `CALL` OpCode. This fails with the JIT because the return address is in
- // the JITed code, not in the original p-code. Instead, when the JIT is in use,
- // use `codescan` to convert runtime `addressof` calls to startup-time
- // resolutions. Actually, there's no reason why this should be restricted to
- // JIT only.
- static stock AddressofResolveFoundStart(scanner[CodeScanner]) {
- // Skip over now superfluous code.
- new ctx[AsmContext];
- CodeScanGetMatchAsm(scanner, ctx);
- new
- hdr[AMX_HDR];
- GetAmxHeader(hdr);
- AsmEmitJump(ctx, CodeScanGetMatchHole(scanner, 0) + GetAmxBaseAddress() + hdr[AMX_HDR_COD]);
- }
- static stock AddressofResolveFoundEnd(scanner[CodeScanner]) {
- // Write a `const` for the function address.
- new ctx[AsmContext];
- CodeScanGetMatchAsm(scanner, ctx, CodeScanGetMatchLength(scanner) - 2 * cellbytes);
- AsmEmitConstPri(ctx, CodeScanGetMatchHole(scanner, 0));
- }
- stock AddressofResolve() {
- if (gAddressofResolved)
- return;
- gAddressofResolved = true;
- // Scan through the entire assembly and replace calls to `addressof` with
- // just a constant. The generated assembly is amazingly consistent between
- // different optimisation levels:
- //
- // push.c 0 // Make `jump l.185`
- // call .O@A_
- // jzer 185 // Jump target.
- // push.c 0 // (tested function call).
- // call .MyFunc // (tested function call).
- // load.pri 2950
- // jzer 187
- // const.pri 1
- // jump 188
- // l.187
- // const.pri 2
- // l.188
- // jump 186
- // l.185
- // load.pri 2950 // Make `const.pri .MyFunc`
- // l.186
- //
- // We can actually use `addressof` (via `&`) in this code, since it should
- // NEVER be called after the JIT has started. We assert that.
- assert(!GetAmxJITBaseAddress());
- new scanner[CodeScanner];
- CodeScanInit(scanner);
-
- // Start.
- new csm1[CodeScanMatcher];
- CodeScanMatcherInit(csm1, &AddressofResolveFoundStart);
- CodeScanMatcherPattern(csm1,
- OP(PUSH_C, 0)
- OP(CALL, &AddressOfGetNextCall_)
- OP(JZER, ???)
- );
- CodeScanAddMatcher(scanner, csm1);
-
- // End.
- new csm2[CodeScanMatcher];
- CodeScanMatcherInit(csm2, &AddressofResolveFoundEnd);
- CodeScanMatcherPattern(csm2,
- OP(CALL, ???)
- OP(LOAD_PRI, ref(gAddressOfReturnVar_))
- OP(JZER, ???)
- OP(CONST_PRI, 1)
- OP(JUMP, ???)
- OP(CONST_PRI, 2)
- OP(JUMP, ???)
- OP(LOAD_PRI, ref(gAddressOfReturnVar_))
- );
- CodeScanAddMatcher(scanner, csm2);
-
- // End with heap.
- new csm3[CodeScanMatcher];
- CodeScanMatcherInit(csm3, &AddressofResolveFoundEnd);
- CodeScanMatcherPattern(csm3,
- OP(CALL, ???)
- OP(HEAP, ???)
- OP(LOAD_PRI, ref(gAddressOfReturnVar_))
- OP(JZER, ???)
- OP(CONST_PRI, 1)
- OP(JUMP, ???)
- OP(CONST_PRI, 2)
- OP(JUMP, ???)
- OP(LOAD_PRI, ref(gAddressOfReturnVar_))
- );
- CodeScanAddMatcher(scanner, csm3);
-
- // Run the scanner.
- CodeScanRun(scanner);
- }
|