Move some JIT data members to more appropriate places
[hiphop-php.git] / hphp / runtime / vm / jit / srcdb.h
blob1a6497dead9d1e56a3e6235cf916be8ff64f2178
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
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_
19 #include <algorithm>
20 #include <atomic>
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 ////////////////////////////////////////////////////////////////////////////////
34 struct CGMeta;
35 struct RelocationInfo;
38 * Incoming branches between different translations are tracked using
39 * this structure.
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
44 * table).
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
48 * intact.
50 struct IncomingBranch {
51 enum class Tag {
52 JMP,
53 JCC,
54 ADDR,
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);
80 void patch(TCA dest);
81 TCA target() const;
82 private:
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>;
89 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
99 * respective regions.
101 struct TransLoc {
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(); }
135 bool empty() const {
136 return m_mainOff == kDefaultOff && m_mainLen == 0 &&
137 m_coldOff == kDefaultOff && m_frozenOff == kDefaultOff;
140 private:
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.
156 struct SrcRec {
157 SrcRec()
158 : m_topTranslation(nullptr)
159 , m_anchorTranslation(nullptr)
160 , m_dbgBranchGuardSrc(nullptr)
161 , m_guard(0)
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
170 * lease.
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
231 * it a lot.
232 * m_guard doesn't quite solve it, but its as good as things were
233 * before.
235 bool tryLock() {
236 uint32_t val = 0;
237 return m_guard.compare_exchange_strong(val, 1);
240 void freeLock() {
241 m_guard = 0;
244 private:
245 void patchIncomingBranches(TCA newStart);
247 private:
248 // This either points to the most recent translation in the
249 // translations vector, or if hasDebuggerGuard() it points to the
250 // debug guard.
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;
266 MD5 m_unitMd5;
267 // The branch src for the debug guard, if this has one.
268 LowTCA m_dbgBranchGuardSrc;
269 std::atomic<uint32_t> m_guard;
272 struct SrcDB {
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 //////////////////////////////////////////////////////////////////////////////
285 explicit SrcDB() {}
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());
301 return p ? *p : 0;
304 SrcRec* insert(SrcKey sk) {
305 return *m_map.insert(sk.toAtomicInt(), new SrcRec);
308 private:
309 THM m_map{1024};
312 ////////////////////////////////////////////////////////////////////////////////
315 #endif