2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2014 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 #ifndef incl_HPHP_TRANSLATOR_INLINE_H_
18 #define incl_HPHP_TRANSLATOR_INLINE_H_
20 #include "hphp/runtime/vm/jit/translator.h"
21 #include "hphp/runtime/vm/jit/translator-helpers.h"
22 #include <boost/noncopyable.hpp>
23 #include "hphp/runtime/base/execution-context.h"
26 * Because of a circular dependence with ExecutionContext, these
27 * translation-related helpers cannot live in translator.h.
32 * Accessors for the virtual machine registers, both rvalues and
35 * Note that these do not assert anything about tl_regState; use
38 inline Cell
*& vmsp() { return (Cell
*&)g_context
->m_stack
.top(); }
39 inline Cell
*& vmfp() { return (Cell
*&)g_context
->m_fp
; }
40 inline const unsigned char*& vmpc() { return g_context
->m_pc
; }
41 inline ActRec
*& vmFirstAR() { return g_context
->m_firstAR
; }
43 inline ActRec
* liveFrame() { return (ActRec
*)vmfp(); }
44 inline const Func
* liveFunc() { return liveFrame()->m_func
; }
45 inline const Unit
* liveUnit() { return liveFunc()->unit(); }
46 inline Class
* liveClass() { return liveFunc()->cls(); }
47 inline bool liveResumed() { return liveFrame()->resumed(); }
49 inline Offset
liveSpOff() {
51 if (liveFrame()->resumed()) {
52 fp
= (Cell
*)Stack::resumableStackBase((ActRec
*)fp
);
59 inline int cellsToBytes(int nCells
) {
60 return safe_cast
<int32_t>(nCells
* ssize_t(sizeof(Cell
)));
63 inline int localOffset(int locId
) {
64 return -cellsToBytes(locId
+ 1);
67 inline void assert_native_stack_aligned() {
69 assert(reinterpret_cast<uintptr_t>(__builtin_frame_address(0)) % 16 == 0);
74 * This class is used as a scoped guard around code that is called from the JIT
75 * which needs the VM to be in a consistent state. JIT helpers use it to guard
76 * calls into HHVM's runtime. It is used like this:
78 * void helperFunction() {
83 * VMRegAnchor should also be used before entering a C library compiled with
84 * -fomit-frame-pointer which will call back into HHVM. If VMRegAnchor is not
85 * used, HHVM's runtime will attempt to traverse the native stack, and will
86 * assert or crash if it attempts to parse a part of the stack with no frame
87 * pointers. VMRegAnchor forces the stack traversal to be done when it is
90 struct VMRegAnchor
: private boost::noncopyable
{
93 assert_native_stack_aligned();
97 explicit VMRegAnchor(ActRec
* ar
) {
98 // Some C++ entry points have an ActRec prepared from after a call
99 // instruction. This syncs us to right after the call instruction.
100 assert(tl_regState
== VMRegState::DIRTY
);
101 m_old
= VMRegState::DIRTY
;
102 tl_regState
= VMRegState::CLEAN
;
104 auto prevAr
= g_context
->getOuterVMFrame(ar
);
105 const Func
* prevF
= prevAr
->m_func
;
106 assert(!ar
->resumed());
107 vmsp() = (TypedValue
*)ar
- ar
->numArgs();
108 assert(g_context
->m_stack
.isValidAddress((uintptr_t)vmsp()));
109 vmpc() = prevF
->unit()->at(prevF
->base() + ar
->m_soff
);
110 vmfp() = (TypedValue
*)prevAr
;
118 * This class is used as an invocation guard equivalent to VMRegAnchor, except
119 * the sync is assumed to have already been done. This was part of a
120 * project aimed at improving performance by doing the fixup in advance, i.e.
121 * eagerly -- the benefits turned out to be marginal or negative in most cases.
123 struct EagerVMRegAnchor
{
127 DEBUG_ONLY
const Cell
* fp
= vmfp();
128 DEBUG_ONLY
const Cell
* sp
= vmsp();
129 DEBUG_ONLY
const auto* pc
= vmpc();
131 assert(vmfp() == fp
);
132 assert(vmsp() == sp
);
133 assert(vmpc() == pc
);
136 tl_regState
= VMRegState::CLEAN
;
138 ~EagerVMRegAnchor() {
143 inline ActRec
* regAnchorFP(Offset
* pc
= nullptr) {
144 // In builtins, m_fp points to the caller's frame if called
145 // through FCallBuiltin, else it points to the builtin's frame,
146 // in which case, getPrevVMState() gets the caller's frame.
147 // In addition, we need to skip over php-defined builtin functions
148 // in order to find the true context.
149 auto const context
= g_context
.getNoCheck();
150 auto cur
= context
->getFP();
151 if (pc
) *pc
= cur
->m_func
->unit()->offsetOf(context
->getPC());
152 while (cur
&& cur
->skipFrame()) {
153 cur
= context
->getPrevVMState(cur
, pc
);
158 inline ActRec
* regAnchorFPForArgs() {
159 // Like regAnchorFP, but only account for FCallBuiltin
160 auto const context
= g_context
.getNoCheck();
161 ActRec
* cur
= context
->getFP();
162 if (cur
&& cur
->m_func
->isCPPBuiltin()) {
163 cur
= context
->getPrevVMState(cur
);
168 struct EagerCallerFrame
: public EagerVMRegAnchor
{
169 ActRec
* operator()() {
170 return regAnchorFP();
172 ActRec
* actRecForArgs() { return regAnchorFPForArgs(); }
176 // VM helper to retrieve the frame pointer from the TC. This is
177 // a common need for extensions.
178 struct CallerFrame
: public VMRegAnchor
{
179 template<class... Args
>
180 ActRec
* operator()(Args
&&... args
) {
181 return regAnchorFP(std::forward
<Args
>(args
)...);
183 ActRec
* actRecForArgs() { return regAnchorFPForArgs(); }
186 #define SYNC_VM_REGS_SCOPED() \
187 HPHP::JIT::VMRegAnchor _anchorUnused