1/*
2 * Copyright (C) 2015 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 "DFGConstantHoistingPhase.h"
28
29#if ENABLE(DFG_JIT)
30
31#include "DFGGraph.h"
32#include "DFGInsertionSet.h"
33#include "DFGPhase.h"
34#include "DFGPredictionPropagationPhase.h"
35#include "DFGVariableAccessDataDump.h"
36#include "JSCInlines.h"
37
38namespace JSC { namespace DFG {
39
40namespace {
41
42class ConstantHoistingPhase : public Phase {
43public:
44 ConstantHoistingPhase(Graph& graph)
45 : Phase(graph, "constant hoisting")
46 {
47 }
48
49 bool run()
50 {
51 DFG_ASSERT(m_graph, nullptr, m_graph.m_form == SSA);
52
53 m_graph.clearReplacements();
54
55 HashMap<FrozenValue*, Node*> jsValues;
56 HashMap<FrozenValue*, Node*> doubleValues;
57 HashMap<FrozenValue*, Node*> int52Values;
58
59 auto valuesFor = [&] (NodeType op) -> HashMap<FrozenValue*, Node*>& {
60 // Use a roundabout approach because clang thinks that this closure returning a
61 // reference to a stack-allocated value in outer scope is a bug. It's not.
62 HashMap<FrozenValue*, Node*>* result;
63
64 switch (op) {
65 case JSConstant:
66 result = &jsValues;
67 break;
68 case DoubleConstant:
69 result = &doubleValues;
70 break;
71 case Int52Constant:
72 result = &int52Values;
73 break;
74 default:
75 DFG_CRASH(m_graph, nullptr, "Invalid node type in valuesFor()");
76 result = nullptr;
77 break;
78 }
79
80 return *result;
81 };
82
83 Vector<Node*> toFree;
84
85 for (BasicBlock* block : m_graph.blocksInNaturalOrder()) {
86 unsigned sourceIndex = 0;
87 unsigned targetIndex = 0;
88 while (sourceIndex < block->size()) {
89 Node* node = block->at(sourceIndex++);
90 switch (node->op()) {
91 case JSConstant:
92 case DoubleConstant:
93 case Int52Constant: {
94 HashMap<FrozenValue*, Node*>& values = valuesFor(node->op());
95 auto result = values.add(node->constant(), node);
96 if (result.isNewEntry)
97 node->origin = m_graph.block(0)->at(0)->origin;
98 else {
99 node->setReplacement(result.iterator->value);
100 toFree.append(node);
101 }
102 break;
103 }
104 default:
105 block->at(targetIndex++) = node;
106 break;
107 }
108 }
109 block->resize(targetIndex);
110 }
111
112 // Insert the constants into the root block.
113 InsertionSet insertionSet(m_graph);
114 auto insertConstants = [&] (const HashMap<FrozenValue*, Node*>& values) {
115 for (auto& entry : values)
116 insertionSet.insert(0, entry.value);
117 };
118 insertConstants(jsValues);
119 insertConstants(doubleValues);
120 insertConstants(int52Values);
121 insertionSet.execute(m_graph.block(0));
122
123 // Perform all of the substitutions. We want all instances of the removed constants to
124 // point at their replacements.
125 for (BasicBlock* block : m_graph.blocksInNaturalOrder()) {
126 for (Node* node : *block)
127 m_graph.performSubstitution(node);
128 }
129
130 // And finally free the constants that we removed.
131 m_graph.invalidateNodeLiveness();
132 for (Node* node : toFree)
133 m_graph.deleteNode(node);
134
135 return true;
136 }
137};
138
139} // anonymous namespace
140
141bool performConstantHoisting(Graph& graph)
142{
143 return runPhase<ConstantHoistingPhase>(graph);
144}
145
146} } // namespace JSC::DFG
147
148#endif // ENABLE(DFG_JIT)
149
150