2 +----------------------------------------------------------------------+
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 +----------------------------------------------------------------------+
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>
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').
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.
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.
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
99 * Service request types.
101 enum ServiceRequest
{
102 #define REQ(nm) REQ_##nm,
107 ///////////////////////////////////////////////////////////////////////////////
111 ///////////////////////////////////////////////////////////////////////////////
114 * ID to name mapping for tracing.
116 inline const char* to_name(ServiceRequest req
) {
117 static const char* reqNames
[] = {
122 return reqNames
[req
];
125 #undef SERVICE_REQUESTS
127 ///////////////////////////////////////////////////////////////////////////////
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
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
} {}
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
,
180 folly::Optional
<FPInvOffset
> spOff
,
183 template<typename
... Args
>
184 TCA
emit_ephemeral(CodeBlock
& cb
,
188 folly::Optional
<FPInvOffset
> spOff
,
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
,
198 folly::Optional
<FPInvOffset
> spOff
,
201 template<typename
... Args
>
202 TCA
emit_ephemeral(CodeBlock
& cb
,
205 folly::Optional
<FPInvOffset
> spOff
,
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;
236 constexpr int kMovLen
= 10;
237 constexpr int kLeaVmSpLen
= 7;
241 // vasm lea is emitted in 4 bytes.
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;
268 return kTotalArgs
* x64::kMovLen
+ x64::kLeaVmSpLen
;
270 return arm::kLeaVmSpLen
+
271 kTotalArgs
* arm::kMovLen
+
272 arm::kPersist
+ arm::kSvcReqExit
;
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.");
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");
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.
296 * The service request type.
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.
309 * Service request arguments; see SERVICE_REQUESTS for documentation.
314 SrcKey::AtomicInt sk
;
326 static_assert(sizeof(ReqInfo
) == 0x30,
327 "rsp adjustments in handleSRHelper");
329 ///////////////////////////////////////////////////////////////////////////////
333 #include "hphp/runtime/vm/jit/service-requests-inl.h"