|
14 | 14 | +----------------------------------------------------------------------+ |
15 | 15 | */ |
16 | 16 |
|
| 17 | +#include <cstdint> |
| 18 | +#include <unwind.h> |
| 19 | + |
17 | 20 | #include "hphp/runtime/vm/jit/fixup.h" |
18 | 21 |
|
19 | 22 | #include "hphp/runtime/base/stats.h" |
|
22 | 25 | #include "hphp/runtime/vm/jit/tc.h" |
23 | 26 |
|
24 | 27 | #include "hphp/util/configs/jit.h" |
| 28 | +#include "hphp/util/dwarf-reg.h" |
25 | 29 |
|
26 | 30 | TRACE_SET_MOD(fixup) |
27 | 31 |
|
@@ -181,49 +185,50 @@ bool processFixupForVMFrame(VMFrame frame) { |
181 | 185 | return true; |
182 | 186 | } |
183 | 187 |
|
184 | | -bool fixupWork(ActRec* nextRbp, bool soft) { |
185 | | - assertx(Cfg::Jit::Enabled); |
186 | | - |
187 | | - TRACE(1, "fixup(begin):\n"); |
188 | | - |
189 | | - while (true) { |
190 | | - auto const rbp = nextRbp; |
191 | | - nextRbp = rbp->m_sfp; |
192 | | - |
193 | | - if (UNLIKELY(soft) && (!nextRbp || nextRbp == rbp)) return false; |
194 | | - assertx(nextRbp && nextRbp != rbp && "Missing fixup for native call"); |
| 188 | +//////////////////////////////////////////////////////////////////////////////// |
| 189 | +} |
195 | 190 |
|
196 | | - TRACE(2, "considering frame %p, %p\n", rbp, (void*)rbp->m_savedRip); |
| 191 | +namespace detail { |
| 192 | +struct FixupWorkState { |
| 193 | + bool soft; |
| 194 | + bool synced; |
| 195 | +}; |
197 | 196 |
|
198 | | - if (isVMFrame(nextRbp, soft)) { |
199 | | - TRACE(2, "fixup checking vm frame %s\n", |
200 | | - nextRbp->func()->name()->data()); |
201 | | - auto const cfa = uintptr_t(rbp) + kNativeFrameSize; |
202 | | - auto const frame = VMFrame{nextRbp, TCA(rbp->m_savedRip), cfa}; |
203 | | - auto const res = processFixupForVMFrame(frame); |
204 | | - if (res || LIKELY(soft)) return res; |
| 197 | +/* |
| 198 | + * Perform a fixup of the VM registers for the current stack. |
| 199 | + */ |
| 200 | +_Unwind_Reason_Code fixupWork(_Unwind_Context* context, void* arg) { |
| 201 | + auto state = static_cast<FixupWorkState*>(arg); |
| 202 | + auto const fp = reinterpret_cast<ActRec*>(_Unwind_GetGR(context, dw_reg::FP)); |
| 203 | + |
| 204 | + TRACE(2, "considering frame %p, %p\n", fp, (void*)fp->m_savedRip); |
| 205 | + |
| 206 | + if (isVMFrame(fp, state->soft)) { |
| 207 | + const uintptr_t cfa = _Unwind_GetCFA(context); |
| 208 | + const uintptr_t rip = _Unwind_GetIP(context); |
| 209 | + auto frame = VMFrame{fp, TCA(rip), cfa}; |
| 210 | + state->synced = FixupMap::processFixupForVMFrame(frame); |
| 211 | + if (state->synced || LIKELY(state->soft)) { |
| 212 | + return _URC_END_OF_STACK; |
| 213 | + } |
205 | 214 | always_assert(false && "Fixup expected for leafmost VM frame"); |
206 | | - } |
207 | 215 | } |
208 | | - return false; |
| 216 | + return _URC_NO_REASON; |
209 | 217 | } |
210 | 218 |
|
211 | | -//////////////////////////////////////////////////////////////////////////////// |
212 | | -} |
213 | | - |
214 | | -namespace detail { |
215 | 219 | void syncVMRegsWork(bool soft) { |
| 220 | + assertx(Cfg::Jit::Enabled); |
| 221 | + |
| 222 | + TRACE(1, "fixup(begin):\n"); |
| 223 | + |
216 | 224 | // Start looking for fixup entries at the current (C++) frame. This |
217 | 225 | // will walk the frames upward until we find a TC frame. |
218 | | - DECLARE_FRAME_POINTER(framePtr); |
219 | | - auto fp = regState() >= VMRegState::GUARDED_THRESHOLD ? |
220 | | - (ActRec*)regState() : framePtr; |
| 226 | + FixupWorkState state{soft, false}; |
| 227 | + _Unwind_Backtrace(fixupWork, &state); |
221 | 228 |
|
222 | | - // TODO(mcolavita): This is incorrect for C++ routines with padding after |
223 | | - // their CFA. |
224 | | - auto const synced = FixupMap::fixupWork(fp, soft); |
| 229 | + assertx((state.synced || state.soft) && "Missing fixup for native call"); |
225 | 230 |
|
226 | | - if (synced) regState() = VMRegState::CLEAN; |
| 231 | + if (state.synced) regState() = VMRegState::CLEAN; |
227 | 232 | Stats::inc(Stats::TC_Sync); |
228 | 233 | } |
229 | 234 | } |
|
0 commit comments