PageRenderTime 44ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/hphp/runtime/vm/jit/srcdb.h

https://gitlab.com/Blueprint-Marketing/hhvm
C Header | 324 lines | 203 code | 38 blank | 83 comment | 4 complexity | 37763f0ed6fcb47a7dc1a0eab2108a6b MD5 | raw file
  1. /*
  2. +----------------------------------------------------------------------+
  3. | HipHop for PHP |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 2010-2014 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. +----------------------------------------------------------------------+
  15. */
  16. #ifndef incl_HPHP_SRCDB_H_
  17. #define incl_HPHP_SRCDB_H_
  18. #include <boost/noncopyable.hpp>
  19. #include <algorithm>
  20. #include <atomic>
  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/stack-offsets.h"
  25. #include "hphp/runtime/vm/jit/types.h"
  26. #include "hphp/runtime/vm/srckey.h"
  27. #include "hphp/runtime/vm/tread-hash-map.h"
  28. namespace HPHP { namespace jit {
  29. struct CodeGenFixups;
  30. struct RelocationInfo;
  31. template<typename T>
  32. struct GrowableVector {
  33. GrowableVector() {}
  34. GrowableVector(GrowableVector&& other) noexcept : m_vec(other.m_vec) {
  35. other.m_vec = nullptr;
  36. }
  37. GrowableVector& operator=(GrowableVector&& other) {
  38. m_vec = other.m_vec;
  39. other.m_vec = nullptr;
  40. return *this;
  41. }
  42. GrowableVector(const GrowableVector&) = delete;
  43. GrowableVector& operator=(const GrowableVector&) = delete;
  44. size_t size() const {
  45. return m_vec ? m_vec->m_size : 0;
  46. }
  47. T& operator[](const size_t idx) {
  48. assertx(idx < size());
  49. return m_vec->m_data[idx];
  50. }
  51. const T& operator[](const size_t idx) const {
  52. assertx(idx < size());
  53. return m_vec->m_data[idx];
  54. }
  55. void push_back(const T& datum) {
  56. if (!m_vec) {
  57. m_vec = Impl::make();
  58. }
  59. m_vec = m_vec->push_back(datum);
  60. }
  61. void swap(GrowableVector<T>& other) {
  62. std::swap(m_vec, other.m_vec);
  63. }
  64. void clear() {
  65. free(m_vec);
  66. m_vec = nullptr;
  67. }
  68. bool empty() const {
  69. return !m_vec;
  70. }
  71. T* begin() const { return m_vec ? m_vec->m_data : (T*)this; }
  72. T* end() const { return m_vec ? &m_vec->m_data[m_vec->m_size] : (T*)this; }
  73. private:
  74. struct Impl {
  75. uint32_t m_size;
  76. T m_data[1]; // Actually variable length
  77. Impl() : m_size(0) { }
  78. static Impl* make() {
  79. static_assert(std::is_trivially_destructible<T>::value,
  80. "GrowableVector can only hold trivially "
  81. "destructible types");
  82. auto mem = malloc(sizeof(Impl));
  83. return new (mem) Impl;
  84. }
  85. Impl* push_back(const T& datum) {
  86. Impl* gv;
  87. // m_data always has room for at least one element due to the m_data[1]
  88. // declaration, so the realloc() code first has to kick in when a second
  89. // element is about to be pushed.
  90. if (folly::isPowTwo(m_size)) {
  91. gv = (Impl*)realloc(this,
  92. offsetof(Impl, m_data) + 2 * m_size * sizeof(T));
  93. } else {
  94. gv = this;
  95. }
  96. gv->m_data[gv->m_size++] = datum;
  97. return gv;
  98. }
  99. };
  100. Impl* m_vec{nullptr};
  101. };
  102. /*
  103. * Incoming branches between different translations are tracked using
  104. * this structure.
  105. *
  106. * This allows us to smash them later to point to different things.
  107. * We handle conditional and unconditional jumps, as well as pointers
  108. * to code (via IncomingBranch::ADDR, used for example in a switch
  109. * table).
  110. *
  111. * We don't need to track which condition code a conditional jump used
  112. * because we take care to smash only the address and leave the code
  113. * intact.
  114. */
  115. struct IncomingBranch {
  116. enum class Tag {
  117. JMP,
  118. JCC,
  119. ADDR,
  120. };
  121. using Opaque = CompactTaggedPtr<void>::Opaque;
  122. static IncomingBranch jmpFrom(TCA from) {
  123. return IncomingBranch(Tag::JMP, from);
  124. }
  125. static IncomingBranch jccFrom(TCA from) {
  126. return IncomingBranch(Tag::JCC, from);
  127. }
  128. static IncomingBranch addr(TCA* from) {
  129. return IncomingBranch(Tag::ADDR, TCA(from));
  130. }
  131. Opaque getOpaque() const {
  132. return m_ptr.getOpaque();
  133. }
  134. explicit IncomingBranch(CompactTaggedPtr<void>::Opaque v) : m_ptr(v) {}
  135. Tag type() const { return m_ptr.tag(); }
  136. TCA toSmash() const { return TCA(m_ptr.ptr()); }
  137. void relocate(RelocationInfo& rel);
  138. void adjust(TCA addr) {
  139. m_ptr.set(m_ptr.tag(), addr);
  140. }
  141. void patch(TCA dest);
  142. TCA target() const;
  143. private:
  144. explicit IncomingBranch(Tag type, TCA toSmash) {
  145. m_ptr.set(type, toSmash);
  146. }
  147. /* needed to allow IncomingBranch to be put in a GrowableVector */
  148. friend class GrowableVector<IncomingBranch>;
  149. IncomingBranch() {}
  150. CompactTaggedPtr<void,Tag> m_ptr;
  151. };
  152. /*
  153. * SrcRec: record of translator output for a given source location.
  154. */
  155. struct SrcRec {
  156. SrcRec()
  157. : m_topTranslation(nullptr)
  158. , m_anchorTranslation(0)
  159. , m_dbgBranchGuardSrc(nullptr)
  160. , m_guard(0)
  161. {}
  162. /*
  163. * The top translation is our first target, a translation whose type
  164. * checks properly chain through all other translations. Usually this will
  165. * be the first translation.
  166. *
  167. * This function can be safely called without holding the write
  168. * lease.
  169. */
  170. TCA getTopTranslation() const {
  171. return m_topTranslation.load(std::memory_order_acquire);
  172. }
  173. /*
  174. * The following functions are used during creation of new
  175. * translations or when inserting debug guards. May only be called
  176. * when holding the translator write lease.
  177. */
  178. void setFuncInfo(const Func* f);
  179. void chainFrom(IncomingBranch br);
  180. void emitFallbackJump(CodeBlock& cb, ConditionCode cc = CC_None);
  181. void registerFallbackJump(TCA from, ConditionCode cc = CC_None);
  182. void emitFallbackJumpCustom(CodeBlock& cb,
  183. CodeBlock& frozen,
  184. SrcKey sk,
  185. TransFlags trflags,
  186. ConditionCode cc = CC_None);
  187. TCA getFallbackTranslation() const;
  188. void newTranslation(TCA newStart,
  189. GrowableVector<IncomingBranch>& inProgressTailBranches);
  190. void replaceOldTranslations();
  191. void addDebuggerGuard(TCA dbgGuard, TCA m_dbgBranchGuardSrc);
  192. bool hasDebuggerGuard() const { return m_dbgBranchGuardSrc != nullptr; }
  193. const MD5& unitMd5() const { return m_unitMd5; }
  194. const GrowableVector<TCA>& translations() const {
  195. return m_translations;
  196. }
  197. const GrowableVector<IncomingBranch>& tailFallbackJumps() {
  198. return m_tailFallbackJumps;
  199. }
  200. /*
  201. * The anchor translation is a retranslate request for the current
  202. * SrcKey that will continue the tracelet chain.
  203. */
  204. void setAnchorTranslation(TCA anc) {
  205. assertx(!m_anchorTranslation);
  206. assertx(m_tailFallbackJumps.empty());
  207. m_anchorTranslation = anc;
  208. }
  209. /*
  210. * Returns the VM stack offset the translations in the SrcRec have, in
  211. * situations where we need to and can know.
  212. *
  213. * Pre: this SrcRec is for a non-resumed SrcKey
  214. * Pre: setAnchorTranslation has been called
  215. */
  216. FPInvOffset nonResumedSPOff() const;
  217. const GrowableVector<IncomingBranch>& incomingBranches() const {
  218. return m_incomingBranches;
  219. }
  220. void relocate(RelocationInfo& rel);
  221. /*
  222. * There is an unlikely race in retranslate, where two threads
  223. * could simultaneously generate the same translation for a
  224. * tracelet. In practice its almost impossible to hit this, unless
  225. * Eval.JitRequireWriteLease is set. But when it is set, we hit
  226. * it a lot.
  227. * m_guard doesn't quite solve it, but its as good as things were
  228. * before.
  229. */
  230. bool tryLock() {
  231. uint32_t val = 0;
  232. return m_guard.compare_exchange_strong(val, 1);
  233. }
  234. void freeLock() {
  235. m_guard = 0;
  236. }
  237. private:
  238. void patchIncomingBranches(TCA newStart);
  239. private:
  240. // This either points to the most recent translation in the
  241. // translations vector, or if hasDebuggerGuard() it points to the
  242. // debug guard.
  243. std::atomic<TCA> m_topTranslation;
  244. /*
  245. * The following members are all protected by the translator write
  246. * lease. They can only be read when the lease is held.
  247. */
  248. // We chain new translations onto the end of the list, so we need to
  249. // track all the fallback jumps from the "tail" translation so we
  250. // can rewrire them to new ones.
  251. TCA m_anchorTranslation;
  252. GrowableVector<IncomingBranch> m_tailFallbackJumps;
  253. GrowableVector<TCA> m_translations;
  254. GrowableVector<IncomingBranch> m_incomingBranches;
  255. MD5 m_unitMd5;
  256. // The branch src for the debug guard, if this has one.
  257. TCA m_dbgBranchGuardSrc;
  258. std::atomic<uint32_t> m_guard;
  259. };
  260. class SrcDB : boost::noncopyable {
  261. // Although it seems tempting, in an experiment, trying to stash the
  262. // top TCA in place in the hashtable did worse than dereferencing a
  263. // SrcRec* to get it. Maybe could be possible with a better hash
  264. // function or lower max load factor. (See D450383.)
  265. typedef TreadHashMap<SrcKey::AtomicInt,SrcRec*,int64_hash> THM;
  266. THM m_map;
  267. public:
  268. explicit SrcDB()
  269. : m_map(1024)
  270. {}
  271. typedef THM::iterator iterator;
  272. typedef THM::const_iterator const_iterator;
  273. iterator begin() { return m_map.begin(); }
  274. iterator end() { return m_map.end(); }
  275. const_iterator begin() const { return m_map.begin(); }
  276. const_iterator end() const { return m_map.end(); }
  277. SrcRec* find(SrcKey sk) const {
  278. SrcRec* const* p = m_map.find(sk.toAtomicInt());
  279. return p ? *p : 0;
  280. }
  281. SrcRec* insert(SrcKey sk) {
  282. return *m_map.insert(sk.toAtomicInt(), new SrcRec);
  283. }
  284. };
  285. } }
  286. #endif