2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2013 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 <boost/noncopyable.hpp>
21 #include "hphp/util/asm-x64.h"
22 #include "hphp/util/trace.h"
23 #include "hphp/util/mutex.h"
24 #include "hphp/runtime/vm/jit/types.h"
25 #include "hphp/runtime/vm/srckey.h"
26 #include "hphp/runtime/vm/tread_hash_map.h"
32 * Incoming branches between different translations are tracked using
35 * This allows us to smash them later to point to different things.
36 * We handle conditional and unconditional jumps, as well as pointers
37 * to code (via IncomingBranch::ADDR, used for example in a switch
40 * We don't need to track which condition code a conditional jump used
41 * because we take care to smash only the address and leave the code
44 struct IncomingBranch
{
51 static IncomingBranch
jmpFrom(TCA from
) {
52 return IncomingBranch(Tag::JMP
, from
);
54 static IncomingBranch
jccFrom(TCA from
) {
55 return IncomingBranch(Tag::JCC
, from
);
57 static IncomingBranch
addr(TCA
* from
) {
58 return IncomingBranch(Tag::ADDR
, TCA(from
));
61 Tag
type() const { return m_type
; }
62 TCA
toSmash() const { return m_toSmash
; }
65 explicit IncomingBranch(Tag type
, TCA toSmash
)
75 * SrcRec: record of translator output for a given source location.
79 : m_topTranslation(nullptr)
80 , m_anchorTranslation(0)
81 , m_dbgBranchGuardSrc(nullptr)
85 * The top translation is our first target, a translation whose type
86 * checks properly chain through all other translations. Usually this will
87 * be the most recently created translation.
89 * This function can be safely called without holding the write
92 TCA
getTopTranslation() const {
93 return atomic_acquire_load(&m_topTranslation
);
97 * The following functions are used during creation of new
98 * translations or when inserting debug guards. May only be called
99 * when holding the translator write lease.
101 void setFuncInfo(const Func
* f
);
102 void chainFrom(IncomingBranch br
);
103 void emitFallbackJump(TCA from
, int cc
= -1);
104 void newTranslation(TCA newStart
);
105 void replaceOldTranslations();
106 void addDebuggerGuard(TCA dbgGuard
, TCA m_dbgBranchGuardSrc
);
107 bool hasDebuggerGuard() const { return m_dbgBranchGuardSrc
!= nullptr; }
108 const MD5
& unitMd5() const { return m_unitMd5
; }
110 const vector
<TCA
>& translations() const {
111 return m_translations
;
115 * The anchor translation is a retranslate request for the current
116 * SrcKey that will continue the tracelet chain.
118 void setAnchorTranslation(TCA anc
) {
119 assert(!m_anchorTranslation
);
120 assert(m_tailFallbackJumps
.empty());
121 m_anchorTranslation
= anc
;
124 const vector
<IncomingBranch
>& inProgressTailJumps() const {
125 return m_inProgressTailJumps
;
128 void clearInProgressTailJumps() {
129 m_inProgressTailJumps
.clear();
133 TCA
getFallbackTranslation() const;
134 void patch(IncomingBranch branch
, TCA dest
);
135 void patchIncomingBranches(TCA newStart
);
138 // This either points to the most recent translation in the
139 // translations vector, or if hasDebuggerGuard() it points to the
140 // debug guard. Read/write with atomic primitives only.
141 TCA m_topTranslation
;
144 * The following members are all protected by the translator write
145 * lease. They can only be read when the lease is held.
148 // We chain new translations onto the end of the list, so we need to
149 // track all the fallback jumps from the "tail" translation so we
150 // can rewrire them to new ones.
151 TCA m_anchorTranslation
;
152 vector
<IncomingBranch
> m_tailFallbackJumps
;
153 vector
<IncomingBranch
> m_inProgressTailJumps
;
155 vector
<TCA
> m_translations
;
156 vector
<IncomingBranch
> m_incomingBranches
;
158 // The branch src for the debug guard, if this has one.
159 TCA m_dbgBranchGuardSrc
;
165 * We make a large number of these, and they typically only have one entry.
166 * It's a shame to use a 24-byte std::vector for this.
168 * Only gets larger. Non-standard interface because we may realloc
169 * at push_back() time.
172 struct GrowableVector
{
174 T m_data
[1]; // Actually variable length
175 GrowableVector() : m_size(0) { }
176 size_t size() const {
179 T
& operator[](const size_t idx
) {
180 assert(idx
< m_size
);
183 const T
& operator[](const size_t idx
) const {
184 assert(idx
< m_size
);
187 GrowableVector
* push_back(const T
& datum
) {
189 // m_data always has room for at least one element due to the m_data[1]
190 // declaration, so the realloc() code first has to kick in when a second
191 // element is about to be pushed.
192 if (Util::isPowerOfTwo(m_size
)) {
193 gv
= (GrowableVector
*)realloc(this,
194 offsetof(GrowableVector
<T
>, m_data
) +
195 2 * m_size
* sizeof(T
));
199 gv
->m_data
[gv
->m_size
++] = datum
;
204 class SrcDB
: boost::noncopyable
{
205 // SrcKeys that depend on a particular file go here.
206 typedef hphp_hash_map
<const Eval::PhpFile
*,
207 GrowableVector
<SrcKey
>*,
208 pointer_hash
<Eval::PhpFile
> > FileDepMap
;
211 // Although it seems tempting, in an experiment, trying to stash the
212 // top TCA in place in the hashtable did worse than dereferencing a
213 // SrcRec* to get it. Maybe could be possible with a better hash
214 // function or lower max load factor. (See D450383.)
215 typedef TreadHashMap
<SrcKey::AtomicInt
,SrcRec
*,int64_hash
> THM
;
222 typedef THM::iterator iterator
;
223 typedef THM::const_iterator const_iterator
;
225 iterator
begin() { return m_map
.begin(); }
226 iterator
end() { return m_map
.end(); }
227 const_iterator
begin() const { return m_map
.begin(); }
228 const_iterator
end() const { return m_map
.end(); }
230 SrcRec
* find(const SrcKey
& sk
) const {
231 SrcRec
* const* p
= m_map
.find(sk
.toAtomicInt());
235 SrcRec
* insert(const SrcKey
& sk
) {
236 return *m_map
.insert(sk
.toAtomicInt(), new SrcRec
);
239 size_t invalidateCode(const Eval::PhpFile
* file
);