DFG should be able to set watchpoints on global variables
[WebKit-https.git] / Source / JavaScriptCore / dfg / DFGConstantFoldingPhase.cpp
1 /*
2  * Copyright (C) 2012 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
26 #include "config.h"
27 #include "DFGConstantFoldingPhase.h"
28
29 #if ENABLE(DFG_JIT)
30
31 #include "DFGAbstractState.h"
32 #include "DFGBasicBlock.h"
33 #include "DFGGraph.h"
34 #include "DFGInsertionSet.h"
35 #include "DFGPhase.h"
36
37 namespace JSC { namespace DFG {
38
39 class ConstantFoldingPhase : public Phase {
40 public:
41     ConstantFoldingPhase(Graph& graph)
42         : Phase(graph, "constant folding")
43     {
44     }
45     
46     bool run()
47     {
48         bool changed = false;
49         
50         AbstractState state(m_graph);
51         InsertionSet<NodeIndex> insertionSet;
52         
53         for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) {
54             BasicBlock* block = m_graph.m_blocks[blockIndex].get();
55             if (!block)
56                 continue;
57             if (!block->cfaFoundConstants)
58                 continue;
59 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
60             dataLog("Constant folding considering Block #%u.\n", blockIndex);
61 #endif
62             state.beginBasicBlock(block);
63             for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) {
64                 if (!state.isValid())
65                     break;
66                 NodeIndex nodeIndex = block->at(indexInBlock);
67                 Node& node = m_graph[nodeIndex];
68                 
69                 bool eliminated = false;
70                     
71                 switch (node.op()) {
72                 case CheckArgumentsNotCreated: {
73                     if (!isEmptySpeculation(
74                             state.variables().operand(
75                                 m_graph.argumentsRegisterFor(node.codeOrigin)).m_type))
76                         break;
77                     ASSERT(node.refCount() == 1);
78                     node.setOpAndDefaultFlags(Phantom);
79                     eliminated = true;
80                     break;
81                 }
82                     
83                 // FIXME: This would be a great place to remove CheckStructure's.
84                     
85                 default:
86                     break;
87                 }
88                 
89                 if (eliminated) {
90                     changed = true;
91                     continue;
92                 }
93                 
94                 state.execute(indexInBlock);
95                 if (!node.shouldGenerate()
96                     || state.didClobber()
97                     || node.hasConstant())
98                     continue;
99                 JSValue value = state.forNode(nodeIndex).value();
100                 if (!value)
101                     continue;
102                 
103                 Node phantom(Phantom, node.codeOrigin);
104                 
105                 if (node.op() == GetLocal) {
106                     NodeIndex previousLocalAccess = NoNode;
107                     if (block->variablesAtHead.operand(node.local()) == nodeIndex
108                         && m_graph[node.child1()].op() == Phi) {
109                         // We expect this to be the common case.
110                         ASSERT(block->isInPhis(node.child1().index()));
111                         previousLocalAccess = node.child1().index();
112                         block->variablesAtHead.operand(node.local()) = previousLocalAccess;
113                     } else {
114                         ASSERT(indexInBlock > 0);
115                         // Must search for the previous access to this local.
116                         for (BlockIndex subIndexInBlock = indexInBlock; subIndexInBlock--;) {
117                             NodeIndex subNodeIndex = block->at(subIndexInBlock);
118                             Node& subNode = m_graph[subNodeIndex];
119                             if (!subNode.shouldGenerate())
120                                 continue;
121                             if (!subNode.hasVariableAccessData())
122                                 continue;
123                             if (subNode.local() != node.local())
124                                 continue;
125                             // The two must have been unified.
126                             ASSERT(subNode.variableAccessData() == node.variableAccessData());
127                             previousLocalAccess = subNodeIndex;
128                             break;
129                         }
130                         ASSERT(previousLocalAccess != NoNode);
131                     }
132                     
133                     NodeIndex tailNodeIndex = block->variablesAtTail.operand(node.local());
134                     if (tailNodeIndex == nodeIndex)
135                         block->variablesAtTail.operand(node.local()) = previousLocalAccess;
136                     else {
137                         ASSERT(m_graph[tailNodeIndex].op() == Flush
138                                || m_graph[tailNodeIndex].op() == SetLocal);
139                     }
140                 }
141                 
142                 phantom.children = node.children;
143                 phantom.ref();
144                 
145                 m_graph.convertToConstant(nodeIndex, value);
146                 NodeIndex phantomNodeIndex = m_graph.size();
147                 m_graph.append(phantom);
148                 insertionSet.append(indexInBlock, phantomNodeIndex);
149                 
150                 changed = true;
151             }
152             insertionSet.execute(*block);
153             state.reset();
154         }
155         
156         return changed;
157     }
158 };
159
160 bool performConstantFolding(Graph& graph)
161 {
162     return runPhase<ConstantFoldingPhase>(graph);
163 }
164
165 } } // namespace JSC::DFG
166
167 #endif // ENABLE(DFG_JIT)
168
169