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