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/call-flags.h"
20 #include "hphp/runtime/vm/hhbc.h"
22 #include "hphp/runtime/vm/jit/code-cache.h"
23 #include "hphp/runtime/vm/jit/containers.h"
24 #include "hphp/runtime/vm/jit/types.h"
25 #include "hphp/runtime/vm/jit/phys-reg.h"
26 #include "hphp/runtime/vm/jit/srcdb.h"
27 #include "hphp/runtime/vm/jit/stack-offsets.h"
37 namespace Debug
{ struct DebugInfo
; }
41 ///////////////////////////////////////////////////////////////////////////////
43 constexpr int kNumFreeLocalsHelpers
= 7;
46 * Addresses of various unique, long-lived JIT helper routines.
48 * The global set of unique stubs is emitted when we initialize the TC.
52 * Unique stubs, ABIs, and stack alignment.
54 * A lot of complex control flow occurs amongst the various unique stubs, as
55 * well as between the unique stubs and the TC. This complexity is
56 * exacerbated by the profusion of different ABIs used when entering and
59 * The goal of the documentation in this file is to enumerate all the ways
60 * each stub is reached, as well as to clarify the ABI boundaries they
61 * implement to, if any.
63 * Among the most important ABI invariants in jitted code is this:
65 * - In the body of a PHP function, after the initial instructions of the
66 * func prologue, the native stack pointer is always 16-byte aligned.
68 * This holds even when the register allocator inserts stack spills; we
69 * always offset the native stack pointer in increments of 16.
71 * Many target architectures have 16-byte stack alignment restrictions. On
72 * x64, for example, the stack must be 16-byte aligned before calls, to allow
73 * the compiler to safely use aligned movs, e.g., for saving callee-saved XMM
74 * registers. On AArch64, attempting to address the stack pointer when it is
75 * not 16-byte aligned results in a fault.
77 * Our alignment invariant should be sufficient for architectures with
78 * 16-byte (or looser) alignment constraints. We don't currently support any
79 * higher- order alignment restrictions.
81 * Our other ABI concern is calling convention. HHVM supports three distinct
82 * calling conventions:
83 * - native: C++ helper calls on the targeted architecture
84 * - PHP: calls between PHP functions, as well as to those unique stubs
85 * which play the same role as various parts of PHP functions
86 * - stub: calls to unique stubs that implement helper routines
88 * Maintaining native stack alignment, and appropriately stashing the return
89 * address, is shared between the call, return, and callee prologue
90 * instructions for each convention:
92 * +---------------------+---------+-----------+
93 * | main call instrs | return | prologue |
94 * +---------+---------------------+---------+-----------+
95 * | native | call{,r,m,s} | ret | N/A |
96 * +---------+---------------------+---------+-----------+
97 * | PHP | phpcall | phpret | phplogue |
98 * +---------+---------------------+---------+----------+
99 * | stub | callstub | stubret | stublogue |
100 * +---------+---------------------+---------+-----------+
102 * Further documentation on these calling conventions can be found in
103 * vasm-instr.h, alongside the corresponding instructions.
105 * Each stub is documented below with a (hopefully) exhaustive list of ways
106 * it is reached, as well as the context under which it is reached:
107 * - func guard: pre-phplogue{}; an intermediate state where
108 * addressing the stack and making native calls are
110 * - func prologue: implements a phplogue{}
111 * - func body: dominated by a phplogue{}; already ABI-conforming
112 * - stub: implements a stublogue{}
115 /////////////////////////////////////////////////////////////////////////////
119 * Dynamically dispatch to the appropriate func prologue based on the
120 * information in php_call_regs, while repacking arguments as needed.
122 * @reached: callphp from TC
123 * @context: func guard
125 TCA funcPrologueRedispatch
;
126 TCA funcPrologueRedispatchUnpack
;
129 * Look up or emit a func prologue and jump to it---or, failing that, call
130 * native routines that do the same work.
132 * All entries in the prologue tables of all Funcs are initialized to this
133 * stub, so that we can lazily generate their prologues. If codegen for the
134 * prologue succeeds, we update the prologue table to point to the new
135 * prologue instead of this stub.
137 * @reached: callphpr from TC
139 * jmp from immutableBindCallStub
140 * jmp from funcPrologueRedispatch
141 * jmp from funcPrologueRedispatchUnpack
142 * @context: func prologue
144 TCA fcallHelperThunk
;
145 TCA fcallHelperNoTranslateThunk
;
148 * Call EventHook::onFunctionCall() and handle the case where it requests
149 * that we skip the function.
151 * @reached: vinvoke from func prologue
152 * jmp from functionSurprisedOrStackOverflow
155 TCA functionEnterHelper
;
158 * Handle either a surprise condition or a stack overflow.
160 * Also gracefully handles spurious wake-ups that result from racing with a
161 * background thread clearing surprise flags.
163 * @reached: vinvoke from func prologue
166 TCA functionSurprisedOrStackOverflow
;
169 /////////////////////////////////////////////////////////////////////////////
173 * Return from a function when the ActRec was pushed by the interpreter.
175 * The return IP on the ActRec will be set to one of these stubs, so if
176 * someone tries to execute a return instruction, handlePostInterpRet() gets
177 * a chance to translate the code starting at the return address.
179 * Generators need a different stub because the ActRec for a generator is in
182 * @reached: phpret from TC
183 * @context: func body (after returning to caller)
186 TCA genRetHelper
; // version for generator
187 TCA asyncGenRetHelper
; // version for async generators
190 * Return from a function when the ActRec was pushed by an inlined call.
192 * This is the same as retHelper, but is kept separate to aid in debugging.
194 * @reached: phpret from TC
195 * @context: func body (after returning to caller)
200 * Return from a resumed async function.
202 * Store result into the AsyncFunctionWaitHandle, mark it as finished and
203 * unblock its parents. Check whether the first parent is eligible to be
204 * resumed directly (it is an AsyncFunctionWaitHandle in the same context
205 * with a non-null resume address), and do so if possible. Otherwise, jump
206 * to asyncSwitchCtrl. Slow version doesn't try to resume and just returns
207 * to the asio scheduler.
209 * rvmfp() should point to the ActRec of the AsyncFunctionWaitHandle that
210 * is returning, rvmsp() should point to an uninitialized cell on the
211 * stack containing garbage.
213 * @reached: jmp from TC
214 * @context: func body
217 TCA asyncFuncRetSlow
;
220 * Async function finish-suspend-and-resume stub.
222 * Check for fast resumables on the AsioContext runnable queue. If one is
223 * found that is ready to run, jump to it directly; otherwise, leave the TC
224 * and return to the scheduler.
226 * rvmfp() should point to the ActRec of the WaitHandle that is suspending.
228 * @reached: jmp from TC
229 * @context: func body
234 /////////////////////////////////////////////////////////////////////////////
238 * Stub for immutable PHP calls.
240 * @reached: callphps from TC
241 * @context: func prologue
243 TCA immutableBindCallStub
;
246 /////////////////////////////////////////////////////////////////////////////
247 // Interpreter stubs.
250 * Restart execution based on the value of vmpc. Used, e.g., to resume
251 * execution after an InterpOne.
253 * Expects that all VM registers are synced.
255 * @reached: entry from jit::enterTC
256 * jmp from fcallHelperThunk
257 * call from enterTCHelper
258 * @context: func body
261 TCA resumeHelperNoTranslate
;
264 * Like resumeHelper, but interpret a basic block first to ensure we make
267 * interpHelper expects the correct value of vmpc to be in the first argument
268 * register and syncs it, whereas interpHelperSyncedPC expects vmpc to be
269 * synced a priori. Both stubs will sync the vmsp and vmfp registers to
270 * vmRegs before passing control to the interpreter.
272 * @reached: jmp from TC
273 * @context: func body
276 TCA interpHelperSyncedPC
;
277 TCA interpHelperNoTranslate
;
280 * Stubs for each bytecode with the CF flag, which InterpOne the bytecode and
281 * then call resumeHelper.
283 * These stubs expect rvmfp() and rvmsp() to be live, and rAsm to contain the
284 * offset to the bytecode to interpret.
286 * @reached: jmp from TC
287 * @context: func body
289 jit::fast_map
<Op
, TCA
> interpOneCFHelpers
;
292 /////////////////////////////////////////////////////////////////////////////
296 * Expensive, generic decref of a value with an unknown (but known to be
297 * refcounted) DataType.
299 * The value to be decref'd should be in the first two argument registers
300 * (data, type). All GP registers are saved around the destructor call.
302 * @reached: callfaststub from TC
308 * Perform generic decrefs of locals on function return.
310 * Each freeLocalHelpers[i] is an entry point to a partially-unrolled loop.
311 * freeManyLocalsHelper should be used instead when there are more than
312 * kNumFreeLocalsHelpers locals.
314 * These helpers expect the address of the frame's last local variable (which
315 * has the lowest address) to be passed in the second argument register. The
316 * first argument register is ignored.
318 * @reached: vcall from TC
321 TCA freeLocalsHelpers
[kNumFreeLocalsHelpers
];
322 TCA freeManyLocalsHelper
;
325 /////////////////////////////////////////////////////////////////////////////
329 * Enter (or reenter) the TC.
331 * This is an assembly stub called from native code to transfer control
332 * (back) to jitted PHP code.
334 * enterTCExit is the address returned to when we leave the TC.
336 void (*enterTCHelper
)(TCA start
, ActRec
* fp
, void* tl
, TypedValue
* sp
,
341 * Return from this VM nesting level to the previous one.
343 * This has the same effect as a leavetc{} instruction---it pops the address
344 * of enterTCExit off the stack and transfers control to it.
346 * @reached: phpret from TC
348 * @context: func body
353 * Perform dispatch at the end of a catch block.
355 * The endCatchHelper passes the current vmfp() to the unwinder to determine
356 * the catch trace of the return address of the parent frame.
358 * The endCatchStublogueHelper passes the current vmfp() and RIP saved in
359 * the stublogue header. Unwinder uses it to determine the catch trace of
360 * the return adddress belonging to the same logical vmfp().
362 * The endCatchStubloguePrologueHelper initializes the ActRec space pointed
363 * to by the rvmsp() to uninits and continues at endCatchStublogueHelper.
365 * If the unwinder has set state indicating a return address to jump to, we
366 * load vmfp and vmsp and jump there. Otherwise, we call _Unwind_Resume.
369 TCA endCatchSkipTeardownHelper
;
370 TCA endCatchTeardownThisHelper
;
372 TCA endCatchHelperPast
;
373 TCA endCatchStublogueHelper
;
374 TCA endCatchStubloguePrologueHelper
;
375 TCA unwinderAsyncRet
;
376 TCA unwinderAsyncNullRet
;
379 * Throws an exception from the unwinder to enter the itanium unwinder
381 TCA throwExceptionWhileUnwinding
;
384 * Service request helper.
386 * Packs service request arguments into a struct on the stack before calling
387 * the C++ service request handler.
389 * @reached: jmp from TC
390 * @context: func body
395 * Handle a request to retranslate the current function in optimized mode.
396 * See svcreq::handleRetranslateOpt() for more details.
398 * @reached: jmp from TC
399 * @context: func body
401 TCA handleRetranslateOpt
;
403 /////////////////////////////////////////////////////////////////////////////
406 * Emit the full set of unique stubs to `code'.
408 void emitAll(CodeCache
& code
, Debug::DebugInfo
& dbg
);
411 * Utility for logging stub addresses during startup and registering the gdb
412 * symbols. It's often useful to know where they were when debugging.
414 void add(const char* name
,
415 const CodeCache
& code
,
417 CodeCache::View view
,
419 Debug::DebugInfo
& dbg
);
422 * If the given address is within one of the registered stubs, return a
423 * string indicating which stub and how far in it is: "retHelper+0xfa".
425 * Otherwise, return a string representation of the raw address: "0xabcdef".
427 std::string
describe(TCA addr
) const;
431 * Emit all Resumable-related unique stubs to `code'.
433 void emitAllResumable(CodeCache
& code
, Debug::DebugInfo
& dbg
);
439 bool operator<(const StubRange
& other
) const {
440 return start
< other
.start
;
443 bool contains(TCA address
) const {
444 return start
<= address
&& address
< end
;
448 std::vector
<StubRange
> m_ranges
;
451 ////////////////////////////////////////////////////////////////////////////////
454 * Registers that are live on entry to an interpOneCFHelper.
456 RegSet
interp_one_cf_regs();
459 * Emit code to `v' which jumps to interpHelper with the proper arguments.
461 void emitInterpReq(Vout
& v
, SrcKey sk
, SBInvOffset spOff
);
462 void emitInterpReqNoTranslate(Vout
& v
, SrcKey sk
, SBInvOffset spOff
);
464 ///////////////////////////////////////////////////////////////////////////////
467 * Wrappers around the enterTC*Helper stubs, called from enterTC*().
469 void enterTCImpl(TCA start
);
471 ///////////////////////////////////////////////////////////////////////////////