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
;
37 enum class VMFunctionId
;
39 // [SMDOC] JIT Inline Caches (ICs)
41 // Baseline Inline Caches are polymorphic caches that aggressively
42 // share their stub code.
44 // Every polymorphic site contains a linked list of stubs which are
45 // specific to that site. These stubs are composed of a |StubData|
46 // structure that stores parametrization information (e.g.
47 // the shape pointer for a shape-check-and-property-get stub), any
48 // dynamic information (e.g. warm-up counters), a pointer to the stub code,
49 // and a pointer to the next stub state in the linked list.
51 // Every BaselineScript keeps an table of |CacheDescriptor| data
52 // structures, which store the following:
53 // A pointer to the first StubData in the cache.
54 // The bytecode PC of the relevant IC.
55 // The machine-code PC where the call to the stubcode returns.
59 // Control flow Pointers
60 // =======# ----. .---->
65 // .---------------------------------------.
66 // | .-------------------------. |
68 // Baseline | | | | | |
69 // JIT Code 0 ^ 1 ^ 2 ^ | | |
70 // +--------------+ .-->+-----+ +-----+ +-----+ | | |
71 // | | #=|==>| |==>| |==>| FB | | | |
72 // | | # | +-----+ +-----+ +-----+ | | |
73 // | | # | # # # | | |
74 // |==============|==# | # # # | | |
75 // |=== IC =======| | # # # | | |
76 // .->|==============|<===|======#=========#=========# | | |
81 // | | | | +---------+ | |
82 // | | | | | Fallback| | |
83 // | | | | | Stub | | |
84 // | | | | | Code | | |
85 // | | | | +---------+ | |
86 // | +--------------+ | | |
87 // | |_______ | +---------+ | |
88 // | | | | Stub |<---/ |
89 // | IC | \--. | Code | |
90 // | Descriptor | | +---------+ |
92 // | +-----------------+ | +---------+ |
93 // \--| Ins | PC | Stub |----/ | Stub |<-------/
94 // +-----------------+ | Code |
95 // | ... | +---------+
96 // +-----------------+
103 class ICFallbackStub
;
106 void FallbackICSpew(JSContext
* cx
, ICFallbackStub
* stub
, const char* fmt
, ...)
107 MOZ_FORMAT_PRINTF(3, 4);
109 # define FallbackICSpew(...)
112 // An entry in the ICScript IC table. There's one ICEntry per IC.
114 // A pointer to the first IC stub for this instruction.
118 explicit ICEntry(ICStub
* firstStub
) : firstStub_(firstStub
) {}
120 ICStub
* firstStub() const {
121 MOZ_ASSERT(firstStub_
);
125 void setFirstStub(ICStub
* stub
) { firstStub_
= stub
; }
127 static constexpr size_t offsetOfFirstStub() {
128 return offsetof(ICEntry
, firstStub_
);
131 void trace(JSTracer
* trc
);
132 bool traceWeak(JSTracer
* trc
);
136 // Base class for all IC stubs.
139 friend class ICFallbackStub
;
142 // The raw jitcode to call for this stub.
145 // Counts the number of times the stub was entered
147 // See Bug 1494473 comment 6 for a mechanism to handle overflow if overflow
148 // becomes a concern.
149 uint32_t enteredCount_
= 0;
151 // Tracks input types for some CacheIR stubs, to help optimize
152 // polymorphic cases. Stored in the base class to make use of
156 // Whether this is an ICFallbackStub or an ICCacheIRStub.
159 ICStub(uint8_t* stubCode
, bool isFallback
)
160 : stubCode_(stubCode
), isFallback_(isFallback
) {
161 #ifndef ENABLE_PORTABLE_BASELINE_INTERP
162 MOZ_ASSERT(stubCode
!= nullptr);
163 #endif // !ENABLE_PORTABLE_BASELINE_INTERP
167 inline bool isFallback() const { return isFallback_
; }
169 inline ICStub
* maybeNext() const;
171 inline const ICFallbackStub
* toFallbackStub() const {
172 MOZ_ASSERT(isFallback());
173 return reinterpret_cast<const ICFallbackStub
*>(this);
176 inline ICFallbackStub
* toFallbackStub() {
177 MOZ_ASSERT(isFallback());
178 return reinterpret_cast<ICFallbackStub
*>(this);
181 ICCacheIRStub
* toCacheIRStub() {
182 MOZ_ASSERT(!isFallback());
183 return reinterpret_cast<ICCacheIRStub
*>(this);
185 const ICCacheIRStub
* toCacheIRStub() const {
186 MOZ_ASSERT(!isFallback());
187 return reinterpret_cast<const ICCacheIRStub
*>(this);
190 bool usesTrampolineCode() const {
191 // All fallback code is stored in a single JitCode instance, so we can't
192 // call JitCode::FromExecutable on the raw pointer.
196 MOZ_ASSERT(!usesTrampolineCode());
197 return JitCode::FromExecutable(stubCode_
);
199 bool hasJitCode() { return !!stubCode_
; }
201 uint32_t enteredCount() const { return enteredCount_
; }
202 inline void incrementEnteredCount() { enteredCount_
++; }
203 void resetEnteredCount() { enteredCount_
= 0; }
205 static constexpr size_t offsetOfStubCode() {
206 return offsetof(ICStub
, stubCode_
);
208 static constexpr size_t offsetOfEnteredCount() {
209 return offsetof(ICStub
, enteredCount_
);
213 class ICFallbackStub final
: public ICStub
{
214 friend class ICStubConstIterator
;
217 // The PC offset of this IC's bytecode op within the JSScript.
220 // The state of this IC.
224 explicit ICFallbackStub(uint32_t pcOffset
, TrampolinePtr stubCode
)
225 : ICStub(stubCode
.value
, /* isFallback = */ true), pcOffset_(pcOffset
) {}
227 inline size_t numOptimizedStubs() const { return state_
.numOptimizedStubs(); }
229 bool newStubIsFirstStub() const { return state_
.newStubIsFirstStub(); }
231 ICState
& state() { return state_
; }
233 uint32_t pcOffset() const { return pcOffset_
; }
235 // Add a new stub to the IC chain terminated by this fallback stub.
236 inline void addNewStub(ICEntry
* icEntry
, ICCacheIRStub
* stub
);
238 void discardStubs(Zone
* zone
, ICEntry
* icEntry
);
240 void clearUsedByTranspiler() { state_
.clearUsedByTranspiler(); }
241 void setUsedByTranspiler() { state_
.setUsedByTranspiler(); }
242 bool usedByTranspiler() const { return state_
.usedByTranspiler(); }
244 void clearMayHaveFoldedStub() { state_
.clearMayHaveFoldedStub(); }
245 void setMayHaveFoldedStub() { state_
.setMayHaveFoldedStub(); }
246 bool mayHaveFoldedStub() const { return state_
.mayHaveFoldedStub(); }
248 TrialInliningState
trialInliningState() const {
249 return state_
.trialInliningState();
251 void setTrialInliningState(TrialInliningState state
) {
252 state_
.setTrialInliningState(state
);
255 void trackNotAttached();
257 void unlinkStub(Zone
* zone
, ICEntry
* icEntry
, ICCacheIRStub
* prev
,
258 ICCacheIRStub
* stub
);
259 void unlinkStubUnbarriered(ICEntry
* icEntry
, ICCacheIRStub
* prev
,
260 ICCacheIRStub
* stub
);
263 class ICCacheIRStub final
: public ICStub
{
264 // Pointer to next IC stub.
265 ICStub
* next_
= nullptr;
267 const CacheIRStubInfo
* stubInfo_
;
270 // Ensure stub data is 8-byte aligned on 32-bit.
271 uintptr_t padding_
= 0;
275 ICCacheIRStub(JitCode
* stubCode
, const CacheIRStubInfo
* stubInfo
)
276 : ICStub(stubCode
? stubCode
->raw() : nullptr, /* isFallback = */ false),
277 stubInfo_(stubInfo
) {
278 MOZ_ASSERT_IF(!IsPortableBaselineInterpreterEnabled(), stubCode
);
281 ICStub
* next() const { return next_
; }
282 void setNext(ICStub
* stub
) { next_
= stub
; }
284 ICCacheIRStub
* nextCacheIR() const {
285 return next_
->isFallback() ? nullptr : next_
->toCacheIRStub();
288 const CacheIRStubInfo
* stubInfo() const { return stubInfo_
; }
289 uint8_t* stubDataStart();
291 void trace(JSTracer
* trc
);
292 bool traceWeak(JSTracer
* trc
);
294 ICCacheIRStub
* clone(JSRuntime
* rt
, ICStubSpace
& newSpace
);
296 // Returns true if this stub can call JS or VM code that can trigger a GC.
297 bool makesGCCalls() const;
299 static constexpr size_t offsetOfNext() {
300 return offsetof(ICCacheIRStub
, next_
);
303 void setTypeData(TypeData data
) { typeData_
= data
; }
304 TypeData
typeData() const { return typeData_
; }
307 // Assert stub size is what we expect to catch regressions.
309 static_assert(sizeof(ICFallbackStub
) == 3 * sizeof(uintptr_t));
310 static_assert(sizeof(ICCacheIRStub
) == 4 * sizeof(uintptr_t));
312 static_assert(sizeof(ICFallbackStub
) == 5 * sizeof(uintptr_t));
313 static_assert(sizeof(ICCacheIRStub
) == 6 * sizeof(uintptr_t));
316 inline ICStub
* ICStub::maybeNext() const {
317 return isFallback() ? nullptr : toCacheIRStub()->next();
320 inline void ICFallbackStub::addNewStub(ICEntry
* icEntry
, ICCacheIRStub
* stub
) {
321 MOZ_ASSERT(stub
->next() == nullptr);
322 stub
->setNext(icEntry
->firstStub());
323 icEntry
->setFirstStub(stub
);
324 state_
.trackAttached();
327 AllocatableGeneralRegisterSet
BaselineICAvailableGeneralRegs(size_t numInputs
);
329 bool ICSupportsPolymorphicTypeData(JSOp op
);
331 struct IonOsrTempData
;
333 extern bool DoCallFallback(JSContext
* cx
, BaselineFrame
* frame
,
334 ICFallbackStub
* stub
, uint32_t argc
, Value
* vp
,
335 MutableHandleValue res
);
337 extern bool DoSpreadCallFallback(JSContext
* cx
, BaselineFrame
* frame
,
338 ICFallbackStub
* stub
, Value
* vp
,
339 MutableHandleValue res
);
341 extern bool DoToBoolFallback(JSContext
* cx
, BaselineFrame
* frame
,
342 ICFallbackStub
* stub
, HandleValue arg
,
343 MutableHandleValue ret
);
345 extern bool DoGetElemSuperFallback(JSContext
* cx
, BaselineFrame
* frame
,
346 ICFallbackStub
* stub
, HandleValue lhs
,
347 HandleValue rhs
, HandleValue receiver
,
348 MutableHandleValue res
);
350 extern bool DoGetElemFallback(JSContext
* cx
, BaselineFrame
* frame
,
351 ICFallbackStub
* stub
, HandleValue lhs
,
352 HandleValue rhs
, MutableHandleValue res
);
354 extern bool DoSetElemFallback(JSContext
* cx
, BaselineFrame
* frame
,
355 ICFallbackStub
* stub
, Value
* stack
,
356 HandleValue objv
, HandleValue index
,
359 extern bool DoInFallback(JSContext
* cx
, BaselineFrame
* frame
,
360 ICFallbackStub
* stub
, HandleValue key
,
361 HandleValue objValue
, MutableHandleValue res
);
363 extern bool DoHasOwnFallback(JSContext
* cx
, BaselineFrame
* frame
,
364 ICFallbackStub
* stub
, HandleValue keyValue
,
365 HandleValue objValue
, MutableHandleValue res
);
367 extern bool DoCheckPrivateFieldFallback(JSContext
* cx
, BaselineFrame
* frame
,
368 ICFallbackStub
* stub
,
369 HandleValue objValue
,
370 HandleValue keyValue
,
371 MutableHandleValue res
);
373 extern bool DoGetNameFallback(JSContext
* cx
, BaselineFrame
* frame
,
374 ICFallbackStub
* stub
, HandleObject envChain
,
375 MutableHandleValue res
);
377 extern bool DoBindNameFallback(JSContext
* cx
, BaselineFrame
* frame
,
378 ICFallbackStub
* stub
, HandleObject envChain
,
379 MutableHandleValue res
);
381 extern bool DoGetIntrinsicFallback(JSContext
* cx
, BaselineFrame
* frame
,
382 ICFallbackStub
* stub
,
383 MutableHandleValue res
);
385 extern bool DoGetPropFallback(JSContext
* cx
, BaselineFrame
* frame
,
386 ICFallbackStub
* stub
, MutableHandleValue val
,
387 MutableHandleValue res
);
389 extern bool DoGetPropSuperFallback(JSContext
* cx
, BaselineFrame
* frame
,
390 ICFallbackStub
* stub
, HandleValue receiver
,
391 MutableHandleValue val
,
392 MutableHandleValue res
);
394 extern bool DoSetPropFallback(JSContext
* cx
, BaselineFrame
* frame
,
395 ICFallbackStub
* stub
, Value
* stack
,
396 HandleValue lhs
, HandleValue rhs
);
398 extern bool DoGetIteratorFallback(JSContext
* cx
, BaselineFrame
* frame
,
399 ICFallbackStub
* stub
, HandleValue value
,
400 MutableHandleValue res
);
402 extern bool DoOptimizeSpreadCallFallback(JSContext
* cx
, BaselineFrame
* frame
,
403 ICFallbackStub
* stub
,
405 MutableHandleValue res
);
407 extern bool DoInstanceOfFallback(JSContext
* cx
, BaselineFrame
* frame
,
408 ICFallbackStub
* stub
, HandleValue lhs
,
409 HandleValue rhs
, MutableHandleValue res
);
411 extern bool DoTypeOfFallback(JSContext
* cx
, BaselineFrame
* frame
,
412 ICFallbackStub
* stub
, HandleValue val
,
413 MutableHandleValue res
);
415 extern bool DoToPropertyKeyFallback(JSContext
* cx
, BaselineFrame
* frame
,
416 ICFallbackStub
* stub
, HandleValue val
,
417 MutableHandleValue res
);
419 extern bool DoRestFallback(JSContext
* cx
, BaselineFrame
* frame
,
420 ICFallbackStub
* stub
, MutableHandleValue res
);
422 extern bool DoUnaryArithFallback(JSContext
* cx
, BaselineFrame
* frame
,
423 ICFallbackStub
* stub
, HandleValue val
,
424 MutableHandleValue res
);
426 extern bool DoBinaryArithFallback(JSContext
* cx
, BaselineFrame
* frame
,
427 ICFallbackStub
* stub
, HandleValue lhs
,
428 HandleValue rhs
, MutableHandleValue ret
);
430 extern bool DoNewArrayFallback(JSContext
* cx
, BaselineFrame
* frame
,
431 ICFallbackStub
* stub
, MutableHandleValue res
);
433 extern bool DoNewObjectFallback(JSContext
* cx
, BaselineFrame
* frame
,
434 ICFallbackStub
* stub
, MutableHandleValue res
);
436 extern bool DoCompareFallback(JSContext
* cx
, BaselineFrame
* frame
,
437 ICFallbackStub
* stub
, HandleValue lhs
,
438 HandleValue rhs
, MutableHandleValue ret
);
440 extern bool DoCloseIterFallback(JSContext
* cx
, BaselineFrame
* frame
,
441 ICFallbackStub
* stub
, HandleObject iter
);
443 extern bool DoOptimizeGetIteratorFallback(JSContext
* cx
, BaselineFrame
* frame
,
444 ICFallbackStub
* stub
,
446 MutableHandleValue res
);
451 #endif /* jit_BaselineIC_h */