Bug 1837620 - Part 1: Remove baseline ICs that guard shapes when the shape becomes...
[gecko.git] / js / src / jit / BaselineIC.h
blobc38930ca42dfa9bd4a321ca67521c256fe4de96c
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"
13 #include <stddef.h>
14 #include <stdint.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;
26 namespace js {
28 MOZ_COLD void ReportOutOfMemory(JSContext* cx);
30 namespace jit {
32 class BaselineFrame;
33 class CacheIRStubInfo;
34 class ICScript;
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.
56 // A diagram:
58 // Control flow Pointers
59 // =======# ----. .---->
60 // # | |
61 // #======> \-----/
64 // .---------------------------------------.
65 // | .-------------------------. |
66 // | | .----. | |
67 // Baseline | | | | | |
68 // JIT Code 0 ^ 1 ^ 2 ^ | | |
69 // +--------------+ .-->+-----+ +-----+ +-----+ | | |
70 // | | #=|==>| |==>| |==>| FB | | | |
71 // | | # | +-----+ +-----+ +-----+ | | |
72 // | | # | # # # | | |
73 // |==============|==# | # # # | | |
74 // |=== IC =======| | # # # | | |
75 // .->|==============|<===|======#=========#=========# | | |
76 // | | | | | | |
77 // | | | | | | |
78 // | | | | | | |
79 // | | | | v | |
80 // | | | | +---------+ | |
81 // | | | | | Fallback| | |
82 // | | | | | Stub | | |
83 // | | | | | Code | | |
84 // | | | | +---------+ | |
85 // | +--------------+ | | |
86 // | |_______ | +---------+ | |
87 // | | | | Stub |<---/ |
88 // | IC | \--. | Code | |
89 // | Descriptor | | +---------+ |
90 // | Table v | |
91 // | +-----------------+ | +---------+ |
92 // \--| Ins | PC | Stub |----/ | Stub |<-------/
93 // +-----------------+ | Code |
94 // | ... | +---------+
95 // +-----------------+
96 // Shared
97 // Stub Code
100 class ICStub;
101 class ICCacheIRStub;
102 class ICFallbackStub;
104 #ifdef JS_JITSPEW
105 void FallbackICSpew(JSContext* cx, ICFallbackStub* stub, const char* fmt, ...)
106 MOZ_FORMAT_PRINTF(3, 4);
107 #else
108 # define FallbackICSpew(...)
109 #endif
111 // An entry in the ICScript IC table. There's one ICEntry per IC.
112 class ICEntry {
113 // A pointer to the first IC stub for this instruction.
114 ICStub* firstStub_;
116 public:
117 explicit ICEntry(ICStub* firstStub) : firstStub_(firstStub) {}
119 ICStub* firstStub() const {
120 MOZ_ASSERT(firstStub_);
121 return 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.
137 class ICStub {
138 friend class ICFallbackStub;
140 protected:
141 // The raw jitcode to call for this stub.
142 uint8_t* stubCode_;
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
152 // padding bytes.
153 TypeData typeData_;
155 // Whether this is an ICFallbackStub or an ICCacheIRStub.
156 bool isFallback_;
158 ICStub(uint8_t* stubCode, bool isFallback)
159 : stubCode_(stubCode), isFallback_(isFallback) {
160 MOZ_ASSERT(stubCode != nullptr);
163 public:
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.
190 return isFallback();
192 JitCode* jitCode() {
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;
212 protected:
213 // The PC offset of this IC's bytecode op within the JSScript.
214 uint32_t pcOffset_;
216 // The state of this IC.
217 ICState state_{};
219 public:
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_;
265 #ifndef JS_64BIT
266 // Ensure stub data is 8-byte aligned on 32-bit.
267 uintptr_t padding_ = 0;
268 #endif
270 public:
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.
304 #ifdef JS_64BIT
305 static_assert(sizeof(ICFallbackStub) == 3 * sizeof(uintptr_t));
306 static_assert(sizeof(ICCacheIRStub) == 4 * sizeof(uintptr_t));
307 #else
308 static_assert(sizeof(ICFallbackStub) == 5 * sizeof(uintptr_t));
309 static_assert(sizeof(ICCacheIRStub) == 6 * sizeof(uintptr_t));
310 #endif
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,
353 HandleValue rhs);
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,
400 HandleValue value,
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);
439 } // namespace jit
440 } // namespace js
442 #endif /* jit_BaselineIC_h */