DFGCPSRethreadingPhase.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500
  1. /*
  2. * Copyright (C) 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. #include "config.h"
  26. #include "DFGCPSRethreadingPhase.h"
  27. #if ENABLE(DFG_JIT)
  28. #include "DFGBasicBlockInlines.h"
  29. #include "DFGGraph.h"
  30. #include "DFGPhase.h"
  31. #include "Operations.h"
  32. namespace JSC { namespace DFG {
  33. class CPSRethreadingPhase : public Phase {
  34. public:
  35. CPSRethreadingPhase(Graph& graph)
  36. : Phase(graph, "CPS rethreading")
  37. {
  38. }
  39. bool run()
  40. {
  41. if (m_graph.m_form == ThreadedCPS)
  42. return false;
  43. clearIsLoadedFrom();
  44. freeUnnecessaryNodes();
  45. canonicalizeLocalsInBlocks();
  46. propagatePhis<LocalOperand>();
  47. propagatePhis<ArgumentOperand>();
  48. m_graph.m_form = ThreadedCPS;
  49. return true;
  50. }
  51. private:
  52. void clearIsLoadedFrom()
  53. {
  54. for (unsigned i = 0; i < m_graph.m_variableAccessData.size(); ++i)
  55. m_graph.m_variableAccessData[i].setIsLoadedFrom(false);
  56. }
  57. void freeUnnecessaryNodes()
  58. {
  59. SamplingRegion samplingRegion("DFG CPS Rethreading: freeUnnecessaryNodes");
  60. for (BlockIndex blockIndex = m_graph.m_blocks.size(); blockIndex--;) {
  61. BasicBlock* block = m_graph.m_blocks[blockIndex].get();
  62. if (!block)
  63. continue;
  64. ASSERT(block->isReachable);
  65. unsigned fromIndex = 0;
  66. unsigned toIndex = 0;
  67. while (fromIndex < block->size()) {
  68. Node* node = block->at(fromIndex++);
  69. switch (node->op()) {
  70. case GetLocal:
  71. case Flush:
  72. case PhantomLocal:
  73. node->children.setChild1(Edge());
  74. break;
  75. case Phantom:
  76. if (!node->child1())
  77. continue;
  78. switch (node->child1()->op()) {
  79. case Phi:
  80. case SetArgument:
  81. case SetLocal:
  82. node->convertToPhantomLocal();
  83. break;
  84. default:
  85. ASSERT(node->child1()->hasResult());
  86. break;
  87. }
  88. break;
  89. case Nop:
  90. continue;
  91. default:
  92. break;
  93. }
  94. node->replacement = 0; // Reset the replacement since the next phase will use it.
  95. block->at(toIndex++) = node;
  96. }
  97. block->resize(toIndex);
  98. for (unsigned phiIndex = block->phis.size(); phiIndex--;)
  99. m_graph.m_allocator.free(block->phis[phiIndex]);
  100. block->phis.resize(0);
  101. }
  102. }
  103. template<OperandKind operandKind>
  104. void clearVariablesAtHeadAndTail()
  105. {
  106. ASSERT(
  107. m_block->variablesAtHead.sizeFor<operandKind>()
  108. == m_block->variablesAtTail.sizeFor<operandKind>());
  109. for (unsigned i = m_block->variablesAtHead.sizeFor<operandKind>(); i--;) {
  110. m_block->variablesAtHead.atFor<operandKind>(i) = 0;
  111. m_block->variablesAtTail.atFor<operandKind>(i) = 0;
  112. }
  113. }
  114. ALWAYS_INLINE Node* addPhiSilently(BasicBlock* block, const CodeOrigin& codeOrigin, VariableAccessData* variable)
  115. {
  116. Node* result = m_graph.addNode(SpecNone, Phi, codeOrigin, OpInfo(variable));
  117. block->phis.append(result);
  118. return result;
  119. }
  120. template<OperandKind operandKind>
  121. ALWAYS_INLINE Node* addPhi(BasicBlock* block, const CodeOrigin& codeOrigin, VariableAccessData* variable, size_t index)
  122. {
  123. Node* result = addPhiSilently(block, codeOrigin, variable);
  124. phiStackFor<operandKind>().append(PhiStackEntry(block, index, result));
  125. return result;
  126. }
  127. template<OperandKind operandKind>
  128. ALWAYS_INLINE Node* addPhi(const CodeOrigin& codeOrigin, VariableAccessData* variable, size_t index)
  129. {
  130. return addPhi<operandKind>(m_block, codeOrigin, variable, index);
  131. }
  132. template<OperandKind operandKind>
  133. void canonicalizeGetLocalFor(Node* node, VariableAccessData* variable, size_t idx)
  134. {
  135. ASSERT(!node->child1());
  136. if (Node* otherNode = m_block->variablesAtTail.atFor<operandKind>(idx)) {
  137. ASSERT(otherNode->variableAccessData() == variable);
  138. switch (otherNode->op()) {
  139. case Flush:
  140. case PhantomLocal:
  141. otherNode = otherNode->child1().node();
  142. if (otherNode->op() == Phi) {
  143. // We need to have a GetLocal, so this might as well be the one.
  144. node->children.setChild1(Edge(otherNode));
  145. m_block->variablesAtTail.atFor<operandKind>(idx) = node;
  146. return;
  147. }
  148. ASSERT(otherNode->op() == SetLocal || otherNode->op() == SetArgument);
  149. break;
  150. default:
  151. break;
  152. }
  153. ASSERT(otherNode->op() == SetLocal || otherNode->op() == SetArgument || otherNode->op() == GetLocal);
  154. ASSERT(otherNode->variableAccessData() == variable);
  155. if (otherNode->op() == SetArgument) {
  156. variable->setIsLoadedFrom(true);
  157. node->children.setChild1(Edge(otherNode));
  158. m_block->variablesAtTail.atFor<operandKind>(idx) = node;
  159. return;
  160. }
  161. if (variable->isCaptured()) {
  162. variable->setIsLoadedFrom(true);
  163. if (otherNode->op() == GetLocal)
  164. otherNode = otherNode->child1().node();
  165. else
  166. ASSERT(otherNode->op() == SetLocal || otherNode->op() == SetArgument);
  167. ASSERT(otherNode->op() == Phi || otherNode->op() == SetLocal || otherNode->op() == SetArgument);
  168. // Keep this GetLocal but link it to the prior ones.
  169. node->children.setChild1(Edge(otherNode));
  170. m_block->variablesAtTail.atFor<operandKind>(idx) = node;
  171. return;
  172. }
  173. if (otherNode->op() == GetLocal) {
  174. // Replace all references to this GetLocal with otherNode.
  175. node->replacement = otherNode;
  176. return;
  177. }
  178. ASSERT(otherNode->op() == SetLocal);
  179. node->replacement = otherNode->child1().node();
  180. return;
  181. }
  182. variable->setIsLoadedFrom(true);
  183. Node* phi = addPhi<operandKind>(node->codeOrigin, variable, idx);
  184. node->children.setChild1(Edge(phi));
  185. m_block->variablesAtHead.atFor<operandKind>(idx) = phi;
  186. m_block->variablesAtTail.atFor<operandKind>(idx) = node;
  187. }
  188. void canonicalizeGetLocal(Node* node)
  189. {
  190. VariableAccessData* variable = node->variableAccessData();
  191. if (operandIsArgument(variable->local()))
  192. canonicalizeGetLocalFor<ArgumentOperand>(node, variable, operandToArgument(variable->local()));
  193. else
  194. canonicalizeGetLocalFor<LocalOperand>(node, variable, variable->local());
  195. }
  196. void canonicalizeSetLocal(Node* node)
  197. {
  198. m_block->variablesAtTail.setOperand(node->local(), node);
  199. }
  200. template<NodeType nodeType, OperandKind operandKind>
  201. void canonicalizeFlushOrPhantomLocalFor(Node* node, VariableAccessData* variable, size_t idx)
  202. {
  203. ASSERT(!node->child1());
  204. if (Node* otherNode = m_block->variablesAtTail.atFor<operandKind>(idx)) {
  205. ASSERT(otherNode->variableAccessData() == variable);
  206. switch (otherNode->op()) {
  207. case Flush:
  208. case PhantomLocal:
  209. case GetLocal:
  210. otherNode = otherNode->child1().node();
  211. break;
  212. default:
  213. break;
  214. }
  215. ASSERT(otherNode->op() == Phi || otherNode->op() == SetLocal || otherNode->op() == SetArgument);
  216. if (nodeType == PhantomLocal && otherNode->op() == SetLocal) {
  217. // PhantomLocal(SetLocal) doesn't make sense. PhantomLocal means: at this
  218. // point I know I would have been interested in the value of this variable
  219. // for the purpose of OSR. PhantomLocal(SetLocal) means: at this point I
  220. // know that I would have read the value written by that SetLocal. This is
  221. // redundant and inefficient, since really it just means that we want to
  222. // be keeping the operand to the SetLocal alive. The SetLocal may die, and
  223. // we'll be fine because OSR tracks dead SetLocals.
  224. // So we turn this into a Phantom on the child of the SetLocal.
  225. node->convertToPhantom();
  226. node->children.setChild1(otherNode->child1());
  227. return;
  228. }
  229. variable->setIsLoadedFrom(true);
  230. // There is nothing wrong with having redundant Flush's. It just needs to
  231. // be linked appropriately. Note that if there had already been a previous
  232. // use at tail then we don't override it. It's fine for variablesAtTail to
  233. // omit Flushes and PhantomLocals. On the other hand, having it refer to a
  234. // Flush or a PhantomLocal if just before it the last use was a GetLocal would
  235. // seriously confuse the CFA.
  236. node->children.setChild1(Edge(otherNode));
  237. return;
  238. }
  239. variable->setIsLoadedFrom(true);
  240. node->children.setChild1(Edge(addPhi<operandKind>(node->codeOrigin, variable, idx)));
  241. m_block->variablesAtHead.atFor<operandKind>(idx) = node;
  242. m_block->variablesAtTail.atFor<operandKind>(idx) = node;
  243. }
  244. template<NodeType nodeType>
  245. void canonicalizeFlushOrPhantomLocal(Node* node)
  246. {
  247. VariableAccessData* variable = node->variableAccessData();
  248. if (operandIsArgument(variable->local()))
  249. canonicalizeFlushOrPhantomLocalFor<nodeType, ArgumentOperand>(node, variable, operandToArgument(variable->local()));
  250. else
  251. canonicalizeFlushOrPhantomLocalFor<nodeType, LocalOperand>(node, variable, variable->local());
  252. }
  253. void canonicalizeSetArgument(Node* node)
  254. {
  255. int local = node->local();
  256. ASSERT(operandIsArgument(local));
  257. int argument = operandToArgument(local);
  258. m_block->variablesAtHead.setArgumentFirstTime(argument, node);
  259. m_block->variablesAtTail.setArgumentFirstTime(argument, node);
  260. }
  261. void canonicalizeLocalsInBlock()
  262. {
  263. if (!m_block)
  264. return;
  265. ASSERT(m_block->isReachable);
  266. clearVariablesAtHeadAndTail<ArgumentOperand>();
  267. clearVariablesAtHeadAndTail<LocalOperand>();
  268. // Assumes that all phi references have been removed. Assumes that things that
  269. // should be live have a non-zero ref count, but doesn't assume that the ref
  270. // counts are correct beyond that (more formally !!logicalRefCount == !!actualRefCount
  271. // but not logicalRefCount == actualRefCount). Assumes that it can break ref
  272. // counts.
  273. for (unsigned nodeIndex = 0; nodeIndex < m_block->size(); ++nodeIndex) {
  274. Node* node = m_block->at(nodeIndex);
  275. m_graph.performSubstitution(node);
  276. // The rules for threaded CPS form:
  277. //
  278. // Head variable: describes what is live at the head of the basic block.
  279. // Head variable links may refer to Flush, PhantomLocal, Phi, or SetArgument.
  280. // SetArgument may only appear in the root block.
  281. //
  282. // Tail variable: the last thing that happened to the variable in the block.
  283. // It may be a Flush, PhantomLocal, GetLocal, SetLocal, or SetArgument.
  284. // SetArgument may only appear in the root block. Note that if there ever
  285. // was a GetLocal to the variable, and it was followed by PhantomLocals and
  286. // Flushes but not SetLocals, then the tail variable will be the GetLocal.
  287. // This reflects the fact that you only care that the tail variable is a
  288. // Flush or PhantomLocal if nothing else interesting happened.
  289. //
  290. // Child of GetLocal: the operation that the GetLocal keeps alive. For
  291. // uncaptured locals, it may be a Phi from the current block. For arguments,
  292. // it may be a SetArgument. For captured locals and arguments it may also be
  293. // a SetLocal.
  294. //
  295. // Child of SetLocal: must be a value producing node.
  296. //
  297. // Child of Flush: it may be a Phi from the current block or a SetLocal. For
  298. // arguments it may also be a SetArgument.
  299. //
  300. // Child of PhantomLocal: it may be a Phi from the current block. For
  301. // arguments it may also be a SetArgument.
  302. //
  303. // Children of Phi: other Phis in the same basic block, or any of the
  304. // following from predecessor blocks: SetLocal, Phi, or SetArgument. These
  305. // are computed by looking at the tail variables of the predecessor blocks
  306. // and either using it directly (if it's a SetLocal, Phi, or SetArgument) or
  307. // loading that nodes child (if it's a GetLocal, PhanomLocal, or Flush - all
  308. // of these will have children that are SetLocal, Phi, or SetArgument).
  309. switch (node->op()) {
  310. case GetLocal:
  311. canonicalizeGetLocal(node);
  312. break;
  313. case SetLocal:
  314. canonicalizeSetLocal(node);
  315. break;
  316. case Flush:
  317. canonicalizeFlushOrPhantomLocal<Flush>(node);
  318. break;
  319. case PhantomLocal:
  320. canonicalizeFlushOrPhantomLocal<PhantomLocal>(node);
  321. break;
  322. case SetArgument:
  323. canonicalizeSetArgument(node);
  324. break;
  325. default:
  326. break;
  327. }
  328. }
  329. }
  330. void canonicalizeLocalsInBlocks()
  331. {
  332. SamplingRegion samplingRegion("DFG CPS Rethreading: canonicalizeLocalsInBlocks");
  333. for (m_blockIndex = m_graph.m_blocks.size(); m_blockIndex--;) {
  334. m_block = m_graph.m_blocks[m_blockIndex].get();
  335. canonicalizeLocalsInBlock();
  336. }
  337. }
  338. template<OperandKind operandKind>
  339. void propagatePhis()
  340. {
  341. Vector<PhiStackEntry, 128>& phiStack = operandKind == ArgumentOperand ? m_argumentPhiStack : m_localPhiStack;
  342. SamplingRegion samplingRegion("DFG CPS Rethreading: propagatePhis");
  343. // Ensure that attempts to use this fail instantly.
  344. m_block = 0;
  345. m_blockIndex = NoBlock;
  346. while (!phiStack.isEmpty()) {
  347. PhiStackEntry entry = phiStack.last();
  348. phiStack.removeLast();
  349. BasicBlock* block = entry.m_block;
  350. PredecessorList& predecessors = block->m_predecessors;
  351. Node* currentPhi = entry.m_phi;
  352. VariableAccessData* variable = currentPhi->variableAccessData();
  353. size_t index = entry.m_index;
  354. for (size_t i = predecessors.size(); i--;) {
  355. BasicBlock* predecessorBlock = m_graph.m_blocks[predecessors[i]].get();
  356. Node* variableInPrevious = predecessorBlock->variablesAtTail.atFor<operandKind>(index);
  357. if (!variableInPrevious) {
  358. variableInPrevious = addPhi<operandKind>(predecessorBlock, currentPhi->codeOrigin, variable, index);
  359. predecessorBlock->variablesAtTail.atFor<operandKind>(index) = variableInPrevious;
  360. predecessorBlock->variablesAtHead.atFor<operandKind>(index) = variableInPrevious;
  361. } else {
  362. switch (variableInPrevious->op()) {
  363. case GetLocal:
  364. case PhantomLocal:
  365. case Flush:
  366. ASSERT(variableInPrevious->variableAccessData() == variableInPrevious->child1()->variableAccessData());
  367. variableInPrevious = variableInPrevious->child1().node();
  368. break;
  369. default:
  370. break;
  371. }
  372. }
  373. ASSERT(
  374. variableInPrevious->op() == SetLocal
  375. || variableInPrevious->op() == Phi
  376. || variableInPrevious->op() == SetArgument);
  377. if (!currentPhi->child1()) {
  378. currentPhi->children.setChild1(Edge(variableInPrevious));
  379. continue;
  380. }
  381. if (!currentPhi->child2()) {
  382. currentPhi->children.setChild2(Edge(variableInPrevious));
  383. continue;
  384. }
  385. if (!currentPhi->child3()) {
  386. currentPhi->children.setChild3(Edge(variableInPrevious));
  387. continue;
  388. }
  389. Node* newPhi = addPhiSilently(block, currentPhi->codeOrigin, variable);
  390. newPhi->children = currentPhi->children;
  391. currentPhi->children.initialize(newPhi, variableInPrevious, 0);
  392. }
  393. }
  394. }
  395. struct PhiStackEntry {
  396. PhiStackEntry(BasicBlock* block, size_t index, Node* phi)
  397. : m_block(block)
  398. , m_index(index)
  399. , m_phi(phi)
  400. {
  401. }
  402. BasicBlock* m_block;
  403. size_t m_index;
  404. Node* m_phi;
  405. };
  406. template<OperandKind operandKind>
  407. Vector<PhiStackEntry, 128>& phiStackFor()
  408. {
  409. if (operandKind == ArgumentOperand)
  410. return m_argumentPhiStack;
  411. return m_localPhiStack;
  412. }
  413. BlockIndex m_blockIndex;
  414. BasicBlock* m_block;
  415. Vector<PhiStackEntry, 128> m_argumentPhiStack;
  416. Vector<PhiStackEntry, 128> m_localPhiStack;
  417. };
  418. bool performCPSRethreading(Graph& graph)
  419. {
  420. SamplingRegion samplingRegion("DFG CPS Rethreading Phase");
  421. return runPhase<CPSRethreadingPhase>(graph);
  422. }
  423. } } // namespace JSC::DFG
  424. #endif // ENABLE(DFG_JIT)