DFGGenerationInfo.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  1. /*
  2. * Copyright (C) 2011, 2013 Apple Inc. All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. * 1. Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * 2. Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. *
  13. * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
  14. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  15. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  16. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
  17. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  18. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  19. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  20. * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
  21. * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  22. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  23. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24. */
  25. #ifndef DFGGenerationInfo_h
  26. #define DFGGenerationInfo_h
  27. #if ENABLE(DFG_JIT)
  28. #include "DFGJITCompiler.h"
  29. #include "DFGMinifiedID.h"
  30. #include "DFGVariableEvent.h"
  31. #include "DFGVariableEventStream.h"
  32. #include "DataFormat.h"
  33. namespace JSC { namespace DFG {
  34. // === GenerationInfo ===
  35. //
  36. // This class is used to track the current status of a live values during code generation.
  37. // Can provide information as to whether a value is in machine registers, and if so which,
  38. // whether a value has been spilled to the RegsiterFile, and if so may be able to provide
  39. // details of the format in memory (all values are spilled in a boxed form, but we may be
  40. // able to track the type of box), and tracks how many outstanding uses of a value remain,
  41. // so that we know when the value is dead and the machine registers associated with it
  42. // may be released.
  43. class GenerationInfo {
  44. public:
  45. GenerationInfo()
  46. : m_node(0)
  47. , m_useCount(0)
  48. , m_registerFormat(DataFormatNone)
  49. , m_spillFormat(DataFormatNone)
  50. , m_canFill(false)
  51. , m_bornForOSR(false)
  52. , m_isConstant(false)
  53. {
  54. }
  55. void initConstant(Node* node, uint32_t useCount)
  56. {
  57. m_node = node;
  58. m_useCount = useCount;
  59. m_registerFormat = DataFormatNone;
  60. m_spillFormat = DataFormatNone;
  61. m_canFill = true;
  62. m_bornForOSR = false;
  63. m_isConstant = true;
  64. ASSERT(m_useCount);
  65. }
  66. void initInteger(Node* node, uint32_t useCount, GPRReg gpr)
  67. {
  68. m_node = node;
  69. m_useCount = useCount;
  70. m_registerFormat = DataFormatInteger;
  71. m_spillFormat = DataFormatNone;
  72. m_canFill = false;
  73. u.gpr = gpr;
  74. m_bornForOSR = false;
  75. m_isConstant = false;
  76. ASSERT(m_useCount);
  77. }
  78. #if USE(JSVALUE64)
  79. void initJSValue(Node* node, uint32_t useCount, GPRReg gpr, DataFormat format = DataFormatJS)
  80. {
  81. ASSERT(format & DataFormatJS);
  82. m_node = node;
  83. m_useCount = useCount;
  84. m_registerFormat = format;
  85. m_spillFormat = DataFormatNone;
  86. m_canFill = false;
  87. u.gpr = gpr;
  88. m_bornForOSR = false;
  89. m_isConstant = false;
  90. ASSERT(m_useCount);
  91. }
  92. #elif USE(JSVALUE32_64)
  93. void initJSValue(Node* node, uint32_t useCount, GPRReg tagGPR, GPRReg payloadGPR, DataFormat format = DataFormatJS)
  94. {
  95. ASSERT(format & DataFormatJS);
  96. m_node = node;
  97. m_useCount = useCount;
  98. m_registerFormat = format;
  99. m_spillFormat = DataFormatNone;
  100. m_canFill = false;
  101. u.v.tagGPR = tagGPR;
  102. u.v.payloadGPR = payloadGPR;
  103. m_bornForOSR = false;
  104. m_isConstant = false;
  105. ASSERT(m_useCount);
  106. }
  107. #endif
  108. void initCell(Node* node, uint32_t useCount, GPRReg gpr)
  109. {
  110. m_node = node;
  111. m_useCount = useCount;
  112. m_registerFormat = DataFormatCell;
  113. m_spillFormat = DataFormatNone;
  114. m_canFill = false;
  115. u.gpr = gpr;
  116. m_bornForOSR = false;
  117. m_isConstant = false;
  118. ASSERT(m_useCount);
  119. }
  120. void initBoolean(Node* node, uint32_t useCount, GPRReg gpr)
  121. {
  122. m_node = node;
  123. m_useCount = useCount;
  124. m_registerFormat = DataFormatBoolean;
  125. m_spillFormat = DataFormatNone;
  126. m_canFill = false;
  127. u.gpr = gpr;
  128. m_bornForOSR = false;
  129. m_isConstant = false;
  130. ASSERT(m_useCount);
  131. }
  132. void initDouble(Node* node, uint32_t useCount, FPRReg fpr)
  133. {
  134. ASSERT(fpr != InvalidFPRReg);
  135. m_node = node;
  136. m_useCount = useCount;
  137. m_registerFormat = DataFormatDouble;
  138. m_spillFormat = DataFormatNone;
  139. m_canFill = false;
  140. u.fpr = fpr;
  141. m_bornForOSR = false;
  142. m_isConstant = false;
  143. ASSERT(m_useCount);
  144. }
  145. void initStorage(Node* node, uint32_t useCount, GPRReg gpr)
  146. {
  147. m_node = node;
  148. m_useCount = useCount;
  149. m_registerFormat = DataFormatStorage;
  150. m_spillFormat = DataFormatNone;
  151. m_canFill = false;
  152. u.gpr = gpr;
  153. m_bornForOSR = false;
  154. m_isConstant = false;
  155. ASSERT(m_useCount);
  156. }
  157. // Get the node that produced this value.
  158. Node* node() { return m_node; }
  159. void noticeOSRBirth(VariableEventStream& stream, Node* node, VirtualRegister virtualRegister)
  160. {
  161. if (m_isConstant)
  162. return;
  163. if (m_node != node)
  164. return;
  165. if (!alive())
  166. return;
  167. if (m_bornForOSR)
  168. return;
  169. m_bornForOSR = true;
  170. if (m_registerFormat != DataFormatNone)
  171. appendFill(BirthToFill, stream);
  172. else if (m_spillFormat != DataFormatNone)
  173. appendSpill(BirthToSpill, stream, virtualRegister);
  174. }
  175. // Mark the value as having been used (decrement the useCount).
  176. // Returns true if this was the last use of the value, and any
  177. // associated machine registers may be freed.
  178. bool use(VariableEventStream& stream)
  179. {
  180. ASSERT(m_useCount);
  181. bool result = !--m_useCount;
  182. if (result && m_bornForOSR) {
  183. ASSERT(m_node);
  184. stream.appendAndLog(VariableEvent::death(MinifiedID(m_node)));
  185. }
  186. return result;
  187. }
  188. // Used to check the operands of operations to see if they are on
  189. // their last use; in some cases it may be safe to reuse the same
  190. // machine register for the result of the operation.
  191. bool canReuse()
  192. {
  193. ASSERT(m_useCount);
  194. return m_useCount == 1;
  195. }
  196. // Get the format of the value in machine registers (or 'none').
  197. DataFormat registerFormat() { return m_registerFormat; }
  198. // Get the format of the value as it is spilled in the JSStack (or 'none').
  199. DataFormat spillFormat() { return m_spillFormat; }
  200. bool isJSFormat(DataFormat expectedFormat)
  201. {
  202. return JSC::isJSFormat(registerFormat(), expectedFormat) || JSC::isJSFormat(spillFormat(), expectedFormat);
  203. }
  204. bool isJSInteger()
  205. {
  206. return isJSFormat(DataFormatJSInteger);
  207. }
  208. bool isJSDouble()
  209. {
  210. return isJSFormat(DataFormatJSDouble);
  211. }
  212. bool isJSCell()
  213. {
  214. return isJSFormat(DataFormatJSCell);
  215. }
  216. bool isJSBoolean()
  217. {
  218. return isJSFormat(DataFormatJSBoolean);
  219. }
  220. bool isUnknownJS()
  221. {
  222. return spillFormat() == DataFormatNone
  223. ? registerFormat() == DataFormatJS || registerFormat() == DataFormatNone
  224. : spillFormat() == DataFormatJS;
  225. }
  226. // Get the machine resister currently holding the value.
  227. #if USE(JSVALUE64)
  228. GPRReg gpr() { ASSERT(m_registerFormat && m_registerFormat != DataFormatDouble); return u.gpr; }
  229. FPRReg fpr() { ASSERT(m_registerFormat == DataFormatDouble); return u.fpr; }
  230. JSValueRegs jsValueRegs() { ASSERT(m_registerFormat & DataFormatJS); return JSValueRegs(u.gpr); }
  231. #elif USE(JSVALUE32_64)
  232. GPRReg gpr() { ASSERT(!(m_registerFormat & DataFormatJS) && m_registerFormat != DataFormatDouble); return u.gpr; }
  233. GPRReg tagGPR() { ASSERT(m_registerFormat & DataFormatJS); return u.v.tagGPR; }
  234. GPRReg payloadGPR() { ASSERT(m_registerFormat & DataFormatJS); return u.v.payloadGPR; }
  235. FPRReg fpr() { ASSERT(m_registerFormat == DataFormatDouble || m_registerFormat == DataFormatJSDouble); return u.fpr; }
  236. JSValueRegs jsValueRegs() { ASSERT(m_registerFormat & DataFormatJS); return JSValueRegs(u.v.tagGPR, u.v.payloadGPR); }
  237. #endif
  238. // Check whether a value needs spilling in order to free up any associated machine registers.
  239. bool needsSpill()
  240. {
  241. // This should only be called on values that are currently in a register.
  242. ASSERT(m_registerFormat != DataFormatNone);
  243. // Constants do not need spilling, nor do values that have already been
  244. // spilled to the JSStack.
  245. return !m_canFill;
  246. }
  247. // Called when a VirtualRegister is being spilled to the JSStack for the first time.
  248. void spill(VariableEventStream& stream, VirtualRegister virtualRegister, DataFormat spillFormat)
  249. {
  250. // We shouldn't be spill values that don't need spilling.
  251. ASSERT(!m_canFill);
  252. ASSERT(m_spillFormat == DataFormatNone);
  253. // We should only be spilling values that are currently in machine registers.
  254. ASSERT(m_registerFormat != DataFormatNone);
  255. m_registerFormat = DataFormatNone;
  256. m_spillFormat = spillFormat;
  257. m_canFill = true;
  258. if (m_bornForOSR)
  259. appendSpill(Spill, stream, virtualRegister);
  260. }
  261. // Called on values that don't need spilling (constants and values that have
  262. // already been spilled), to mark them as no longer being in machine registers.
  263. void setSpilled(VariableEventStream& stream, VirtualRegister virtualRegister)
  264. {
  265. // Should only be called on values that don't need spilling, and are currently in registers.
  266. ASSERT(m_canFill && m_registerFormat != DataFormatNone);
  267. m_registerFormat = DataFormatNone;
  268. if (m_bornForOSR)
  269. appendSpill(Spill, stream, virtualRegister);
  270. }
  271. void killSpilled()
  272. {
  273. m_spillFormat = DataFormatNone;
  274. m_canFill = false;
  275. }
  276. // Record that this value is filled into machine registers,
  277. // tracking which registers, and what format the value has.
  278. #if USE(JSVALUE64)
  279. void fillJSValue(VariableEventStream& stream, GPRReg gpr, DataFormat format = DataFormatJS)
  280. {
  281. ASSERT(format & DataFormatJS);
  282. m_registerFormat = format;
  283. u.gpr = gpr;
  284. if (m_bornForOSR)
  285. appendFill(Fill, stream);
  286. }
  287. #elif USE(JSVALUE32_64)
  288. void fillJSValue(VariableEventStream& stream, GPRReg tagGPR, GPRReg payloadGPR, DataFormat format = DataFormatJS)
  289. {
  290. ASSERT(format & DataFormatJS);
  291. m_registerFormat = format;
  292. u.v.tagGPR = tagGPR; // FIXME: for JSValues with known type (boolean, integer, cell etc.) no tagGPR is needed?
  293. u.v.payloadGPR = payloadGPR;
  294. if (m_bornForOSR)
  295. appendFill(Fill, stream);
  296. }
  297. void fillCell(VariableEventStream& stream, GPRReg gpr)
  298. {
  299. m_registerFormat = DataFormatCell;
  300. u.gpr = gpr;
  301. if (m_bornForOSR)
  302. appendFill(Fill, stream);
  303. }
  304. #endif
  305. void fillInteger(VariableEventStream& stream, GPRReg gpr)
  306. {
  307. m_registerFormat = DataFormatInteger;
  308. u.gpr = gpr;
  309. if (m_bornForOSR)
  310. appendFill(Fill, stream);
  311. }
  312. void fillBoolean(VariableEventStream& stream, GPRReg gpr)
  313. {
  314. m_registerFormat = DataFormatBoolean;
  315. u.gpr = gpr;
  316. if (m_bornForOSR)
  317. appendFill(Fill, stream);
  318. }
  319. void fillDouble(VariableEventStream& stream, FPRReg fpr)
  320. {
  321. ASSERT(fpr != InvalidFPRReg);
  322. m_registerFormat = DataFormatDouble;
  323. u.fpr = fpr;
  324. if (m_bornForOSR)
  325. appendFill(Fill, stream);
  326. }
  327. void fillStorage(VariableEventStream& stream, GPRReg gpr)
  328. {
  329. m_registerFormat = DataFormatStorage;
  330. u.gpr = gpr;
  331. if (m_bornForOSR)
  332. appendFill(Fill, stream);
  333. }
  334. bool alive()
  335. {
  336. return m_useCount;
  337. }
  338. private:
  339. void appendFill(VariableEventKind kind, VariableEventStream& stream)
  340. {
  341. ASSERT(m_bornForOSR);
  342. if (m_registerFormat == DataFormatDouble) {
  343. stream.appendAndLog(VariableEvent::fillFPR(kind, MinifiedID(m_node), u.fpr));
  344. return;
  345. }
  346. #if USE(JSVALUE32_64)
  347. if (m_registerFormat & DataFormatJS) {
  348. stream.appendAndLog(VariableEvent::fillPair(kind, MinifiedID(m_node), u.v.tagGPR, u.v.payloadGPR));
  349. return;
  350. }
  351. #endif
  352. stream.appendAndLog(VariableEvent::fillGPR(kind, MinifiedID(m_node), u.gpr, m_registerFormat));
  353. }
  354. void appendSpill(VariableEventKind kind, VariableEventStream& stream, VirtualRegister virtualRegister)
  355. {
  356. stream.appendAndLog(VariableEvent::spill(kind, MinifiedID(m_node), virtualRegister, m_spillFormat));
  357. }
  358. // The node whose result is stored in this virtual register.
  359. Node* m_node;
  360. uint32_t m_useCount;
  361. DataFormat m_registerFormat;
  362. DataFormat m_spillFormat;
  363. bool m_canFill;
  364. bool m_bornForOSR;
  365. bool m_isConstant;
  366. union {
  367. GPRReg gpr;
  368. FPRReg fpr;
  369. #if USE(JSVALUE32_64)
  370. struct {
  371. GPRReg tagGPR;
  372. GPRReg payloadGPR;
  373. } v;
  374. #endif
  375. } u;
  376. };
  377. } } // namespace JSC::DFG
  378. #endif
  379. #endif