Async tail-call optimization v1
[hiphop-php.git] / hphp / runtime / base / backtrace-inl.h
blobe019f767e1ce352daeef13a6bfed8f8d188cde4e
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
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 +----------------------------------------------------------------------+
17 #ifndef incl_HPHP_BACKTRACE_INL_H_
18 #error "backtrace-inl.h should only be included by backtrace.h"
19 #endif
21 #include "hphp/runtime/base/array-data.h"
22 #include "hphp/runtime/base/rds-header.h"
23 #include "hphp/runtime/base/types.h"
24 #include "hphp/runtime/vm/act-rec.h"
25 #include "hphp/runtime/vm/vm-regs.h"
27 #include "hphp/runtime/vm/jit/types.h"
29 #include <folly/small_vector.h>
31 namespace HPHP {
33 ///////////////////////////////////////////////////////////////////////////////
35 struct c_WaitableWaitHandle;
37 ///////////////////////////////////////////////////////////////////////////////
39 namespace backtrace_detail {
41 struct BTContext {
42 BTContext();
44 BTContext(const BTContext&) = delete;
45 BTContext(BTContext&&) = delete;
46 BTContext& operator=(const BTContext&) = delete;
47 BTContext& operator=(BTContext&&) = delete;
49 const ActRec* clone(const BTContext& src, const ActRec* fp);
51 bool hasInlFrames{false};
53 // To handle awaits in tail-position, we can reuse AsyncFunctionWaitHandle
54 // and stuff just enough tail-frame info into them to support backtracing.
55 // This field is set when iterating over these tail frames.
56 uint8_t afwhTailFrameIndex{0};
58 // fakeAR is used to generate pseudo-frames representing inlined functions
59 // whose frames have been elided. The array operates like a ring buffer as
60 // createBacktrace needs to inspect the current and previous frame pointer,
61 // thus we introduce an m_sfp cycle between these frames.
62 ActRec fakeAR[2];
63 IStack inlineStack;
64 IFrameID prevIFID{kInvalidIFrameID};
66 // The frame we should resume at after unwinding the inlined stack.
67 BTFrame stashedFrm{};
70 BTFrame getPrevActRec(
71 BTContext& ctx, BTFrame frm,
72 folly::small_vector<c_WaitableWaitHandle*, 64>& visitedWHs
76 * Take a `frm` cursor and perform miscellaneous preprocessing on it.
78 * Preprocessing includes:
79 * - Setting up virtual inline stack frames.
80 * - Setting up virtual FCallBuiltin inline frames.
81 * - Coalescing kInvalidOffset `pc` values to `pcOff()`.
83 BTFrame initBTContextAt(BTContext& ctx, jit::CTCA ip, BTFrame frm);
87 template<class L>
88 void walkStack(L func, c_WaitableWaitHandle* wh, bool skipTop) {
89 using namespace backtrace_detail;
91 VMRegAnchor _;
93 folly::small_vector<c_WaitableWaitHandle*, 64> visitedWHs;
95 auto frm = wh != nullptr
96 ? getARFromWH(wh, visitedWHs)
97 : BTFrame { vmfp() };
99 // If there are no VM frames, we're done.
100 if (!frm || !rds::header()) return;
102 BTContext ctx;
104 frm = initBTContextAt(ctx, vmJitReturnAddr(), frm);
106 if (skipTop) frm = getPrevActRec(ctx, frm, visitedWHs);
108 for (; frm; frm = getPrevActRec(ctx, frm, visitedWHs)) {
109 if (ArrayData::call_helper(func, frm.fp, frm.pc)) return;
113 template<class L>
114 void walkStack(L func, bool skipTop) {
115 walkStack(func, nullptr, skipTop);
118 namespace backtrace_detail {
120 template<typename F, typename Pred>
121 from_ret_t<F> fromLeafImpl(F f, Pred pred,
122 from_ret_t<F> def,
123 c_WaitableWaitHandle* wh,
124 bool skipTop) {
125 auto ret = def;
126 walkStack([&] (const ActRec* fp, Offset off) {
127 if (!pred(fp)) return false;
128 ret = f(fp, off);
129 return true;
130 }, wh, skipTop);
131 return ret;
134 inline bool true_pred(const ActRec* fp) { return true; }
138 template<typename F>
139 backtrace_detail::from_ret_t<F> fromLeaf(
140 F f, backtrace_detail::from_ret_t<F> def
142 return backtrace_detail::fromLeafImpl(
143 f, backtrace_detail::true_pred, def, nullptr, false
147 template<typename F>
148 backtrace_detail::from_ret_t<F> fromCaller(
149 F f, backtrace_detail::from_ret_t<F> def
151 return backtrace_detail::fromLeafImpl(
152 f, backtrace_detail::true_pred, def, nullptr, true
156 template<typename F>
157 backtrace_detail::from_ret_t<F> fromLeafWH(
158 c_WaitableWaitHandle* wh, F f,
159 backtrace_detail::from_ret_t<F> def
161 return backtrace_detail::fromLeafImpl(
162 f, backtrace_detail::true_pred, def, wh, false
166 template<typename F, typename Pred>
167 backtrace_detail::from_ret_t<F> fromLeaf(
168 F f, Pred pred, backtrace_detail::from_ret_t<F> def
170 return backtrace_detail::fromLeafImpl(f, pred, def, nullptr, false);
173 template<typename F, typename Pred>
174 backtrace_detail::from_ret_t<F> fromCaller(
175 F f, Pred pred, backtrace_detail::from_ret_t<F> def
177 return backtrace_detail::fromLeafImpl(f, pred, def, nullptr, true);
180 template<typename F, typename Pred>
181 backtrace_detail::from_ret_t<F> fromLeafWH(
182 c_WaitableWaitHandle* wh, F f, Pred pred,
183 backtrace_detail::from_ret_t<F> def
185 return backtrace_detail::fromLeafImpl(f, pred, def, wh, false);
188 ///////////////////////////////////////////////////////////////////////////////