|
14 | 14 | +----------------------------------------------------------------------+ |
15 | 15 | */ |
16 | 16 |
|
| 17 | +#define UNW_LOCAL_ONLY |
| 18 | +#include <libunwind.h> |
| 19 | + |
17 | 20 | #include "hphp/runtime/vm/jit/fixup.h" |
18 | 21 |
|
19 | 22 | #include "hphp/runtime/base/stats.h" |
@@ -181,47 +184,78 @@ bool processFixupForVMFrame(VMFrame frame) { |
181 | 184 | return true; |
182 | 185 | } |
183 | 186 |
|
184 | | -bool fixupWork(ActRec* nextRbp, bool soft) { |
| 187 | +/* |
| 188 | + * Perform a fixup of the VM registers for the current stack. |
| 189 | + * |
| 190 | + * Returns whether we successfully performed the fixup. (We assert on failure |
| 191 | + * if `soft` is not set). |
| 192 | + */ |
| 193 | +bool fixupWork(bool soft) { |
185 | 194 | assertx(Cfg::Jit::Enabled); |
186 | 195 |
|
187 | 196 | TRACE(1, "fixup(begin):\n"); |
188 | 197 |
|
| 198 | + // Start looking for fixup entries at the current (C++) frame. This |
| 199 | + // will walk the frames upward until we find a TC frame. |
| 200 | + // Historically this walked the chain of frame pointers directly |
| 201 | + // and extrapolated the CFA for VM frames using a constant frame size, |
| 202 | + // but this was incorrect for C++ routines with padding after their CFA. |
| 203 | + ActRec* curFrame; |
| 204 | + |
| 205 | + unw_cursor_t cursor; |
| 206 | + unw_context_t uc; |
| 207 | + int err; |
| 208 | + |
| 209 | + err = unw_getcontext(&uc); |
| 210 | + assertx(err == 0); |
| 211 | + err = unw_init_local(&cursor, &uc); |
| 212 | + assertx(err == 0); |
| 213 | + |
| 214 | + unw_word_t fp, ip, cfa; |
| 215 | + |
189 | 216 | while (true) { |
190 | | - auto const rbp = nextRbp; |
191 | | - nextRbp = rbp->m_sfp; |
| 217 | + err = unw_step(&cursor); |
| 218 | + if (err <= 0) { |
| 219 | + assertx(err == 0); |
| 220 | + break; |
| 221 | + } |
| 222 | + |
| 223 | +#ifdef __aarch64__ |
| 224 | + // On aarch64, the FP is stored in x29 |
| 225 | + // and the CFA is the value of SP (x31) at the previous frame. |
| 226 | + unw_get_reg(&cursor, UNW_AARCH64_X29, &fp); |
| 227 | + unw_get_reg(&cursor, UNW_AARCH64_SP, &cfa); |
| 228 | +#else |
| 229 | +#endif |
192 | 230 |
|
193 | | - if (UNLIKELY(soft) && (!nextRbp || nextRbp == rbp)) return false; |
194 | | - assertx(nextRbp && nextRbp != rbp && "Missing fixup for native call"); |
| 231 | + auto const prevFrame = curFrame; |
| 232 | + curFrame = (ActRec*)fp; |
195 | 233 |
|
196 | | - TRACE(2, "considering frame %p, %p\n", rbp, (void*)rbp->m_savedRip); |
| 234 | + TRACE(2, "considering frame %p, %p\n", curFrame, (void*)prevFrame->m_savedRip); |
197 | 235 |
|
198 | | - if (isVMFrame(nextRbp, soft)) { |
| 236 | + if (prevFrame != nullptr && isVMFrame(curFrame, soft)) { |
199 | 237 | 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}; |
| 238 | + curFrame->func()->name()->data()); |
| 239 | + auto const frame = VMFrame{curFrame, TCA(prevFrame->m_savedRip), cfa}; |
203 | 240 | auto const res = processFixupForVMFrame(frame); |
204 | 241 | if (res || LIKELY(soft)) return res; |
205 | 242 | always_assert(false && "Fixup expected for leafmost VM frame"); |
206 | 243 | } |
207 | 244 | } |
208 | | - return false; |
| 245 | + |
| 246 | + if (UNLIKELY(soft)) { |
| 247 | + return false; |
| 248 | + } |
| 249 | + |
| 250 | + always_assert(false && "Missing fixup for native call"); |
209 | 251 | } |
210 | 252 |
|
211 | 253 | //////////////////////////////////////////////////////////////////////////////// |
212 | 254 | } |
213 | 255 |
|
214 | 256 | namespace detail { |
215 | 257 | void syncVMRegsWork(bool soft) { |
216 | | - // Start looking for fixup entries at the current (C++) frame. This |
217 | | - // 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; |
221 | | - |
222 | | - // TODO(mcolavita): This is incorrect for C++ routines with padding after |
223 | | - // their CFA. |
224 | | - auto const synced = FixupMap::fixupWork(fp, soft); |
| 258 | + auto const synced = FixupMap::fixupWork(soft); |
225 | 259 |
|
226 | 260 | if (synced) regState() = VMRegState::CLEAN; |
227 | 261 | Stats::inc(Stats::TC_Sync); |
|
0 commit comments