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