Some JSEntryPtrTags should actually be JSInternalPtrTags.
[WebKit-https.git] / Source / JavaScriptCore / bytecode / CallLinkInfo.cpp
1 /*
2  * Copyright (C) 2012-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 "CallLinkInfo.h"
28
29 #include "CallFrameShuffleData.h"
30 #include "DFGOperations.h"
31 #include "DFGThunks.h"
32 #include "FunctionCodeBlock.h"
33 #include "JSCInlines.h"
34 #include "MacroAssembler.h"
35 #include "Opcode.h"
36 #include "Repatch.h"
37 #include <wtf/ListDump.h>
38
39 #if ENABLE(JIT)
40 namespace JSC {
41
42 CallLinkInfo::CallType CallLinkInfo::callTypeFor(OpcodeID opcodeID)
43 {
44     if (opcodeID == op_call || opcodeID == op_call_eval)
45         return Call;
46     if (opcodeID == op_call_varargs)
47         return CallVarargs;
48     if (opcodeID == op_construct)
49         return Construct;
50     if (opcodeID == op_construct_varargs)
51         return ConstructVarargs;
52     if (opcodeID == op_tail_call)
53         return TailCall;
54     ASSERT(opcodeID == op_tail_call_varargs || opcodeID == op_tail_call_forward_arguments);
55     return TailCallVarargs;
56 }
57
58 CallLinkInfo::CallLinkInfo()
59     : m_hasSeenShouldRepatch(false)
60     , m_hasSeenClosure(false)
61     , m_clearedByGC(false)
62     , m_allowStubs(true)
63     , m_isLinked(false)
64     , m_callType(None)
65     , m_calleeGPR(255)
66     , m_maxNumArguments(0)
67     , m_slowPathCount(0)
68 {
69 }
70
71 CallLinkInfo::~CallLinkInfo()
72 {
73     clearStub();
74     
75     if (isOnList())
76         remove();
77 }
78
79 void CallLinkInfo::clearStub()
80 {
81     if (!stub())
82         return;
83
84     m_stub->clearCallNodesFor(this);
85     m_stub = nullptr;
86 }
87
88 void CallLinkInfo::unlink(VM& vm)
89 {
90     // We could be called even if we're not linked anymore because of how polymorphic calls
91     // work. Each callsite within the polymorphic call stub may separately ask us to unlink().
92     if (isLinked())
93         unlinkFor(vm, *this);
94
95     // Either we were unlinked, in which case we should not have been on any list, or we unlinked
96     // ourselves so that we're not on any list anymore.
97     RELEASE_ASSERT(!isOnList());
98 }
99
100 CodeLocationNearCall<JSInternalPtrTag> CallLinkInfo::callReturnLocation()
101 {
102     RELEASE_ASSERT(!isDirect());
103     return CodeLocationNearCall<JSInternalPtrTag>(m_callReturnLocationOrPatchableJump, Regular);
104 }
105
106 CodeLocationJump<JSInternalPtrTag> CallLinkInfo::patchableJump()
107 {
108     RELEASE_ASSERT(callType() == DirectTailCall);
109     return CodeLocationJump<JSInternalPtrTag>(m_callReturnLocationOrPatchableJump);
110 }
111
112 CodeLocationDataLabelPtr<JSInternalPtrTag> CallLinkInfo::hotPathBegin()
113 {
114     RELEASE_ASSERT(!isDirect());
115     return CodeLocationDataLabelPtr<JSInternalPtrTag>(m_hotPathBeginOrSlowPathStart);
116 }
117
118 CodeLocationLabel<JSInternalPtrTag> CallLinkInfo::slowPathStart()
119 {
120     RELEASE_ASSERT(isDirect());
121     return m_hotPathBeginOrSlowPathStart;
122 }
123
124 void CallLinkInfo::setCallee(VM& vm, JSCell* owner, JSObject* callee)
125 {
126     RELEASE_ASSERT(!isDirect());
127     MacroAssembler::repatchPointer(hotPathBegin(), callee);
128     m_calleeOrCodeBlock.set(vm, owner, callee);
129     m_isLinked = true;
130 }
131
132 void CallLinkInfo::clearCallee()
133 {
134     RELEASE_ASSERT(!isDirect());
135     MacroAssembler::repatchPointer(hotPathBegin(), nullptr);
136     m_calleeOrCodeBlock.clear();
137     m_isLinked = false;
138 }
139
140 JSObject* CallLinkInfo::callee()
141 {
142     RELEASE_ASSERT(!isDirect());
143     return jsCast<JSObject*>(m_calleeOrCodeBlock.get());
144 }
145
146 void CallLinkInfo::setCodeBlock(VM& vm, JSCell* owner, FunctionCodeBlock* codeBlock)
147 {
148     RELEASE_ASSERT(isDirect());
149     m_calleeOrCodeBlock.setMayBeNull(vm, owner, codeBlock);
150     m_isLinked = true;
151 }
152
153 void CallLinkInfo::clearCodeBlock()
154 {
155     RELEASE_ASSERT(isDirect());
156     m_calleeOrCodeBlock.clear();
157     m_isLinked = false;
158 }
159
160 FunctionCodeBlock* CallLinkInfo::codeBlock()
161 {
162     RELEASE_ASSERT(isDirect());
163     return jsCast<FunctionCodeBlock*>(m_calleeOrCodeBlock.get());
164 }
165
166 void CallLinkInfo::setLastSeenCallee(VM& vm, const JSCell* owner, JSObject* callee)
167 {
168     RELEASE_ASSERT(!isDirect());
169     m_lastSeenCalleeOrExecutable.set(vm, owner, callee);
170 }
171
172 void CallLinkInfo::clearLastSeenCallee()
173 {
174     RELEASE_ASSERT(!isDirect());
175     m_lastSeenCalleeOrExecutable.clear();
176 }
177
178 JSObject* CallLinkInfo::lastSeenCallee()
179 {
180     RELEASE_ASSERT(!isDirect());
181     return jsCast<JSObject*>(m_lastSeenCalleeOrExecutable.get());
182 }
183
184 bool CallLinkInfo::haveLastSeenCallee()
185 {
186     RELEASE_ASSERT(!isDirect());
187     return !!m_lastSeenCalleeOrExecutable;
188 }
189
190 void CallLinkInfo::setExecutableDuringCompilation(ExecutableBase* executable)
191 {
192     RELEASE_ASSERT(isDirect());
193     m_lastSeenCalleeOrExecutable.setWithoutWriteBarrier(executable);
194 }
195
196 ExecutableBase* CallLinkInfo::executable()
197 {
198     RELEASE_ASSERT(isDirect());
199     return jsCast<ExecutableBase*>(m_lastSeenCalleeOrExecutable.get());
200 }
201
202 void CallLinkInfo::setMaxNumArguments(unsigned value)
203 {
204     RELEASE_ASSERT(isDirect());
205     RELEASE_ASSERT(value);
206     m_maxNumArguments = value;
207 }
208
209 void CallLinkInfo::visitWeak(VM& vm)
210 {
211     auto handleSpecificCallee = [&] (JSFunction* callee) {
212         if (Heap::isMarked(callee->executable()))
213             m_hasSeenClosure = true;
214         else
215             m_clearedByGC = true;
216     };
217     
218     if (isLinked()) {
219         if (stub()) {
220             if (!stub()->visitWeak(vm)) {
221                 if (Options::verboseOSR()) {
222                     dataLog(
223                         "Clearing closure call to ",
224                         listDump(stub()->variants()), ", stub routine ", RawPointer(stub()),
225                         ".\n");
226                 }
227                 unlink(vm);
228                 m_clearedByGC = true;
229             }
230         } else if (!Heap::isMarked(m_calleeOrCodeBlock.get())) {
231             if (isDirect()) {
232                 if (Options::verboseOSR()) {
233                     dataLog(
234                         "Clearing call to ", RawPointer(codeBlock()), " (",
235                         pointerDump(codeBlock()), ").\n");
236                 }
237             } else {
238                 if (callee()->type() == JSFunctionType) {
239                     if (Options::verboseOSR()) {
240                         dataLog(
241                             "Clearing call to ",
242                             RawPointer(callee()), " (",
243                             static_cast<JSFunction*>(callee())->executable()->hashFor(specializationKind()),
244                             ").\n");
245                     }
246                     handleSpecificCallee(static_cast<JSFunction*>(callee()));
247                 } else {
248                     if (Options::verboseOSR())
249                         dataLog("Clearing call to ", RawPointer(callee()), ".\n");
250                     m_clearedByGC = true;
251                 }
252             }
253             unlink(vm);
254         } else if (isDirect() && !Heap::isMarked(m_lastSeenCalleeOrExecutable.get())) {
255             if (Options::verboseOSR()) {
256                 dataLog(
257                     "Clearing call to ", RawPointer(executable()),
258                     " because the executable is dead.\n");
259             }
260             unlink(vm);
261             // We should only get here once the owning CodeBlock is dying, since the executable must
262             // already be in the owner's weak references.
263             m_lastSeenCalleeOrExecutable.clear();
264         }
265     }
266     if (!isDirect() && haveLastSeenCallee() && !Heap::isMarked(lastSeenCallee())) {
267         if (lastSeenCallee()->type() == JSFunctionType)
268             handleSpecificCallee(jsCast<JSFunction*>(lastSeenCallee()));
269         else
270             m_clearedByGC = true;
271         clearLastSeenCallee();
272     }
273 }
274
275 void CallLinkInfo::setFrameShuffleData(const CallFrameShuffleData& shuffleData)
276 {
277     m_frameShuffleData = std::make_unique<CallFrameShuffleData>(shuffleData);
278 }
279
280 } // namespace JSC
281 #endif // ENABLE(JIT)
282