1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef jit_BaselineIC_h
8 #define jit_BaselineIC_h
10 #include "mozilla/Assertions.h"
11 #include "mozilla/Attributes.h"
16 #include "jit/ICState.h"
17 #include "jit/JitCode.h"
18 #include "jit/shared/Assembler-shared.h"
19 #include "jit/TypeData.h"
20 #include "js/TypeDecls.h"
22 class JS_PUBLIC_API JSTracer
;
24 enum class JSOp
: uint8_t;
28 MOZ_COLD
void ReportOutOfMemory(JSContext
* cx
);
33 class CacheIRStubInfo
;
36 enum class VMFunctionId
;
38 // [SMDOC] JIT Inline Caches (ICs)
40 // Baseline Inline Caches are polymorphic caches that aggressively
41 // share their stub code.
43 // Every polymorphic site contains a linked list of stubs which are
44 // specific to that site. These stubs are composed of a |StubData|
45 // structure that stores parametrization information (e.g.
46 // the shape pointer for a shape-check-and-property-get stub), any
47 // dynamic information (e.g. warm-up counters), a pointer to the stub code,
48 // and a pointer to the next stub state in the linked list.
50 // Every BaselineScript keeps an table of |CacheDescriptor| data
51 // structures, which store the following:
52 // A pointer to the first StubData in the cache.
53 // The bytecode PC of the relevant IC.
54 // The machine-code PC where the call to the stubcode returns.
58 // Control flow Pointers
59 // =======# ----. .---->
64 // .---------------------------------------.
65 // | .-------------------------. |
67 // Baseline | | | | | |
68 // JIT Code 0 ^ 1 ^ 2 ^ | | |
69 // +--------------+ .-->+-----+ +-----+ +-----+ | | |
70 // | | #=|==>| |==>| |==>| FB | | | |
71 // | | # | +-----+ +-----+ +-----+ | | |
72 // | | # | # # # | | |
73 // |==============|==# | # # # | | |
74 // |=== IC =======| | # # # | | |
75 // .->|==============|<===|======#=========#=========# | | |
80 // | | | | +---------+ | |
81 // | | | | | Fallback| | |
82 // | | | | | Stub | | |
83 // | | | | | Code | | |
84 // | | | | +---------+ | |
85 // | +--------------+ | | |
86 // | |_______ | +---------+ | |
87 // | | | | Stub |<---/ |
88 // | IC | \--. | Code | |
89 // | Descriptor | | +---------+ |
91 // | +-----------------+ | +---------+ |
92 // \--| Ins | PC | Stub |----/ | Stub |<-------/
93 // +-----------------+ | Code |
94 // | ... | +---------+
95 // +-----------------+
102 class ICFallbackStub
;
105 void FallbackICSpew(JSContext
* cx
, ICFallbackStub
* stub
, const char* fmt
, ...)
106 MOZ_FORMAT_PRINTF(3, 4);
108 # define FallbackICSpew(...)
111 // An entry in the ICScript IC table. There's one ICEntry per IC.
113 // A pointer to the first IC stub for this instruction.
117 explicit ICEntry(ICStub
* firstStub
) : firstStub_(firstStub
) {}
119 ICStub
* firstStub() const {
120 MOZ_ASSERT(firstStub_
);
124 void setFirstStub(ICStub
* stub
) { firstStub_
= stub
; }
126 static constexpr size_t offsetOfFirstStub() {
127 return offsetof(ICEntry
, firstStub_
);
130 void trace(JSTracer
* trc
);
131 bool traceWeak(JSTracer
* trc
);
135 // Base class for all IC stubs.
138 friend class ICFallbackStub
;
141 // The raw jitcode to call for this stub.
144 // Counts the number of times the stub was entered
146 // See Bug 1494473 comment 6 for a mechanism to handle overflow if overflow
147 // becomes a concern.
148 uint32_t enteredCount_
= 0;
150 // Tracks input types for some CacheIR stubs, to help optimize
151 // polymorphic cases. Stored in the base class to make use of
155 // Whether this is an ICFallbackStub or an ICCacheIRStub.
158 ICStub(uint8_t* stubCode
, bool isFallback
)
159 : stubCode_(stubCode
), isFallback_(isFallback
) {
160 MOZ_ASSERT(stubCode
!= nullptr);
164 inline bool isFallback() const { return isFallback_
; }
166 inline ICStub
* maybeNext() const;
168 inline const ICFallbackStub
* toFallbackStub() const {
169 MOZ_ASSERT(isFallback());
170 return reinterpret_cast<const ICFallbackStub
*>(this);
173 inline ICFallbackStub
* toFallbackStub() {
174 MOZ_ASSERT(isFallback());
175 return reinterpret_cast<ICFallbackStub
*>(this);
178 ICCacheIRStub
* toCacheIRStub() {
179 MOZ_ASSERT(!isFallback());
180 return reinterpret_cast<ICCacheIRStub
*>(this);
182 const ICCacheIRStub
* toCacheIRStub() const {
183 MOZ_ASSERT(!isFallback());
184 return reinterpret_cast<const ICCacheIRStub
*>(this);
187 bool usesTrampolineCode() const {
188 // All fallback code is stored in a single JitCode instance, so we can't
189 // call JitCode::FromExecutable on the raw pointer.
193 MOZ_ASSERT(!usesTrampolineCode());
194 return JitCode::FromExecutable(stubCode_
);
197 uint32_t enteredCount() const { return enteredCount_
; }
198 inline void incrementEnteredCount() { enteredCount_
++; }
199 void resetEnteredCount() { enteredCount_
= 0; }
201 static constexpr size_t offsetOfStubCode() {
202 return offsetof(ICStub
, stubCode_
);
204 static constexpr size_t offsetOfEnteredCount() {
205 return offsetof(ICStub
, enteredCount_
);
209 class ICFallbackStub final
: public ICStub
{
210 friend class ICStubConstIterator
;
213 // The PC offset of this IC's bytecode op within the JSScript.
216 // The state of this IC.
220 explicit ICFallbackStub(uint32_t pcOffset
, TrampolinePtr stubCode
)
221 : ICStub(stubCode
.value
, /* isFallback = */ true), pcOffset_(pcOffset
) {}
223 inline size_t numOptimizedStubs() const { return state_
.numOptimizedStubs(); }
225 bool newStubIsFirstStub() const { return state_
.newStubIsFirstStub(); }
227 ICState
& state() { return state_
; }
229 uint32_t pcOffset() const { return pcOffset_
; }
231 // Add a new stub to the IC chain terminated by this fallback stub.
232 inline void addNewStub(ICEntry
* icEntry
, ICCacheIRStub
* stub
);
234 void discardStubs(JSContext
* cx
, ICEntry
* icEntry
);
236 void clearUsedByTranspiler() { state_
.clearUsedByTranspiler(); }
237 void setUsedByTranspiler() { state_
.setUsedByTranspiler(); }
238 bool usedByTranspiler() const { return state_
.usedByTranspiler(); }
240 void clearHasFoldedStub() { state_
.clearHasFoldedStub(); }
241 void setHasFoldedStub() { state_
.setHasFoldedStub(); }
242 bool hasFoldedStub() const { return state_
.hasFoldedStub(); }
244 TrialInliningState
trialInliningState() const {
245 return state_
.trialInliningState();
247 void setTrialInliningState(TrialInliningState state
) {
248 state_
.setTrialInliningState(state
);
251 void trackNotAttached();
253 void unlinkStub(Zone
* zone
, ICEntry
* icEntry
, ICCacheIRStub
* prev
,
254 ICCacheIRStub
* stub
);
255 void unlinkStubUnbarriered(ICEntry
* icEntry
, ICCacheIRStub
* prev
,
256 ICCacheIRStub
* stub
);
259 class ICCacheIRStub final
: public ICStub
{
260 // Pointer to next IC stub.
261 ICStub
* next_
= nullptr;
263 const CacheIRStubInfo
* stubInfo_
;
266 // Ensure stub data is 8-byte aligned on 32-bit.
267 uintptr_t padding_
= 0;
271 ICCacheIRStub(JitCode
* stubCode
, const CacheIRStubInfo
* stubInfo
)
272 : ICStub(stubCode
->raw(), /* isFallback = */ false),
273 stubInfo_(stubInfo
) {}
275 ICStub
* next() const { return next_
; }
276 void setNext(ICStub
* stub
) { next_
= stub
; }
278 ICCacheIRStub
* nextCacheIR() const {
279 return next_
->isFallback() ? nullptr : next_
->toCacheIRStub();
282 const CacheIRStubInfo
* stubInfo() const { return stubInfo_
; }
283 uint8_t* stubDataStart();
285 void trace(JSTracer
* trc
);
286 bool traceWeak(JSTracer
* trc
);
288 // Optimized stubs get purged on GC. But some stubs can be active on the
289 // stack during GC - specifically the ones that can make calls. To ensure
290 // that these do not get purged, all stubs that can make calls are allocated
291 // in the fallback stub space.
292 bool makesGCCalls() const;
293 bool allocatedInFallbackSpace() const { return makesGCCalls(); }
295 static constexpr size_t offsetOfNext() {
296 return offsetof(ICCacheIRStub
, next_
);
299 void setTypeData(TypeData data
) { typeData_
= data
; }
300 TypeData
typeData() const { return typeData_
; }
303 // Assert stub size is what we expect to catch regressions.
305 static_assert(sizeof(ICFallbackStub
) == 3 * sizeof(uintptr_t));
306 static_assert(sizeof(ICCacheIRStub
) == 4 * sizeof(uintptr_t));
308 static_assert(sizeof(ICFallbackStub
) == 5 * sizeof(uintptr_t));
309 static_assert(sizeof(ICCacheIRStub
) == 6 * sizeof(uintptr_t));
312 inline ICStub
* ICStub::maybeNext() const {
313 return isFallback() ? nullptr : toCacheIRStub()->next();
316 inline void ICFallbackStub::addNewStub(ICEntry
* icEntry
, ICCacheIRStub
* stub
) {
317 MOZ_ASSERT(stub
->next() == nullptr);
318 stub
->setNext(icEntry
->firstStub());
319 icEntry
->setFirstStub(stub
);
320 state_
.trackAttached();
323 AllocatableGeneralRegisterSet
BaselineICAvailableGeneralRegs(size_t numInputs
);
325 bool ICSupportsPolymorphicTypeData(JSOp op
);
327 struct IonOsrTempData
;
329 extern bool DoCallFallback(JSContext
* cx
, BaselineFrame
* frame
,
330 ICFallbackStub
* stub
, uint32_t argc
, Value
* vp
,
331 MutableHandleValue res
);
333 extern bool DoSpreadCallFallback(JSContext
* cx
, BaselineFrame
* frame
,
334 ICFallbackStub
* stub
, Value
* vp
,
335 MutableHandleValue res
);
337 extern bool DoToBoolFallback(JSContext
* cx
, BaselineFrame
* frame
,
338 ICFallbackStub
* stub
, HandleValue arg
,
339 MutableHandleValue ret
);
341 extern bool DoGetElemSuperFallback(JSContext
* cx
, BaselineFrame
* frame
,
342 ICFallbackStub
* stub
, HandleValue lhs
,
343 HandleValue rhs
, HandleValue receiver
,
344 MutableHandleValue res
);
346 extern bool DoGetElemFallback(JSContext
* cx
, BaselineFrame
* frame
,
347 ICFallbackStub
* stub
, HandleValue lhs
,
348 HandleValue rhs
, MutableHandleValue res
);
350 extern bool DoSetElemFallback(JSContext
* cx
, BaselineFrame
* frame
,
351 ICFallbackStub
* stub
, Value
* stack
,
352 HandleValue objv
, HandleValue index
,
355 extern bool DoInFallback(JSContext
* cx
, BaselineFrame
* frame
,
356 ICFallbackStub
* stub
, HandleValue key
,
357 HandleValue objValue
, MutableHandleValue res
);
359 extern bool DoHasOwnFallback(JSContext
* cx
, BaselineFrame
* frame
,
360 ICFallbackStub
* stub
, HandleValue keyValue
,
361 HandleValue objValue
, MutableHandleValue res
);
363 extern bool DoCheckPrivateFieldFallback(JSContext
* cx
, BaselineFrame
* frame
,
364 ICFallbackStub
* stub
,
365 HandleValue objValue
,
366 HandleValue keyValue
,
367 MutableHandleValue res
);
369 extern bool DoGetNameFallback(JSContext
* cx
, BaselineFrame
* frame
,
370 ICFallbackStub
* stub
, HandleObject envChain
,
371 MutableHandleValue res
);
373 extern bool DoBindNameFallback(JSContext
* cx
, BaselineFrame
* frame
,
374 ICFallbackStub
* stub
, HandleObject envChain
,
375 MutableHandleValue res
);
377 extern bool DoGetIntrinsicFallback(JSContext
* cx
, BaselineFrame
* frame
,
378 ICFallbackStub
* stub
,
379 MutableHandleValue res
);
381 extern bool DoGetPropFallback(JSContext
* cx
, BaselineFrame
* frame
,
382 ICFallbackStub
* stub
, MutableHandleValue val
,
383 MutableHandleValue res
);
385 extern bool DoGetPropSuperFallback(JSContext
* cx
, BaselineFrame
* frame
,
386 ICFallbackStub
* stub
, HandleValue receiver
,
387 MutableHandleValue val
,
388 MutableHandleValue res
);
390 extern bool DoSetPropFallback(JSContext
* cx
, BaselineFrame
* frame
,
391 ICFallbackStub
* stub
, Value
* stack
,
392 HandleValue lhs
, HandleValue rhs
);
394 extern bool DoGetIteratorFallback(JSContext
* cx
, BaselineFrame
* frame
,
395 ICFallbackStub
* stub
, HandleValue value
,
396 MutableHandleValue res
);
398 extern bool DoOptimizeSpreadCallFallback(JSContext
* cx
, BaselineFrame
* frame
,
399 ICFallbackStub
* stub
,
401 MutableHandleValue res
);
403 extern bool DoInstanceOfFallback(JSContext
* cx
, BaselineFrame
* frame
,
404 ICFallbackStub
* stub
, HandleValue lhs
,
405 HandleValue rhs
, MutableHandleValue res
);
407 extern bool DoTypeOfFallback(JSContext
* cx
, BaselineFrame
* frame
,
408 ICFallbackStub
* stub
, HandleValue val
,
409 MutableHandleValue res
);
411 extern bool DoToPropertyKeyFallback(JSContext
* cx
, BaselineFrame
* frame
,
412 ICFallbackStub
* stub
, HandleValue val
,
413 MutableHandleValue res
);
415 extern bool DoRestFallback(JSContext
* cx
, BaselineFrame
* frame
,
416 ICFallbackStub
* stub
, MutableHandleValue res
);
418 extern bool DoUnaryArithFallback(JSContext
* cx
, BaselineFrame
* frame
,
419 ICFallbackStub
* stub
, HandleValue val
,
420 MutableHandleValue res
);
422 extern bool DoBinaryArithFallback(JSContext
* cx
, BaselineFrame
* frame
,
423 ICFallbackStub
* stub
, HandleValue lhs
,
424 HandleValue rhs
, MutableHandleValue ret
);
426 extern bool DoNewArrayFallback(JSContext
* cx
, BaselineFrame
* frame
,
427 ICFallbackStub
* stub
, MutableHandleValue res
);
429 extern bool DoNewObjectFallback(JSContext
* cx
, BaselineFrame
* frame
,
430 ICFallbackStub
* stub
, MutableHandleValue res
);
432 extern bool DoCompareFallback(JSContext
* cx
, BaselineFrame
* frame
,
433 ICFallbackStub
* stub
, HandleValue lhs
,
434 HandleValue rhs
, MutableHandleValue ret
);
436 extern bool DoCloseIterFallback(JSContext
* cx
, BaselineFrame
* frame
,
437 ICFallbackStub
* stub
, HandleObject iter
);
442 #endif /* jit_BaselineIC_h */