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{
67}
68
69CallLinkInfo::~CallLinkInfo()
70{
71 clearStub();
72
73 if (isOnList())
74 remove();
75}
76
77void CallLinkInfo::clearStub()
78{
79 if (!stub())
80 return;
81
82 m_stub->clearCallNodesFor(this);
83 m_stub = nullptr;
84}
85
86void CallLinkInfo::unlink(VM& vm)
87{
88 // We could be called even if we're not linked anymore because of how polymorphic calls
89 // work. Each callsite within the polymorphic call stub may separately ask us to unlink().
90 if (isLinked())
91 unlinkFor(vm, *this);
92
93 // Either we were unlinked, in which case we should not have been on any list, or we unlinked
94 // ourselves so that we're not on any list anymore.
95 RELEASE_ASSERT(!isOnList());
96}
97
98CodeLocationNearCall<JSInternalPtrTag> CallLinkInfo::callReturnLocation()
99{
100 RELEASE_ASSERT(!isDirect());
101 return CodeLocationNearCall<JSInternalPtrTag>(m_callReturnLocationOrPatchableJump, NearCallMode::Regular);
102}
103
104CodeLocationJump<JSInternalPtrTag> CallLinkInfo::patchableJump()
105{
106 RELEASE_ASSERT(callType() == DirectTailCall);
107 return CodeLocationJump<JSInternalPtrTag>(m_callReturnLocationOrPatchableJump);
108}
109
110CodeLocationDataLabelPtr<JSInternalPtrTag> CallLinkInfo::hotPathBegin()
111{
112 RELEASE_ASSERT(!isDirect());
113 return CodeLocationDataLabelPtr<JSInternalPtrTag>(m_hotPathBeginOrSlowPathStart);
114}
115
116CodeLocationLabel<JSInternalPtrTag> CallLinkInfo::slowPathStart()
117{
118 RELEASE_ASSERT(isDirect());
119 return m_hotPathBeginOrSlowPathStart;
120}
121
122void CallLinkInfo::setCallee(VM& vm, JSCell* owner, JSObject* callee)
123{
124 RELEASE_ASSERT(!isDirect());
125 m_calleeOrCodeBlock.set(vm, owner, callee);
126}
127
128void CallLinkInfo::clearCallee()
129{
130 RELEASE_ASSERT(!isDirect());
131 m_calleeOrCodeBlock.clear();
132}
133
134JSObject* CallLinkInfo::callee()
135{
136 RELEASE_ASSERT(!isDirect());
137 return jsCast<JSObject*>(m_calleeOrCodeBlock.get());
138}
139
140void CallLinkInfo::setCodeBlock(VM& vm, JSCell* owner, FunctionCodeBlock* codeBlock)
141{
142 RELEASE_ASSERT(isDirect());
143 m_calleeOrCodeBlock.setMayBeNull(vm, owner, codeBlock);
144}
145
146void CallLinkInfo::clearCodeBlock()
147{
148 RELEASE_ASSERT(isDirect());
149 m_calleeOrCodeBlock.clear();
150}
151
152FunctionCodeBlock* CallLinkInfo::codeBlock()
153{
154 RELEASE_ASSERT(isDirect());
155 return jsCast<FunctionCodeBlock*>(m_calleeOrCodeBlock.get());
156}
157
158void CallLinkInfo::setLastSeenCallee(VM& vm, const JSCell* owner, JSObject* callee)
159{
160 RELEASE_ASSERT(!isDirect());
161 m_lastSeenCalleeOrExecutable.set(vm, owner, callee);
162}
163
164void CallLinkInfo::clearLastSeenCallee()
165{
166 RELEASE_ASSERT(!isDirect());
167 m_lastSeenCalleeOrExecutable.clear();
168}
169
170JSObject* CallLinkInfo::lastSeenCallee()
171{
172 RELEASE_ASSERT(!isDirect());
173 return jsCast<JSObject*>(m_lastSeenCalleeOrExecutable.get());
174}
175
176bool CallLinkInfo::haveLastSeenCallee()
177{
178 RELEASE_ASSERT(!isDirect());
179 return !!m_lastSeenCalleeOrExecutable;
180}
181
182void CallLinkInfo::setExecutableDuringCompilation(ExecutableBase* executable)
183{
184 RELEASE_ASSERT(isDirect());
185 m_lastSeenCalleeOrExecutable.setWithoutWriteBarrier(executable);
186}
187
188ExecutableBase* CallLinkInfo::executable()
189{
190 RELEASE_ASSERT(isDirect());
191 return jsCast<ExecutableBase*>(m_lastSeenCalleeOrExecutable.get());
192}
193
194void CallLinkInfo::setMaxNumArguments(unsigned value)
195{
196 RELEASE_ASSERT(isDirect());
197 RELEASE_ASSERT(value);
198 m_maxNumArguments = value;
199}
200
201void CallLinkInfo::visitWeak(VM& vm)
202{
203 auto handleSpecificCallee = [&] (JSFunction* callee) {
204 if (vm.heap.isMarked(callee->executable()))
205 m_hasSeenClosure = true;
206 else
207 m_clearedByGC = true;
208 };
209
210 if (isLinked()) {
211 if (stub()) {
212 if (!stub()->visitWeak(vm)) {
213 if (Options::verboseOSR()) {
214 dataLog(
215 "At ", m_codeOrigin, ", ", RawPointer(this), ": clearing call stub to ",
216 listDump(stub()->variants()), ", stub routine ", RawPointer(stub()),
217 ".\n");
218 }
219 unlink(vm);
220 m_clearedByGC = true;
221 }
222 } else if (!vm.heap.isMarked(m_calleeOrCodeBlock.get())) {
223 if (isDirect()) {
224 if (Options::verboseOSR()) {
225 dataLog(
226 "Clearing call to ", RawPointer(codeBlock()), " (",
227 pointerDump(codeBlock()), ").\n");
228 }
229 } else {
230 if (callee()->type() == JSFunctionType) {
231 if (Options::verboseOSR()) {
232 dataLog(
233 "Clearing call to ",
234 RawPointer(callee()), " (",
235 static_cast<JSFunction*>(callee())->executable()->hashFor(specializationKind()),
236 ").\n");
237 }
238 handleSpecificCallee(static_cast<JSFunction*>(callee()));
239 } else {
240 if (Options::verboseOSR())
241 dataLog("Clearing call to ", RawPointer(callee()), ".\n");
242 m_clearedByGC = true;
243 }
244 }
245 unlink(vm);
246 } else if (isDirect() && !vm.heap.isMarked(m_lastSeenCalleeOrExecutable.get())) {
247 if (Options::verboseOSR()) {
248 dataLog(
249 "Clearing call to ", RawPointer(executable()),
250 " because the executable is dead.\n");
251 }
252 unlink(vm);
253 // We should only get here once the owning CodeBlock is dying, since the executable must
254 // already be in the owner's weak references.
255 m_lastSeenCalleeOrExecutable.clear();
256 }
257 }
258 if (!isDirect() && haveLastSeenCallee() && !vm.heap.isMarked(lastSeenCallee())) {
259 if (lastSeenCallee()->type() == JSFunctionType)
260 handleSpecificCallee(jsCast<JSFunction*>(lastSeenCallee()));
261 else
262 m_clearedByGC = true;
263 clearLastSeenCallee();
264 }
265}
266
267void CallLinkInfo::setFrameShuffleData(const CallFrameShuffleData& shuffleData)
268{
269 m_frameShuffleData = std::make_unique<CallFrameShuffleData>(shuffleData);
270}
271
272} // namespace JSC
273#endif // ENABLE(JIT)
274
275