POST_INTERP_RET: use a direct helper rather than service request
[hiphop-php.git] / hphp / runtime / vm / jit / service-requests.h
blob62d89827daa1467d6c886e716951af83cdfeef0c
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
17 #pragma once
19 #include "hphp/runtime/vm/srckey.h"
21 #include "hphp/runtime/vm/jit/types.h"
22 #include "hphp/runtime/vm/jit/containers.h"
23 #include "hphp/runtime/vm/jit/stack-offsets.h"
25 #include "hphp/util/asm-x64.h"
26 #include "hphp/util/data-block.h"
28 #include <folly/Optional.h>
30 namespace HPHP {
32 struct ActRec;
34 namespace jit {
36 struct CGMeta;
38 ///////////////////////////////////////////////////////////////////////////////
41 * A service request is a co-routine used to invoke JIT translation services.
43 * Most service requests are accomplished by jumping to a service request stub,
44 * which rolls up arguments and calls into the JIT via handleSRHelper().
45 * Afterwards, we re-enter the TC, returning control non-locally to the next
46 * logical instruction.
48 * The implementation of the service request will return the TCA at which to
49 * resume execution even if it's another stub rather than the calling function.
51 #define SERVICE_REQUESTS \
53 * bind_jmp(TCA jmp, SrcKey target)
55 * A jmp to the potentially untranslated code for `target'.
57 * Jump to a service request stub, which invokes the JIT and looks up the
58 * translation for `target'---or creates a translation if one does not exist.
59 * The address of the translation is then smashed into the immediate of the
60 * jump instruction (whose address is passed via `jmp').
61 */ \
62 REQ(BIND_JMP) \
65 * bind_addr(TCA* addr, SrcKey target)
67 * A code pointer to the potentially untranslated `target'; used for
68 * just-in-time indirect call translations.
70 * Similar to bind_jmp, except that the smash target is *addr instead of the
71 * jmp instruction's immediate. When we emit a bind_addr, we only emit the
72 * request stub and store its address to *addr; someone else has to emit the
73 * indirect jump that actually invokes the service request.
74 */ \
75 REQ(BIND_ADDR) \
78 * retranslate(Offset off)
80 * A request to retranslate the current function at bytecode offset `off',
81 * for when no existing translations support the incoming types.
83 * The smash target(s) of a retranslate is stored in
84 * SrcRec::m_tailFallbackJumps.
85 */ \
86 REQ(RETRANSLATE) \
89 * retranslate_opt(SrcKey sk)
91 * A request to retranslate the function from `sk', leveraging profiling data
92 * to produce a set of larger, more optimized translations. Only used when
93 * PGO is enabled. Execution will resume at `sk' whether or not retranslation
94 * is successful.
95 */ \
96 REQ(RETRANSLATE_OPT)
99 * Service request types.
101 enum ServiceRequest {
102 #define REQ(nm) REQ_##nm,
103 SERVICE_REQUESTS
104 #undef REQ
107 ///////////////////////////////////////////////////////////////////////////////
109 namespace svcreq {
111 ///////////////////////////////////////////////////////////////////////////////
114 * ID to name mapping for tracing.
116 inline const char* to_name(ServiceRequest req) {
117 static const char* reqNames[] = {
118 #define REQ(nm) #nm,
119 SERVICE_REQUESTS
120 #undef REQ
122 return reqNames[req];
125 #undef SERVICE_REQUESTS
127 ///////////////////////////////////////////////////////////////////////////////
128 // Emitters.
131 * Type-discriminated service request argument.
133 * Each argument is written to a register when the service request is made:
134 * - Immediates are loaded directly.
135 * - Addresses are loaded using an rip-relative lea to aid code relocation.
136 * - Condition codes produce a setcc based on the status flags passed to the
137 * emit routine.
139 struct Arg {
140 enum class Kind { Immed, Address, CondCode };
142 explicit Arg(uint64_t imm) : kind{Kind::Immed}, imm{imm} {}
143 explicit Arg(TCA addr) : kind{Kind::Address}, addr{addr} {}
144 explicit Arg(ConditionCode cc) : kind{Kind::CondCode}, cc{cc} {}
146 public:
147 Kind kind;
148 union {
149 uint64_t imm;
150 TCA addr;
151 ConditionCode cc;
155 using ArgVec = jit::vector<Arg>;
158 * Service request stub emitters.
160 * These stubs do some shuffling of arguments before launching into the JIT
161 * translator via handleSRHelper().
163 * Service request stubs can be either persistent or ephemeral. The only
164 * difference (besides that ephemeral service requests require a stub start
165 * address) is that ephemeral requests are padded to stub_size().
167 * Since making a service request leaves the TC, we need to sync the current
168 * bytecode eval stack pointer, given via `spOff', to vmsp. In the cases where
169 * vmsp also needs to be synced between translations (namely, in resumed
170 * contexts), we do this sync inline at the site of the jump to the stub, so
171 * that it still occurs once the jump gets smashed. Otherwise (namely, in
172 * non-resumed contexts), the client must pass a non-none `spOff', and we do
173 * the sync in the stub to save work once the service request is completed and
174 * the jump is smashed.
176 template<typename... Args>
177 TCA emit_persistent(CodeBlock& cb,
178 DataBlock& data,
179 CGMeta& meta,
180 folly::Optional<FPInvOffset> spOff,
181 ServiceRequest sr,
182 Args... args);
183 template<typename... Args>
184 TCA emit_ephemeral(CodeBlock& cb,
185 DataBlock& data,
186 CGMeta& meta,
187 TCA start,
188 folly::Optional<FPInvOffset> spOff,
189 ServiceRequest sr,
190 Args... args);
192 * These emit service request stubs that may not be relocated. This distinction
193 * is important, because these discard metadata that allows relocation.
195 template<typename... Args>
196 TCA emit_persistent(CodeBlock& cb,
197 DataBlock& data,
198 folly::Optional<FPInvOffset> spOff,
199 ServiceRequest sr,
200 Args... args);
201 template<typename... Args>
202 TCA emit_ephemeral(CodeBlock& cb,
203 DataBlock& data,
204 TCA start,
205 folly::Optional<FPInvOffset> spOff,
206 ServiceRequest sr,
207 Args... args);
210 * Helpers for emitting specific service requests.
212 TCA emit_bindjmp_stub(CodeBlock& cb, DataBlock& data, CGMeta& fixups,
213 FPInvOffset spOff, TCA jmp, SrcKey target);
214 TCA emit_bindaddr_stub(CodeBlock& cb, DataBlock& data, CGMeta& fixups,
215 FPInvOffset spOff, TCA* addr, SrcKey target);
216 TCA emit_retranslate_opt_stub(CodeBlock& cb, DataBlock& data, CGMeta& fixups,
217 FPInvOffset spOff, SrcKey sk);
220 * Emit a stub which syncs vmsp and vmpc and then calls
221 * resumeHelperNoTranslate. Call are smashed to this when we know we
222 * can no longer create new translations. The address of the stub is
223 * returned if successful, nullptr otherwise (the creation can fail if
224 * there's no space in the TC for it).
226 TCA emit_interp_no_translate_stub(FPInvOffset spOff, SrcKey sk);
228 ///////////////////////////////////////////////////////////////////////////////
231 * Maximum number of arguments a service request can accept.
233 constexpr int kMaxArgs = 4;
235 namespace x64 {
236 constexpr int kMovLen = 10;
237 constexpr int kLeaVmSpLen = 7;
240 namespace arm {
241 // vasm lea is emitted in 4 bytes.
242 // ADD imm
243 constexpr int kLeaVmSpLen = 4;
244 // The largest of vasm setcc, copy, or leap is emitted in 16 bytes.
245 // AND imm, MOV, LDR + B + dc32, or ADRP + ADD imm
246 constexpr int kMovLen = 12;
247 // The largest of vasm copy or leap is emitted in 16 bytes.
248 // MOV, LDR + B + dc32, or ADRP + ADD imm
249 constexpr int kPersist = 12;
250 // vasm copy and jmpi is emitted in 16 bytes.
251 // MOV + LDR + B + dc32
252 constexpr int kSvcReqExit = 16;
256 * Space used by an ephemeral stub.
258 * All ephemeral service request stubs are sized to this fixed, architecture-
259 * dependent size, which is guaranteed to fit all service request types along
260 * with a terminal padding instruction.
262 constexpr size_t stub_size() {
263 // The extra args are the request type and the stub address.
264 constexpr auto kTotalArgs = kMaxArgs + 2;
266 switch (arch()) {
267 case Arch::X64:
268 return kTotalArgs * x64::kMovLen + x64::kLeaVmSpLen;
269 case Arch::ARM:
270 return arm::kLeaVmSpLen +
271 kTotalArgs * arm::kMovLen +
272 arm::kPersist + arm::kSvcReqExit;
273 default:
274 // GCC has a bug with throwing in a constexpr function.
275 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67371
276 // throw std::logic_error("Stub size not defined on architecture.");
277 break;
279 // Because of GCC's issue, we have this assert, and a return value.
280 static_assert(arch() == Arch::X64 || arch() == Arch::ARM,
281 "Stub size not defined on architecture");
282 return 0;
285 ///////////////////////////////////////////////////////////////////////////////
288 * Service request metadata.
290 * This structure is created on the stack by handleSRHelper() from the SR
291 * arguments passed in registers. Any changes to its size or layout of must be
292 * reflected in the handleSRHelper unique stub.
294 struct ReqInfo {
296 * The service request type.
298 ServiceRequest req;
301 * Address of the service request's code stub for non-persistent requests.
303 * The service request handler will free this stub if it's set, after the
304 * service is performed.
306 TCA stub;
309 * Service request arguments; see SERVICE_REQUESTS for documentation.
311 union {
312 TCA tca;
313 Offset offset;
314 SrcKey::AtomicInt sk;
315 TransID transID;
316 bool boolVal;
317 ActRec* ar;
318 Value tvData;
319 struct {
320 DataType tvType;
321 AuxUnion tvAux;
323 } args[kMaxArgs];
326 static_assert(sizeof(ReqInfo) == 0x30,
327 "rsp adjustments in handleSRHelper");
329 ///////////////////////////////////////////////////////////////////////////////
333 #include "hphp/runtime/vm/jit/service-requests-inl.h"