2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2016 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 +----------------------------------------------------------------------+
16 #ifndef incl_HPHP_SRCDB_H_
17 #define incl_HPHP_SRCDB_H_
22 #include "hphp/util/asm-x64.h"
23 #include "hphp/util/growable-vector.h"
24 #include "hphp/util/trace.h"
26 #include "hphp/runtime/vm/jit/stack-offsets.h"
27 #include "hphp/runtime/vm/jit/types.h"
28 #include "hphp/runtime/vm/srckey.h"
29 #include "hphp/runtime/vm/tread-hash-map.h"
31 namespace HPHP
{ namespace jit
{
32 ////////////////////////////////////////////////////////////////////////////////
35 struct RelocationInfo
;
38 * Incoming branches between different translations are tracked using
41 * This allows us to smash them later to point to different things.
42 * We handle conditional and unconditional jumps, as well as pointers
43 * to code (via IncomingBranch::ADDR, used for example in a switch
46 * We don't need to track which condition code a conditional jump used
47 * because we take care to smash only the address and leave the code
50 struct IncomingBranch
{
57 using Opaque
= CompactTaggedPtr
<void>::Opaque
;
59 static IncomingBranch
jmpFrom(TCA from
) {
60 return IncomingBranch(Tag::JMP
, from
);
62 static IncomingBranch
jccFrom(TCA from
) {
63 return IncomingBranch(Tag::JCC
, from
);
65 static IncomingBranch
addr(TCA
* from
) {
66 return IncomingBranch(Tag::ADDR
, TCA(from
));
69 Opaque
getOpaque() const {
70 return m_ptr
.getOpaque();
72 explicit IncomingBranch(CompactTaggedPtr
<void>::Opaque v
) : m_ptr(v
) {}
74 Tag
type() const { return m_ptr
.tag(); }
75 TCA
toSmash() const { return TCA(m_ptr
.ptr()); }
76 void relocate(RelocationInfo
& rel
);
77 void adjust(TCA addr
) {
78 m_ptr
.set(m_ptr
.tag(), addr
);
83 explicit IncomingBranch(Tag type
, TCA toSmash
) {
84 m_ptr
.set(type
, toSmash
);
87 /* needed to allow IncomingBranch to be put in a GrowableVector */
88 friend struct GrowableVector
<IncomingBranch
>;
91 CompactTaggedPtr
<void,Tag
> m_ptr
;
95 * TransLoc: the location of a translation in the TC
97 * All offsets are stored relative to the start of the TC, and the sizes of the
98 * cold and frozen regions are encoded in the first four bytes of their
102 void setMainStart(TCA newStart
);
103 void setColdStart(TCA newStart
);
104 void setFrozenStart(TCA newFrozen
);
106 void setMainSize(size_t size
) {
107 assert(size
< std::numeric_limits
<uint32_t>::max());
108 m_mainLen
= (uint32_t)size
;
111 bool contains(TCA loc
) {
112 return (mainStart() <= loc
&& loc
< mainEnd()) ||
113 (coldStart() <= loc
&& loc
< coldEnd()) ||
114 (frozenStart() <= loc
&& loc
< frozenEnd());
117 TCA
mainStart() const;
118 TCA
coldStart() const;
119 TCA
frozenStart() const;
121 TCA
coldCodeStart() const { return coldStart() + sizeof(uint32_t); }
122 TCA
frozenCodeStart() const { return frozenStart() + sizeof(uint32_t); }
124 uint32_t coldCodeSize() const { return coldSize() - sizeof(uint32_t); }
125 uint32_t frozenCodeSize() const { return frozenSize() - sizeof(uint32_t); }
127 TCA
mainEnd() const { return mainStart() + m_mainLen
; }
128 TCA
coldEnd() const { return coldStart() + coldSize(); }
129 TCA
frozenEnd() const { return frozenStart() + frozenSize(); }
131 uint32_t mainSize() const { return m_mainLen
; }
132 uint32_t coldSize() const { return *(uint32_t*)coldStart(); }
133 uint32_t frozenSize() const { return *(uint32_t*)frozenStart(); }
136 return m_mainOff
== kDefaultOff
&& m_mainLen
== 0 &&
137 m_coldOff
== kDefaultOff
&& m_frozenOff
== kDefaultOff
;
141 static auto constexpr kDefaultOff
= std::numeric_limits
<uint32_t>::max();
143 uint32_t m_mainOff
{kDefaultOff
};
144 uint32_t m_mainLen
{0};
146 uint32_t m_coldOff
{kDefaultOff
};
147 uint32_t m_frozenOff
{kDefaultOff
};
150 // Prevent unintentional growth of the SrcDB
151 static_assert(sizeof(TransLoc
) == 16, "Don't add fields to TransLoc");
154 * SrcRec: record of translator output for a given source location.
158 : m_topTranslation(nullptr)
159 , m_anchorTranslation(nullptr)
160 , m_dbgBranchGuardSrc(nullptr)
165 * The top translation is our first target, a translation whose type
166 * checks properly chain through all other translations. Usually this will
167 * be the first translation.
169 * This function can be safely called without holding the write
172 TCA
getTopTranslation() const {
173 return m_topTranslation
.get();
177 * The following functions are used during creation of new
178 * translations or when inserting debug guards. May only be called
179 * when holding the translator write lease.
181 void setFuncInfo(const Func
* f
);
182 void chainFrom(IncomingBranch br
);
183 TCA
getFallbackTranslation() const;
184 void newTranslation(TransLoc newStart
,
185 GrowableVector
<IncomingBranch
>& inProgressTailBranches
);
186 void replaceOldTranslations();
187 void addDebuggerGuard(TCA dbgGuard
, TCA m_dbgBranchGuardSrc
);
188 bool hasDebuggerGuard() const { return m_dbgBranchGuardSrc
!= nullptr; }
189 const MD5
& unitMd5() const { return m_unitMd5
; }
191 const GrowableVector
<TransLoc
>& translations() const {
192 return m_translations
;
195 const GrowableVector
<IncomingBranch
>& tailFallbackJumps() {
196 return m_tailFallbackJumps
;
200 * The anchor translation is a retranslate request for the current
201 * SrcKey that will continue the tracelet chain.
203 void setAnchorTranslation(TCA anc
) {
204 assertx(!m_anchorTranslation
);
205 assertx(m_tailFallbackJumps
.empty());
206 m_anchorTranslation
= anc
;
210 * Returns the VM stack offset the translations in the SrcRec have, in
211 * situations where we need to and can know.
213 * Pre: this SrcRec is for a non-resumed SrcKey
214 * Pre: setAnchorTranslation has been called
216 FPInvOffset
nonResumedSPOff() const;
218 const GrowableVector
<IncomingBranch
>& incomingBranches() const {
219 return m_incomingBranches
;
222 void relocate(RelocationInfo
& rel
);
224 void removeIncomingBranch(TCA toSmash
);
227 * There is an unlikely race in retranslate, where two threads
228 * could simultaneously generate the same translation for a
229 * tracelet. In practice it's almost impossible to hit this, unless
230 * Eval.JitRequireWriteLease is set. But when it is set, we hit
232 * m_guard doesn't quite solve it, but its as good as things were
237 return m_guard
.compare_exchange_strong(val
, 1);
245 void patchIncomingBranches(TCA newStart
);
248 // This either points to the most recent translation in the
249 // translations vector, or if hasDebuggerGuard() it points to the
251 AtomicLowTCA m_topTranslation
;
254 * The following members are all protected by the translator write
255 * lease. They can only be read when the lease is held.
258 // We chain new translations onto the end of the list, so we need to
259 // track all the fallback jumps from the "tail" translation so we
260 // can rewrire them to new ones.
261 LowTCA m_anchorTranslation
;
262 GrowableVector
<IncomingBranch
> m_tailFallbackJumps
;
264 GrowableVector
<TransLoc
> m_translations
;
265 GrowableVector
<IncomingBranch
> m_incomingBranches
;
267 // The branch src for the debug guard, if this has one.
268 LowTCA m_dbgBranchGuardSrc
;
269 std::atomic
<uint32_t> m_guard
;
274 * Although it seems tempting, in an experiment, trying to stash the top TCA
275 * in place in the hashtable did worse than dereferencing a SrcRec* to get it.
276 * Maybe could be possible with a better hash function or lower max load
277 * factor. (See D450383.)
279 using THM
= TreadHashMap
<SrcKey::AtomicInt
, SrcRec
*, int64_hash
>;
280 using iterator
= THM::iterator
;
281 using const_iterator
= THM::const_iterator
;
283 //////////////////////////////////////////////////////////////////////////////
287 SrcDB(const SrcDB
&) = delete;
288 SrcDB
& operator=(const SrcDB
&) = delete;
290 //////////////////////////////////////////////////////////////////////////////
292 iterator
begin() { return m_map
.begin(); }
293 iterator
end() { return m_map
.end(); }
294 const_iterator
begin() const { return m_map
.begin(); }
295 const_iterator
end() const { return m_map
.end(); }
297 //////////////////////////////////////////////////////////////////////////////
299 SrcRec
* find(SrcKey sk
) const {
300 auto const p
= m_map
.find(sk
.toAtomicInt());
304 SrcRec
* insert(SrcKey sk
) {
305 return *m_map
.insert(sk
.toAtomicInt(), new SrcRec
);
312 ////////////////////////////////////////////////////////////////////////////////