-
Notifications
You must be signed in to change notification settings - Fork 14
/
addressof_jit.inc
124 lines (115 loc) · 4.31 KB
/
addressof_jit.inc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
// 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
/**
* <library name="amx_assembly addressof_jit" summary="AMX Assembly Library: `addressof` JIT code.">
* <summary pawndoc="true">
* This library uses the enhanced <em>pawndoc.xsl</em> from
* <a href="https://github.com/pawn-lang/pawndoc">pawn-lang/pawndoc</a>.
* This XSL has features such as library and markdown support, and will not
* render this message when used.
* </summary>
* <remarks>
* <c>addressof</c> 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 <c>CALL</c> 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 <em>codescan</em> to convert
* runtime <c>addressof</c> calls to startup-time resolutions. Actually,
* there's no reason why this should be restricted to JIT only.
* </remarks>
* </library>
*/
/// <p/>
#include "addressof_light"
#include "codescan"
#include "asm"
/// <library>amx_assembly addressof_jit</library>
static stock AddressofResolveFoundStart(const 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]);
new dctx[DisasmContext];
CodeScanGetMatchDisasm(scanner, dctx),
// Skip the three matched instructions.
DisasmNextInsn(dctx),
DisasmNextInsn(dctx),
DisasmNextInsn(dctx);
// Find a `call`.
while (DisasmNextInsn(dctx) != OP_CALL)
{
// Do nothing.
}
new ptr = DisasmGetOperandReloc(dctx);
// Found the location.
AsmInitPtr(ctx, CodeScanGetMatchHole(scanner, 0) - hdr[AMX_HDR_DAT] + hdr[AMX_HDR_COD], 2 * cellbytes);
AsmEmitConstPri(ctx, ptr);
}
/// <library>amx_assembly addressof_jit</library>
stock AddressofResolve() {
static
bool:gAddressofResolved = false;
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);
// Run the scanner.
CodeScanRunFast(scanner, &AddressOfGetNextCall_);
}