Support compiling catch in the FTL
[WebKit-https.git] / Source / JavaScriptCore / dfg / DFGOSREntrypointCreationPhase.cpp
1 /*
2  * Copyright (C) 2013-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 "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
39 namespace JSC { namespace DFG {
40
41 class OSREntrypointCreationPhase : public Phase {
42 public:
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         unsigned bytecodeIndex = m_graph.m_plan.osrEntryBytecodeIndex;
54         RELEASE_ASSERT(bytecodeIndex);
55         RELEASE_ASSERT(bytecodeIndex != UINT_MAX);
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(0), CodeOrigin(0), false);
96         
97         Vector<Node*> locals(baseline->m_numCalleeLocals);
98         for (int local = 0; local < baseline->m_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_entrypointToArguments.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 SetArgument even if it's not needed.
121                 oldNode = newArguments[argument];
122             }
123             Node* node = newRoot->appendNode(
124                 m_graph, SpecNone, SetArgument, origin,
125                 OpInfo(oldNode->variableAccessData()));
126             newArguments[argument] = node;
127         }
128
129         for (int local = 0; local < baseline->m_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_entrypoints.size() == 1);
146         m_graph.m_entrypoints[0] = newRoot;
147         m_graph.m_entrypointToArguments.clear();
148         m_graph.m_entrypointToArguments.add(newRoot, newArguments);
149
150         m_graph.invalidateCFG();
151         m_graph.resetReachability();
152         m_graph.killUnreachableBlocks();
153
154         return true;
155     }
156 };
157
158 bool performOSREntrypointCreation(Graph& graph)
159 {
160     return runPhase<OSREntrypointCreationPhase>(graph);
161 }
162
163 } } // namespace JSC::DFG
164
165 #endif // ENABLE(DFG_JIT)
166
167