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#pragma once
27
28#include "CallMode.h"
29#include "CodeLocation.h"
30#include "CodeSpecializationKind.h"
31#include "PolymorphicCallStubRoutine.h"
32#include "WriteBarrier.h"
33#include <wtf/SentinelLinkedList.h>
34
35namespace JSC {
36
37#if ENABLE(JIT)
38
39class FunctionCodeBlock;
40class JSFunction;
41enum OpcodeID : unsigned;
42struct CallFrameShuffleData;
43
44class CallLinkInfo : public PackedRawSentinelNode<CallLinkInfo> {
45public:
46 enum CallType {
47 None,
48 Call,
49 CallVarargs,
50 Construct,
51 ConstructVarargs,
52 TailCall,
53 TailCallVarargs,
54 DirectCall,
55 DirectConstruct,
56 DirectTailCall
57 };
58
59 static CallType callTypeFor(OpcodeID opcodeID);
60
61 static bool isVarargsCallType(CallType callType)
62 {
63 switch (callType) {
64 case CallVarargs:
65 case ConstructVarargs:
66 case TailCallVarargs:
67 return true;
68
69 default:
70 return false;
71 }
72 }
73
74 CallLinkInfo();
75
76 ~CallLinkInfo();
77
78 static CodeSpecializationKind specializationKindFor(CallType callType)
79 {
80 return specializationFromIsConstruct(callType == Construct || callType == ConstructVarargs || callType == DirectConstruct);
81 }
82 CodeSpecializationKind specializationKind() const
83 {
84 return specializationKindFor(static_cast<CallType>(m_callType));
85 }
86
87 static CallMode callModeFor(CallType callType)
88 {
89 switch (callType) {
90 case Call:
91 case CallVarargs:
92 case DirectCall:
93 return CallMode::Regular;
94 case TailCall:
95 case TailCallVarargs:
96 case DirectTailCall:
97 return CallMode::Tail;
98 case Construct:
99 case ConstructVarargs:
100 case DirectConstruct:
101 return CallMode::Construct;
102 case None:
103 RELEASE_ASSERT_NOT_REACHED();
104 }
105
106 RELEASE_ASSERT_NOT_REACHED();
107 }
108
109 static bool isDirect(CallType callType)
110 {
111 switch (callType) {
112 case DirectCall:
113 case DirectTailCall:
114 case DirectConstruct:
115 return true;
116 case Call:
117 case CallVarargs:
118 case TailCall:
119 case TailCallVarargs:
120 case Construct:
121 case ConstructVarargs:
122 return false;
123 case None:
124 RELEASE_ASSERT_NOT_REACHED();
125 return false;
126 }
127
128 RELEASE_ASSERT_NOT_REACHED();
129 return false;
130 }
131
132 CallMode callMode() const
133 {
134 return callModeFor(static_cast<CallType>(m_callType));
135 }
136
137 bool isDirect() const
138 {
139 return isDirect(static_cast<CallType>(m_callType));
140 }
141
142 bool isTailCall() const
143 {
144 return callMode() == CallMode::Tail;
145 }
146
147 NearCallMode nearCallMode() const
148 {
149 return isTailCall() ? NearCallMode::Tail : NearCallMode::Regular;
150 }
151
152 bool isVarargs() const
153 {
154 return isVarargsCallType(static_cast<CallType>(m_callType));
155 }
156
157 bool isLinked() const { return m_stub || m_calleeOrCodeBlock; }
158 void unlink(VM&);
159
160 void setUpCall(CallType callType, CodeOrigin codeOrigin, GPRReg calleeGPR)
161 {
162 m_callType = callType;
163 m_codeOrigin = codeOrigin;
164 m_calleeGPR = calleeGPR;
165 }
166
167 void setCallLocations(
168 CodeLocationLabel<JSInternalPtrTag> callReturnLocationOrPatchableJump,
169 CodeLocationLabel<JSInternalPtrTag> hotPathBeginOrSlowPathStart,
170 CodeLocationNearCall<JSInternalPtrTag> hotPathOther)
171 {
172 m_callReturnLocationOrPatchableJump = callReturnLocationOrPatchableJump;
173 m_hotPathBeginOrSlowPathStart = hotPathBeginOrSlowPathStart;
174 m_hotPathOther = hotPathOther;
175 }
176
177 bool allowStubs() const { return m_allowStubs; }
178
179 void disallowStubs()
180 {
181 m_allowStubs = false;
182 }
183
184 CodeLocationNearCall<JSInternalPtrTag> callReturnLocation();
185 CodeLocationJump<JSInternalPtrTag> patchableJump();
186 CodeLocationDataLabelPtr<JSInternalPtrTag> hotPathBegin();
187 CodeLocationLabel<JSInternalPtrTag> slowPathStart();
188
189 CodeLocationNearCall<JSInternalPtrTag> hotPathOther()
190 {
191 return m_hotPathOther;
192 }
193
194 void setCallee(VM&, JSCell*, JSObject* callee);
195 void clearCallee();
196 JSObject* callee();
197
198 void setCodeBlock(VM&, JSCell*, FunctionCodeBlock*);
199 void clearCodeBlock();
200 FunctionCodeBlock* codeBlock();
201
202 void setLastSeenCallee(VM&, const JSCell* owner, JSObject* callee);
203 void clearLastSeenCallee();
204 JSObject* lastSeenCallee() const;
205 bool haveLastSeenCallee() const;
206
207 void setExecutableDuringCompilation(ExecutableBase*);
208 ExecutableBase* executable();
209
210 void setStub(Ref<PolymorphicCallStubRoutine>&& newStub)
211 {
212 clearStub();
213 m_stub = WTFMove(newStub);
214 }
215
216 void clearStub();
217
218 PolymorphicCallStubRoutine* stub() const
219 {
220 return m_stub.get();
221 }
222
223 void setSlowStub(Ref<JITStubRoutine>&& newSlowStub)
224 {
225 m_slowStub = WTFMove(newSlowStub);
226 }
227
228 void clearSlowStub()
229 {
230 m_slowStub = nullptr;
231 }
232
233 JITStubRoutine* slowStub()
234 {
235 return m_slowStub.get();
236 }
237
238 bool seenOnce()
239 {
240 return m_hasSeenShouldRepatch;
241 }
242
243 void clearSeen()
244 {
245 m_hasSeenShouldRepatch = false;
246 }
247
248 void setSeen()
249 {
250 m_hasSeenShouldRepatch = true;
251 }
252
253 bool hasSeenClosure()
254 {
255 return m_hasSeenClosure;
256 }
257
258 void setHasSeenClosure()
259 {
260 m_hasSeenClosure = true;
261 }
262
263 bool clearedByGC()
264 {
265 return m_clearedByGC;
266 }
267
268 bool clearedByVirtual()
269 {
270 return m_clearedByVirtual;
271 }
272
273 bool clearedByJettison()
274 {
275 return m_clearedByJettison;
276 }
277
278 void setClearedByVirtual()
279 {
280 m_clearedByVirtual = true;
281 }
282
283 void setClearedByJettison()
284 {
285 m_clearedByJettison = true;
286 }
287
288 void setCallType(CallType callType)
289 {
290 m_callType = callType;
291 }
292
293 CallType callType()
294 {
295 return static_cast<CallType>(m_callType);
296 }
297
298 uint32_t* addressOfMaxArgumentCountIncludingThis()
299 {
300 return &m_maxArgumentCountIncludingThis;
301 }
302
303 uint32_t maxArgumentCountIncludingThis()
304 {
305 return m_maxArgumentCountIncludingThis;
306 }
307
308 void setMaxArgumentCountIncludingThis(unsigned);
309
310 static ptrdiff_t offsetOfSlowPathCount()
311 {
312 return OBJECT_OFFSETOF(CallLinkInfo, m_slowPathCount);
313 }
314
315 GPRReg calleeGPR()
316 {
317 return m_calleeGPR;
318 }
319
320 uint32_t slowPathCount()
321 {
322 return m_slowPathCount;
323 }
324
325 void setCodeOrigin(CodeOrigin codeOrigin)
326 {
327 m_codeOrigin = codeOrigin;
328 }
329
330 CodeOrigin codeOrigin()
331 {
332 return m_codeOrigin;
333 }
334
335 template<typename Functor>
336 void forEachDependentCell(const Functor& functor) const
337 {
338 if (isLinked()) {
339 if (stub())
340 stub()->forEachDependentCell(functor);
341 else {
342 functor(m_calleeOrCodeBlock.get());
343 if (isDirect())
344 functor(m_lastSeenCalleeOrExecutable.get());
345 }
346 }
347 if (!isDirect() && haveLastSeenCallee())
348 functor(lastSeenCallee());
349 }
350
351 void visitWeak(VM&);
352
353 void setFrameShuffleData(const CallFrameShuffleData&);
354
355 const CallFrameShuffleData* frameShuffleData()
356 {
357 return m_frameShuffleData.get();
358 }
359
360private:
361 uint32_t m_maxArgumentCountIncludingThis { 0 }; // For varargs: the profiled maximum number of arguments. For direct: the number of stack slots allocated for arguments.
362 CodeLocationLabel<JSInternalPtrTag> m_callReturnLocationOrPatchableJump;
363 CodeLocationLabel<JSInternalPtrTag> m_hotPathBeginOrSlowPathStart;
364 CodeLocationNearCall<JSInternalPtrTag> m_hotPathOther;
365 WriteBarrier<JSCell> m_calleeOrCodeBlock;
366 WriteBarrier<JSCell> m_lastSeenCalleeOrExecutable;
367 RefPtr<PolymorphicCallStubRoutine> m_stub;
368 RefPtr<JITStubRoutine> m_slowStub;
369 std::unique_ptr<CallFrameShuffleData> m_frameShuffleData;
370 CodeOrigin m_codeOrigin;
371 bool m_hasSeenShouldRepatch : 1;
372 bool m_hasSeenClosure : 1;
373 bool m_clearedByGC : 1;
374 bool m_clearedByVirtual : 1;
375 bool m_allowStubs : 1;
376 bool m_clearedByJettison : 1;
377 unsigned m_callType : 4; // CallType
378 GPRReg m_calleeGPR { InvalidGPRReg };
379 uint32_t m_slowPathCount { 0 };
380};
381
382inline CodeOrigin getCallLinkInfoCodeOrigin(CallLinkInfo& callLinkInfo)
383{
384 return callLinkInfo.codeOrigin();
385}
386
387#endif // ENABLE(JIT)
388
389} // namespace JSC
390