1/*
2 * Copyright (C) 2013-2018 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 "DFGOSREntrypointCreationPhase.h"
28
29#if ENABLE(DFG_JIT)
30
31#include "DFGBasicBlockInlines.h"
32#include "DFGBlockInsertionSet.h"
33#include "DFGCFG.h"
34#include "DFGGraph.h"
35#include "DFGLoopPreHeaderCreationPhase.h"
36#include "DFGPhase.h"
37#include "JSCInlines.h"
38
39namespace JSC { namespace DFG {
40
41class OSREntrypointCreationPhase : public Phase {
42public:
43 OSREntrypointCreationPhase(Graph& graph)
44 : Phase(graph, "OSR entrypoint creation")
45 {
46 }
47
48 bool run()
49 {
50 RELEASE_ASSERT(m_graph.m_plan.mode() == FTLForOSREntryMode);
51 RELEASE_ASSERT(m_graph.m_form == ThreadedCPS);
52
53 BytecodeIndex bytecodeIndex = m_graph.m_plan.osrEntryBytecodeIndex();
54 RELEASE_ASSERT(bytecodeIndex);
55 RELEASE_ASSERT(bytecodeIndex.offset());
56
57 // Needed by createPreHeader().
58 m_graph.ensureCPSDominators();
59
60 CodeBlock* baseline = m_graph.m_profiledBlock;
61
62 BasicBlock* target = 0;
63 for (unsigned blockIndex = m_graph.numBlocks(); blockIndex--;) {
64 BasicBlock* block = m_graph.block(blockIndex);
65 if (!block)
66 continue;
67 unsigned nodeIndex = 0;
68 Node* firstNode = block->at(0);
69 while (firstNode->isSemanticallySkippable())
70 firstNode = block->at(++nodeIndex);
71 if (firstNode->op() == LoopHint
72 && firstNode->origin.semantic == CodeOrigin(bytecodeIndex)) {
73 target = block;
74 break;
75 }
76 }
77
78 if (!target) {
79 // This is a terrible outcome. It shouldn't often happen but it might
80 // happen and so we should defend against it. If it happens, then this
81 // compilation is a failure.
82 return false;
83 }
84
85 BlockInsertionSet insertionSet(m_graph);
86
87 // We say that the execution count of the entry block is 1, because we know for sure
88 // that this must be the case. Under our definition of executionCount, "1" means "once
89 // per invocation". We could have said NaN here, since that would ask any clients of
90 // executionCount to use best judgement - but that seems unnecessary since we know for
91 // sure what the executionCount should be in this case.
92 BasicBlock* newRoot = insertionSet.insert(0, 1);
93
94 // We'd really like to use an unset origin, but ThreadedCPS won't allow that.
95 NodeOrigin origin = NodeOrigin(CodeOrigin(BytecodeIndex(0)), CodeOrigin(BytecodeIndex(0)), false);
96
97 Vector<Node*> locals(baseline->numCalleeLocals());
98 for (int local = 0; local < baseline->numCalleeLocals(); ++local) {
99 Node* previousHead = target->variablesAtHead.local(local);
100 if (!previousHead)
101 continue;
102 VariableAccessData* variable = previousHead->variableAccessData();
103 locals[local] = newRoot->appendNode(
104 m_graph, variable->prediction(), ExtractOSREntryLocal, origin,
105 OpInfo(variable->local().offset()));
106
107 newRoot->appendNode(
108 m_graph, SpecNone, MovHint, origin, OpInfo(variable->local().offset()),
109 Edge(locals[local]));
110 }
111
112 // Now use the origin of the target, since it's not OK to exit, and we will probably hoist
113 // type checks to here.
114 origin = target->at(0)->origin;
115
116 ArgumentsVector newArguments = m_graph.m_rootToArguments.find(m_graph.block(0))->value;
117 for (int argument = 0; argument < baseline->numParameters(); ++argument) {
118 Node* oldNode = target->variablesAtHead.argument(argument);
119 if (!oldNode) {
120 // Just for sanity, always have a SetArgumentDefinitely even if it's not needed.
121 oldNode = newArguments[argument];
122 }
123 Node* node = newRoot->appendNode(
124 m_graph, SpecNone, SetArgumentDefinitely, origin,
125 OpInfo(oldNode->variableAccessData()));
126 newArguments[argument] = node;
127 }
128
129 for (int local = 0; local < baseline->numCalleeLocals(); ++local) {
130 Node* previousHead = target->variablesAtHead.local(local);
131 if (!previousHead)
132 continue;
133 VariableAccessData* variable = previousHead->variableAccessData();
134 Node* node = locals[local];
135 newRoot->appendNode(
136 m_graph, SpecNone, SetLocal, origin, OpInfo(variable), Edge(node));
137 }
138
139 newRoot->appendNode(
140 m_graph, SpecNone, Jump, origin,
141 OpInfo(createPreHeader(m_graph, insertionSet, target)));
142
143 insertionSet.execute();
144
145 RELEASE_ASSERT(m_graph.m_roots.size() == 1);
146 m_graph.m_roots[0] = newRoot;
147 m_graph.m_rootToArguments.clear();
148 m_graph.m_rootToArguments.add(newRoot, newArguments);
149
150 m_graph.invalidateCFG();
151 m_graph.resetReachability();
152 m_graph.killUnreachableBlocks();
153
154 return true;
155 }
156};
157
158bool performOSREntrypointCreation(Graph& graph)
159{
160 return runPhase<OSREntrypointCreationPhase>(graph);
161}
162
163} } // namespace JSC::DFG
164
165#endif // ENABLE(DFG_JIT)
166
167
168