forked from facebook/hhvm
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcode-gen-helpers-x64.h
More file actions
241 lines (199 loc) · 8.68 KB
/
Copy pathcode-gen-helpers-x64.h
File metadata and controls
241 lines (199 loc) · 8.68 KB
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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010-2014 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/
#ifndef incl_HPHP_VM_CODEGENHELPERS_X64_H_
#define incl_HPHP_VM_CODEGENHELPERS_X64_H_
#include "hphp/util/asm-x64.h"
#include "hphp/util/ringbuffer.h"
#include "hphp/runtime/base/types.h"
#include "hphp/runtime/vm/jit/abi-x64.h"
#include "hphp/runtime/vm/jit/code-gen-helpers.h"
#include "hphp/runtime/vm/jit/cpp-call.h"
#include "hphp/runtime/vm/jit/ir-opcode.h"
#include "hphp/runtime/vm/jit/phys-reg.h"
#include "hphp/runtime/vm/jit/service-requests-x64.h"
#include "hphp/runtime/vm/jit/service-requests.h"
#include "hphp/runtime/vm/jit/translator.h"
#include "hphp/runtime/vm/jit/vasm-x64.h"
namespace HPHP {
//////////////////////////////////////////////////////////////////////
struct Func;
namespace jit {
//////////////////////////////////////////////////////////////////////
struct Fixup;
struct SSATmp;
namespace x64 {
//////////////////////////////////////////////////////////////////////
typedef X64Assembler Asm;
constexpr size_t kJmpTargetAlign = 16;
void moveToAlign(CodeBlock& cb, size_t alignment = kJmpTargetAlign);
void emitEagerSyncPoint(Asm& as, const Op* pc, PhysReg vmfp, PhysReg vmsp);
void emitEagerSyncPoint(Vout& v, const Op* pc, Vreg vmfp, Vreg vmsp);
void emitEagerVMRegSave(Asm& as, RegSaveFlags flags);
void emitEagerVMRegSave(Vout& as, RegSaveFlags flags);
void emitGetGContext(Asm& as, PhysReg dest);
void emitGetGContext(Vout& as, Vreg dest);
void emitTransCounterInc(Asm& a);
void emitTransCounterInc(Vout&);
void emitIncRef(Asm& as, PhysReg base);
void emitIncRef(Vout& v, Vreg base);
void emitIncRefCheckNonStatic(Asm& as, PhysReg base, DataType dtype);
void emitIncRefGenericRegSafe(Asm& as, PhysReg base, int disp, PhysReg tmpReg);
void emitAssertFlagsNonNegative(Vout& v, Vreg sf);
void emitAssertRefCount(Vout& v, Vreg base);
void emitMovRegReg(Asm& as, PhysReg srcReg, PhysReg dstReg);
void emitLea(Asm& as, MemoryRef mr, PhysReg dst);
Vreg emitLdObjClass(Vout& v, Vreg objReg, Vreg dstReg);
Vreg emitLdClsCctx(Vout& v, Vreg srcReg, Vreg dstReg);
void emitCall(Asm& as, TCA dest, RegSet args);
void emitCall(Asm& as, CppCall call, RegSet args);
void emitCall(Vout& v, CppCall call, RegSet args);
// store imm to the 8-byte memory location at ref. Warning: don't use this
// if you wanted an atomic store; large imms cause two stores.
void emitImmStoreq(Vout& v, Immed64 imm, Vptr ref);
void emitImmStoreq(Asm& as, Immed64 imm, MemoryRef ref);
void emitRB(Vout& v, Trace::RingBufferType t, const char* msgm);
void emitTraceCall(CodeBlock& cb, Offset pcOff);
/*
* Tests the surprise flags for the current thread. Should be used
* before a jnz to surprise handling code.
*/
void emitTestSurpriseFlags(Asm& as);
Vreg emitTestSurpriseFlags(Vout&);
void emitCheckSurpriseFlagsEnter(Vout& main, Vout& cold, Fixup fixup);
void emitCheckSurpriseFlagsEnter(CodeBlock& mainCode, CodeBlock& coldCode,
Fixup fixup);
#ifdef USE_GCC_FAST_TLS
/*
* TLS access: XXX we currently only support static-style TLS directly
* linked off of FS.
*
* x86 terminology review: "Virtual addresses" are subject to both
* segmented translation and paged translation. "Linear addresses" are
* post-segmentation address, subject only to paging. C and C++ generally
* only have access to bitwise linear addresses.
*
* TLS data live at negative virtual addresses off FS: the first datum
* is typically at VA(FS:-sizeof(datum)). Linux's x64 ABI stores the linear
* address of the base of TLS at VA(FS:0). While this is just a convention, it
* is firm: gcc builds binaries that assume it when, e.g., evaluating
* "&myTlsDatum".
*
* The virtual addresses of TLS data are not exposed to C/C++. To figure it
* out, we take a datum's linear address, and subtract it from the linear
* address where TLS starts.
*/
template<typename T>
inline void
emitTLSLoad(Vout& v, const ThreadLocalNoCheck<T>& datum, Vreg reg) {
uintptr_t virtualAddress = uintptr_t(&datum.m_node.m_p) - tlsBase();
Vptr addr{baseless(virtualAddress), Vptr::FS};
v << load{addr, reg};
}
template<typename T>
inline void
emitTLSLoad(X64Assembler& a, const ThreadLocalNoCheck<T>& datum, Reg64 reg) {
uintptr_t virtualAddress = uintptr_t(&datum.m_node.m_p) - tlsBase();
a.fs().loadq(baseless(virtualAddress), reg);
}
#else // USE_GCC_FAST_TLS
template<typename T>
inline void
emitTLSLoad(Vout& v, const ThreadLocalNoCheck<T>& datum, Vreg dest) {
PhysRegSaver(v, kGPCallerSaved); // we don't know for sure what's alive
v << ldimm{datum.m_key, argNumToRegName[0]};
const CodeAddress addr = (CodeAddress)pthread_getspecific;
if (deltaFits((uintptr_t)addr, sz::dword)) {
v << call{addr, argSet(1)};
} else {
v << ldimm{addr, reg::rax};
v << callr{reg::rax, argSet(1)};
}
if (dest != Vreg(reg::rax)) {
v << copy{reg::rax, dest};
}
}
template<typename T>
inline void
emitTLSLoad(X64Assembler& a, const ThreadLocalNoCheck<T>& datum, Reg64 dest) {
PhysRegSaver(a, kGPCallerSaved); // we don't know for sure what's alive
a. emitImmReg(datum.m_key, argNumToRegName[0]);
const TCA addr = (TCA)pthread_getspecific;
if (deltaFits((uintptr_t)addr, sz::dword)) {
a. call(addr);
} else {
a. movq(addr, reg::rax);
a. call(reg::rax);
}
if (dest != reg::rax) {
a. movq(reg::rax, dest);
}
}
#endif // USE_GCC_FAST_TLS
// Emit a load of a low pointer.
void emitLdLowPtr(Vout& v, Vptr mem, Vreg reg, size_t size);
void emitCmpClass(Vout& v, Vreg sf, const Class* c, Vptr mem);
void emitCmpClass(Vout& v, Vreg sf, Vreg reg, Vptr mem);
void emitCmpClass(Vout& v, Vreg sf, Vreg reg1, Vreg reg2);
void copyTV(Vout& v, Vloc src, Vloc dst);
void pack2(Vout& v, Vreg s0, Vreg s1, Vreg d0);
Vreg zeroExtendIfBool(Vout& v, const SSATmp* src, Vreg reg);
ConditionCode opToConditionCode(Opcode opc);
template<ConditionCode Jcc, class Lambda>
void jccBlock(Asm& a, Lambda body) {
Label exit;
exit.jcc8(a, Jcc);
body();
asm_label(a, exit);
}
/*
* lookupDestructor --
*
* Return a MemoryRef pointer to the destructor for the type in typeReg.
*/
inline MemoryRef lookupDestructor(X64Assembler& a, PhysReg typeReg) {
auto const table = reinterpret_cast<intptr_t>(g_destructors);
always_assert_flog(deltaFits(table, sz::dword),
"Destructor function table is expected to be in the data "
"segment, with addresses less than 2^31"
);
static_assert((KindOfString >> kShiftDataTypeToDestrIndex == 1) &&
(KindOfArray >> kShiftDataTypeToDestrIndex == 2) &&
(KindOfObject >> kShiftDataTypeToDestrIndex == 3) &&
(KindOfResource >> kShiftDataTypeToDestrIndex == 4) &&
(KindOfRef >> kShiftDataTypeToDestrIndex == 5),
"lookup of destructors depends on KindOf* values");
a. shrl (kShiftDataTypeToDestrIndex, r32(typeReg));
return baseless(typeReg*8 + table);
}
inline Vptr lookupDestructor(Vout& v, Vreg typeReg) {
auto const table = reinterpret_cast<intptr_t>(g_destructors);
always_assert_flog(deltaFits(table, sz::dword),
"Destructor function table is expected to be in the data "
"segment, with addresses less than 2^31"
);
static_assert((KindOfString >> kShiftDataTypeToDestrIndex == 1) &&
(KindOfArray >> kShiftDataTypeToDestrIndex == 2) &&
(KindOfObject >> kShiftDataTypeToDestrIndex == 3) &&
(KindOfResource >> kShiftDataTypeToDestrIndex == 4) &&
(KindOfRef >> kShiftDataTypeToDestrIndex == 5),
"lookup of destructors depends on KindOf* values");
auto shiftedType = v.makeReg();
v << shrli{kShiftDataTypeToDestrIndex, typeReg, shiftedType, v.makeReg()};
return Vptr{Vreg{}, shiftedType, 8, safe_cast<int>(table)};
}
//////////////////////////////////////////////////////////////////////
}}}
#endif