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
26#include "config.h"
27#include "DFGWatchpointCollectionPhase.h"
28
29#if ENABLE(DFG_JIT)
30
31#include "ArrayPrototype.h"
32#include "DFGClobberize.h"
33#include "DFGGraph.h"
34#include "DFGPhase.h"
35#include "JSCInlines.h"
36
37namespace JSC { namespace DFG {
38
39class WatchpointCollectionPhase : public Phase {
40    static const bool verbose = false;
41
42public:
43    WatchpointCollectionPhase(Graph& graph)
44        : Phase(graph, "watchpoint collection")
45    {
46    }
47
48    bool run()
49    {
50        for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) {
51            BasicBlock* block = m_graph.block(blockIndex);
52            if (!block)
53                continue;
54
55            for (unsigned nodeIndex = block->size(); nodeIndex--;) {
56                m_node = block->at(nodeIndex);
57                handle();
58            }
59        }
60
61        return true;
62    }
63
64private:
65    void handle()
66    {
67        DFG_NODE_DO_TO_CHILDREN(m_graph, m_node, handleEdge);
68
69        switch (m_node->op()) {
70        case CompareEqConstant:
71        case IsUndefined:
72            handleMasqueradesAsUndefined();
73            break;
74
75        case CompareEq:
76            if (m_node->isBinaryUseKind(ObjectUse)
77                || (m_node->child1().useKind() == ObjectUse && m_node->child2().useKind() == ObjectOrOtherUse)
78                || (m_node->child1().useKind() == ObjectOrOtherUse && m_node->child2().useKind() == ObjectUse))
79                handleMasqueradesAsUndefined();
80            break;
81
82        case LogicalNot:
83        case Branch:
84            if (m_node->child1().useKind() == ObjectOrOtherUse)
85                handleMasqueradesAsUndefined();
86            break;
87
88        case GetByVal:
89            if (m_node->arrayMode().type() == Array::Double
90                && m_node->arrayMode().isSaneChain()) {
91                addLazily(globalObject()->arrayPrototype()->structure()->transitionWatchpointSet());
92                addLazily(globalObject()->objectPrototype()->structure()->transitionWatchpointSet());
93            }
94
95            if (m_node->arrayMode().type() == Array::String)
96                handleStringGetByVal();
97
98            if (JSArrayBufferView* view = m_graph.tryGetFoldableViewForChild1(m_node))
99                addLazily(view);
100            break;
101
102        case PutByVal:
103            if (JSArrayBufferView* view = m_graph.tryGetFoldableViewForChild1(m_node))
104                addLazily(view);
105            break;
106
107        case StringCharAt:
108            handleStringGetByVal();
109            break;
110
111        case NewArray:
112        case NewArrayWithSize:
113        case NewArrayBuffer:
114            if (!globalObject()->isHavingABadTime() && !hasAnyArrayStorage(m_node->indexingType()))
115                addLazily(globalObject()->havingABadTimeWatchpoint());
116            break;
117
118        case AllocationProfileWatchpoint:
119            addLazily(jsCast<JSFunction*>(m_node->function())->allocationProfileWatchpointSet());
120            break;
121
122        case StructureTransitionWatchpoint:
123            m_graph.watchpoints().addLazily(
124                m_node->origin.semantic,
125                m_node->child1()->op() == WeakJSConstant ? BadWeakConstantCacheWatchpoint : BadCacheWatchpoint,
126                m_node->structure()->transitionWatchpointSet());
127            break;
128
129        case VariableWatchpoint:
130            addLazily(m_node->variableWatchpointSet());
131            break;
132
133        case VarInjectionWatchpoint:
134            addLazily(globalObject()->varInjectionWatchpoint());
135            break;
136
137        case FunctionReentryWatchpoint:
138            addLazily(m_node->symbolTable()->m_functionEnteredOnce);
139            break;
140
141        case TypedArrayWatchpoint:
142            addLazily(m_node->typedArray());
143            break;
144
145        default:
146            break;
147        }
148    }
149
150    void handleEdge(Node*, Edge edge)
151    {
152        switch (edge.useKind()) {
153        case StringObjectUse:
154        case StringOrStringObjectUse: {
155            Structure* stringObjectStructure = globalObject()->stringObjectStructure();
156            Structure* stringPrototypeStructure = stringObjectStructure->storedPrototype().asCell()->structure();
157            ASSERT(m_graph.watchpoints().isValidOrMixed(stringPrototypeStructure->transitionWatchpointSet()));
158
159            m_graph.watchpoints().addLazily(
160                m_node->origin.semantic, NotStringObject,
161                stringPrototypeStructure->transitionWatchpointSet());
162            break;
163        }
164
165        default:
166            break;
167        }
168    }
169
170    void handleMasqueradesAsUndefined()
171    {
172        if (m_graph.masqueradesAsUndefinedWatchpointIsStillValid(m_node->origin.semantic))
173            addLazily(globalObject()->masqueradesAsUndefinedWatchpoint());
174    }
175
176    void handleStringGetByVal()
177    {
178        if (!m_node->arrayMode().isOutOfBounds())
179            return;
180        if (!globalObject()->stringPrototypeChainIsSane())
181            return;
182        addLazily(globalObject()->stringPrototype()->structure()->transitionWatchpointSet());
183        addLazily(globalObject()->objectPrototype()->structure()->transitionWatchpointSet());
184    }
185
186    void addLazily(WatchpointSet* set)
187    {
188        m_graph.watchpoints().addLazily(set);
189    }
190    void addLazily(InlineWatchpointSet& set)
191    {
192        m_graph.watchpoints().addLazily(set);
193    }
194    void addLazily(JSArrayBufferView* view)
195    {
196        m_graph.watchpoints().addLazily(view);
197    }
198
199    JSGlobalObject* globalObject()
200    {
201        return m_graph.globalObjectFor(m_node->origin.semantic);
202    }
203
204    Node* m_node;
205};
206
207bool performWatchpointCollection(Graph& graph)
208{
209    SamplingRegion samplingRegion("DFG Watchpoint Collection Phase");
210    return runPhase<WatchpointCollectionPhase>(graph);
211}
212
213} } // namespace JSC::DFG
214
215#endif // ENABLE(DFG_JIT)
216
217