Bug 1874684 - Part 31: Correctly reject invalid durations in some RoundDuration calls...
[gecko.git] / js / src / jit / BaselineIC.h
blob560955e27a0464bdb8065d150c7f48d74e790fc5
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;
35 class ICStubSpace;
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.
57 // A diagram:
59 // Control flow Pointers
60 // =======# ----. .---->
61 // # | |
62 // #======> \-----/
65 // .---------------------------------------.
66 // | .-------------------------. |
67 // | | .----. | |
68 // Baseline | | | | | |
69 // JIT Code 0 ^ 1 ^ 2 ^ | | |
70 // +--------------+ .-->+-----+ +-----+ +-----+ | | |
71 // | | #=|==>| |==>| |==>| FB | | | |
72 // | | # | +-----+ +-----+ +-----+ | | |
73 // | | # | # # # | | |
74 // |==============|==# | # # # | | |
75 // |=== IC =======| | # # # | | |
76 // .->|==============|<===|======#=========#=========# | | |
77 // | | | | | | |
78 // | | | | | | |
79 // | | | | | | |
80 // | | | | v | |
81 // | | | | +---------+ | |
82 // | | | | | Fallback| | |
83 // | | | | | Stub | | |
84 // | | | | | Code | | |
85 // | | | | +---------+ | |
86 // | +--------------+ | | |
87 // | |_______ | +---------+ | |
88 // | | | | Stub |<---/ |
89 // | IC | \--. | Code | |
90 // | Descriptor | | +---------+ |
91 // | Table v | |
92 // | +-----------------+ | +---------+ |
93 // \--| Ins | PC | Stub |----/ | Stub |<-------/
94 // +-----------------+ | Code |
95 // | ... | +---------+
96 // +-----------------+
97 // Shared
98 // Stub Code
101 class ICStub;
102 class ICCacheIRStub;
103 class ICFallbackStub;
105 #ifdef JS_JITSPEW
106 void FallbackICSpew(JSContext* cx, ICFallbackStub* stub, const char* fmt, ...)
107 MOZ_FORMAT_PRINTF(3, 4);
108 #else
109 # define FallbackICSpew(...)
110 #endif
112 // An entry in the ICScript IC table. There's one ICEntry per IC.
113 class ICEntry {
114 // A pointer to the first IC stub for this instruction.
115 ICStub* firstStub_;
117 public:
118 explicit ICEntry(ICStub* firstStub) : firstStub_(firstStub) {}
120 ICStub* firstStub() const {
121 MOZ_ASSERT(firstStub_);
122 return 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.
138 class ICStub {
139 friend class ICFallbackStub;
141 protected:
142 // The raw jitcode to call for this stub.
143 uint8_t* stubCode_;
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
153 // padding bytes.
154 TypeData typeData_;
156 // Whether this is an ICFallbackStub or an ICCacheIRStub.
157 bool isFallback_;
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
166 public:
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.
193 return isFallback();
195 JitCode* jitCode() {
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;
216 protected:
217 // The PC offset of this IC's bytecode op within the JSScript.
218 uint32_t pcOffset_;
220 // The state of this IC.
221 ICState state_{};
223 public:
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_;
269 #ifndef JS_64BIT
270 // Ensure stub data is 8-byte aligned on 32-bit.
271 uintptr_t padding_ = 0;
272 #endif
274 public:
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.
308 #ifdef JS_64BIT
309 static_assert(sizeof(ICFallbackStub) == 3 * sizeof(uintptr_t));
310 static_assert(sizeof(ICCacheIRStub) == 4 * sizeof(uintptr_t));
311 #else
312 static_assert(sizeof(ICFallbackStub) == 5 * sizeof(uintptr_t));
313 static_assert(sizeof(ICCacheIRStub) == 6 * sizeof(uintptr_t));
314 #endif
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,
357 HandleValue rhs);
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,
404 HandleValue value,
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,
445 HandleValue value,
446 MutableHandleValue res);
448 } // namespace jit
449 } // namespace js
451 #endif /* jit_BaselineIC_h */