Bug 1867190 - Add prefs for PHC probablities r=glandium
[gecko.git] / js / src / jit / IonTypes.h
blobcbe60ecf28095a2646f2f1a951f8a30d317183b2
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_IonTypes_h
8 #define jit_IonTypes_h
10 #include "mozilla/HashFunctions.h"
12 #include <algorithm>
13 #include <stdint.h>
15 #include "jstypes.h"
16 #include "NamespaceImports.h"
18 #include "jit/ABIFunctionType.h"
20 #include "js/ScalarType.h" // js::Scalar::Type
21 #include "js/Value.h"
23 namespace js {
25 // Each IonScript has a unique compilation id. This is used to sweep/ignore
26 // constraints for IonScripts that have been invalidated/destroyed.
27 class IonCompilationId {
28 // Use two 32-bit integers instead of uint64_t to avoid 8-byte alignment on
29 // some 32-bit platforms.
30 uint32_t idLo_;
31 uint32_t idHi_;
33 public:
34 explicit IonCompilationId(uint64_t id)
35 : idLo_(id & UINT32_MAX), idHi_(id >> 32) {}
36 bool operator==(const IonCompilationId& other) const {
37 return idLo_ == other.idLo_ && idHi_ == other.idHi_;
39 bool operator!=(const IonCompilationId& other) const {
40 return !operator==(other);
44 namespace jit {
46 using RecoverOffset = uint32_t;
47 using SnapshotOffset = uint32_t;
49 // The maximum size of any buffer associated with an assembler or code object.
50 // This is chosen to not overflow a signed integer, leaving room for an extra
51 // bit on offsets.
52 static const uint32_t MAX_BUFFER_SIZE = (1 << 30) - 1;
54 // Maximum number of scripted arg slots.
55 static const uint32_t SNAPSHOT_MAX_NARGS = 127;
57 static const SnapshotOffset INVALID_RECOVER_OFFSET = uint32_t(-1);
58 static const SnapshotOffset INVALID_SNAPSHOT_OFFSET = uint32_t(-1);
61 * [SMDOC] Avoiding repeated bailouts / invalidations
63 * To avoid getting trapped in a "compilation -> bailout -> invalidation ->
64 * recompilation -> bailout -> invalidation -> ..." loop, every snapshot in
65 * Warp code is assigned a BailoutKind. If we bail out at that snapshot,
66 * FinishBailoutToBaseline will examine the BailoutKind and take appropriate
67 * action. In general:
69 * 1. If the bailing instruction comes from transpiled CacheIR, then when we
70 * bail out and continue execution in the baseline interpreter, the
71 * corresponding stub should fail a guard. As a result, we will either
72 * increment the enteredCount for a subsequent stub or attach a new stub,
73 * either of which will prevent WarpOracle from transpiling the failing stub
74 * when we recompile.
76 * Note: this means that every CacheIR op that can bail out in Warp must
77 * have an equivalent guard in the baseline CacheIR implementation.
79 * FirstExecution works according to the same principles: we have never hit
80 * this IC before, but after we bail to baseline we will attach a stub and
81 * recompile with better CacheIR information.
83 * 2. If the bailout occurs because an assumption we made in WarpBuilder was
84 * invalidated, then FinishBailoutToBaseline will set a flag on the script
85 * to avoid that assumption in the future: for example, UninitializedLexical.
87 * 3. Similarly, if the bailing instruction is generated or modified by a MIR
88 * optimization, then FinishBailoutToBaseline will set a flag on the script
89 * to make that optimization more conservative in the future. Examples
90 * include LICM, EagerTruncation, and HoistBoundsCheck.
92 * 4. Some bailouts can't be handled in Warp, even after a recompile. For
93 * example, Warp does not support catching exceptions. If this happens
94 * too often, then the cost of bailing out repeatedly outweighs the
95 * benefit of Warp compilation, so we invalidate the script and disable
96 * Warp compilation.
98 * 5. Some bailouts don't happen in performance-sensitive code: for example,
99 * the |debugger| statement. We just ignore those.
101 enum class BailoutKind : uint8_t {
102 Unknown,
104 // An instruction generated by the transpiler. If this instruction bails out,
105 // attaching a new stub in baseline will invalidate the current Warp script
106 // and avoid a bailout loop.
107 TranspiledCacheIR,
109 // An instruction generated by stub folding which has been transpiled into
110 // a monomorphic-inlined script. If this instruction bails out, we will
111 // return to baseline and see if we add a new case to the folded stub. If
112 // we do, this should not count as a bailout for the purpose of eventually
113 // invalidating this script. Because the script containing the folded stub
114 // was inlined monomorphically, there's no direct connection between the
115 // inner script and the outer script. We store the inner and outer scripts
116 // so that we know which outer script to notify if we successfully add a
117 // new case to the folded stub.
118 MonomorphicInlinedStubFolding,
120 // An optimistic unbox on the cold path for a non-Value phi failed. If this
121 // instruction bails out, we will invalidate the script and mark the
122 // HadSpeculativePhiBailout flag on the script.
123 SpeculativePhi,
125 // A conversion inserted by a type policy. If this instruction bails out,
126 // we expect to throw an error. If this happens too frequently, we will
127 // invalidate the current Warp script and disable recompilation.
128 TypePolicy,
130 // An instruction hoisted by LICM. If this instruction bails out, we will
131 // bail out to baseline to see if we attach a new stub. If we do, then the
132 // more than once, we will invalidate the current Warp script and
133 // mark the hadLICMInvalidation flag on the script.
134 LICM,
136 // An instruction moved up by InstructionReordering. If this
137 // instruction bails out, we will mark the ReorderingBailout flag on
138 // the script. If this happens too frequently, we will invalidate
139 // the script.
140 InstructionReordering,
142 // An instruction created or hoisted by tryHoistBoundsCheck.
143 // If this instruction bails out, we will invalidate the current Warp script
144 // and mark the HoistBoundsCheckBailout flag on the script.
145 HoistBoundsCheck,
147 // An eager truncation generated by range analysis.
148 // If this instruction bails out, we will invalidate the current Warp script
149 // and mark the EagerTruncationBailout flag on the script.
150 EagerTruncation,
152 // A folded unbox instruction generated by FoldLoadsWithUnbox.
153 // If this instruction bails out, we will invalidate the current Warp script
154 // and mark the UnboxFoldingBailout flag on the script.
155 UnboxFolding,
157 // An inevitable bailout (MBail instruction or type barrier that always bails)
158 Inevitable,
160 // Bailing out during a VM call. Many possible causes that are hard
161 // to distinguish statically at snapshot construction time.
162 // We just lump them together.
163 DuringVMCall,
165 // A spread call or funapply had more than JIT_ARGS_LENGTH_MAX arguments.
166 // We bail out to handle this in the VM. If this happens too frequently,
167 // we will invalidate the current Warp script and disable recompilation.
168 TooManyArguments,
170 // We hit an active |debugger;| statement.
171 Debugger,
173 // We hit this code for the first time.
174 FirstExecution,
176 // A lexical check failed. We will set lexical checks as unmovable.
177 UninitializedLexical,
179 // A bailout to baseline from Ion on exception to handle Debugger hooks.
180 IonExceptionDebugMode,
182 // A bailout to baseline from Ion on exception to handle a finally block.
183 Finally,
185 // We returned to a stack frame after invalidating its IonScript.
186 OnStackInvalidation,
188 // We returned to a stack frame while calling the |return| method of an
189 // iterator, and we have to throw an exception because the return value
190 // was not an object.
191 ThrowCheckIsObject,
193 // These two are similar to ThrowCheckIsObject. We have to throw an exception
194 // because the result of a Proxy get trap didn't match the requirements.
195 ThrowProxyTrapMustReportSameValue,
196 ThrowProxyTrapMustReportUndefined,
198 // We have executed code that should be unreachable, and need to assert.
199 Unreachable,
201 Limit
204 inline const char* BailoutKindString(BailoutKind kind) {
205 switch (kind) {
206 case BailoutKind::Unknown:
207 return "Unknown";
208 case BailoutKind::TranspiledCacheIR:
209 return "TranspiledCacheIR";
210 case BailoutKind::MonomorphicInlinedStubFolding:
211 return "MonomorphicInlinedStubFolding";
212 case BailoutKind::SpeculativePhi:
213 return "SpeculativePhi";
214 case BailoutKind::TypePolicy:
215 return "TypePolicy";
216 case BailoutKind::LICM:
217 return "LICM";
218 case BailoutKind::InstructionReordering:
219 return "InstructionReordering";
220 case BailoutKind::HoistBoundsCheck:
221 return "HoistBoundsCheck";
222 case BailoutKind::EagerTruncation:
223 return "EagerTruncation";
224 case BailoutKind::UnboxFolding:
225 return "UnboxFolding";
226 case BailoutKind::Inevitable:
227 return "Inevitable";
228 case BailoutKind::DuringVMCall:
229 return "DuringVMCall";
230 case BailoutKind::TooManyArguments:
231 return "TooManyArguments";
232 case BailoutKind::Debugger:
233 return "Debugger";
234 case BailoutKind::FirstExecution:
235 return "FirstExecution";
236 case BailoutKind::UninitializedLexical:
237 return "UninitializedLexical";
238 case BailoutKind::IonExceptionDebugMode:
239 return "IonExceptionDebugMode";
240 case BailoutKind::Finally:
241 return "Finally";
242 case BailoutKind::OnStackInvalidation:
243 return "OnStackInvalidation";
244 case BailoutKind::ThrowCheckIsObject:
245 return "ThrowCheckIsObject";
246 case BailoutKind::ThrowProxyTrapMustReportSameValue:
247 return "ThrowProxyTrapMustReportSameValue";
248 case BailoutKind::ThrowProxyTrapMustReportUndefined:
249 return "ThrowProxyTrapMustReportUndefined";
250 case BailoutKind::Unreachable:
251 return "Unreachable";
253 case BailoutKind::Limit:
254 break;
257 MOZ_CRASH("Invalid BailoutKind");
260 static const uint32_t ELEMENT_TYPE_BITS = 5;
261 static const uint32_t ELEMENT_TYPE_SHIFT = 0;
262 static const uint32_t ELEMENT_TYPE_MASK = (1 << ELEMENT_TYPE_BITS) - 1;
263 static const uint32_t VECTOR_TYPE_BITS = 1;
264 static const uint32_t VECTOR_TYPE_SHIFT =
265 ELEMENT_TYPE_BITS + ELEMENT_TYPE_SHIFT;
266 static const uint32_t VECTOR_TYPE_MASK = (1 << VECTOR_TYPE_BITS) - 1;
268 // The integer SIMD types have a lot of operations that do the exact same thing
269 // for signed and unsigned integer types. Sometimes it is simpler to treat
270 // signed and unsigned integer SIMD types as the same type, using a SimdSign to
271 // distinguish the few cases where there is a difference.
272 enum class SimdSign {
273 // Signedness is not applicable to this type. (i.e., Float or Bool).
274 NotApplicable,
275 // Treat as an unsigned integer with a range 0 .. 2^N-1.
276 Unsigned,
277 // Treat as a signed integer in two's complement encoding.
278 Signed,
281 class SimdConstant {
282 public:
283 enum Type {
284 Int8x16,
285 Int16x8,
286 Int32x4,
287 Int64x2,
288 Float32x4,
289 Float64x2,
290 Undefined = -1
293 typedef int8_t I8x16[16];
294 typedef int16_t I16x8[8];
295 typedef int32_t I32x4[4];
296 typedef int64_t I64x2[2];
297 typedef float F32x4[4];
298 typedef double F64x2[2];
300 private:
301 Type type_;
302 union {
303 I8x16 i8x16;
304 I16x8 i16x8;
305 I32x4 i32x4;
306 I64x2 i64x2;
307 F32x4 f32x4;
308 F64x2 f64x2;
309 } u;
311 bool defined() const { return type_ != Undefined; }
313 public:
314 // Doesn't have a default constructor, as it would prevent it from being
315 // included in unions.
317 static SimdConstant CreateX16(const int8_t* array) {
318 SimdConstant cst;
319 cst.type_ = Int8x16;
320 memcpy(cst.u.i8x16, array, sizeof(cst.u));
321 return cst;
323 static SimdConstant SplatX16(int8_t v) {
324 SimdConstant cst;
325 cst.type_ = Int8x16;
326 std::fill_n(cst.u.i8x16, 16, v);
327 return cst;
329 static SimdConstant CreateX8(const int16_t* array) {
330 SimdConstant cst;
331 cst.type_ = Int16x8;
332 memcpy(cst.u.i16x8, array, sizeof(cst.u));
333 return cst;
335 static SimdConstant SplatX8(int16_t v) {
336 SimdConstant cst;
337 cst.type_ = Int16x8;
338 std::fill_n(cst.u.i16x8, 8, v);
339 return cst;
341 static SimdConstant CreateX4(const int32_t* array) {
342 SimdConstant cst;
343 cst.type_ = Int32x4;
344 memcpy(cst.u.i32x4, array, sizeof(cst.u));
345 return cst;
347 static SimdConstant SplatX4(int32_t v) {
348 SimdConstant cst;
349 cst.type_ = Int32x4;
350 std::fill_n(cst.u.i32x4, 4, v);
351 return cst;
353 static SimdConstant CreateX2(const int64_t* array) {
354 SimdConstant cst;
355 cst.type_ = Int64x2;
356 memcpy(cst.u.i64x2, array, sizeof(cst.u));
357 return cst;
359 static SimdConstant SplatX2(int64_t v) {
360 SimdConstant cst;
361 cst.type_ = Int64x2;
362 std::fill_n(cst.u.i64x2, 2, v);
363 return cst;
365 static SimdConstant CreateX4(const float* array) {
366 SimdConstant cst;
367 cst.type_ = Float32x4;
368 memcpy(cst.u.f32x4, array, sizeof(cst.u));
369 return cst;
371 static SimdConstant SplatX4(float v) {
372 SimdConstant cst;
373 cst.type_ = Float32x4;
374 std::fill_n(cst.u.f32x4, 4, v);
375 return cst;
377 static SimdConstant CreateX2(const double* array) {
378 SimdConstant cst;
379 cst.type_ = Float64x2;
380 memcpy(cst.u.f64x2, array, sizeof(cst.u));
381 return cst;
383 static SimdConstant SplatX2(double v) {
384 SimdConstant cst;
385 cst.type_ = Float64x2;
386 std::fill_n(cst.u.f64x2, 2, v);
387 return cst;
390 // Overloads for use by templates.
391 static SimdConstant CreateSimd128(const int8_t* array) {
392 return CreateX16(array);
394 static SimdConstant CreateSimd128(const int16_t* array) {
395 return CreateX8(array);
397 static SimdConstant CreateSimd128(const int32_t* array) {
398 return CreateX4(array);
400 static SimdConstant CreateSimd128(const int64_t* array) {
401 return CreateX2(array);
403 static SimdConstant CreateSimd128(const float* array) {
404 return CreateX4(array);
406 static SimdConstant CreateSimd128(const double* array) {
407 return CreateX2(array);
410 Type type() const {
411 MOZ_ASSERT(defined());
412 return type_;
415 bool isFloatingType() const {
416 MOZ_ASSERT(defined());
417 return type_ >= Float32x4;
420 bool isIntegerType() const {
421 MOZ_ASSERT(defined());
422 return type_ <= Int64x2;
425 // Get the raw bytes of the constant.
426 const void* bytes() const { return u.i8x16; }
428 const I8x16& asInt8x16() const {
429 MOZ_ASSERT(defined() && type_ == Int8x16);
430 return u.i8x16;
433 const I16x8& asInt16x8() const {
434 MOZ_ASSERT(defined() && type_ == Int16x8);
435 return u.i16x8;
438 const I32x4& asInt32x4() const {
439 MOZ_ASSERT(defined() && type_ == Int32x4);
440 return u.i32x4;
443 const I64x2& asInt64x2() const {
444 MOZ_ASSERT(defined() && type_ == Int64x2);
445 return u.i64x2;
448 const F32x4& asFloat32x4() const {
449 MOZ_ASSERT(defined() && type_ == Float32x4);
450 return u.f32x4;
453 const F64x2& asFloat64x2() const {
454 MOZ_ASSERT(defined() && type_ == Float64x2);
455 return u.f64x2;
458 bool bitwiseEqual(const SimdConstant& rhs) const {
459 MOZ_ASSERT(defined() && rhs.defined());
460 return memcmp(&u, &rhs.u, sizeof(u)) == 0;
463 bool isZeroBits() const {
464 MOZ_ASSERT(defined());
465 return u.i64x2[0] == 0 && u.i64x2[1] == 0;
468 bool isOneBits() const {
469 MOZ_ASSERT(defined());
470 return ~u.i64x2[0] == 0 && ~u.i64x2[1] == 0;
473 // SimdConstant is a HashPolicy. Currently we discriminate by type, but it
474 // may be that we should only be discriminating by int vs float.
475 using Lookup = SimdConstant;
477 static HashNumber hash(const SimdConstant& val) {
478 uint32_t hash = mozilla::HashBytes(&val.u, sizeof(val.u));
479 return mozilla::AddToHash(hash, val.type_);
482 static bool match(const SimdConstant& lhs, const SimdConstant& rhs) {
483 return lhs.type() == rhs.type() && lhs.bitwiseEqual(rhs);
487 enum class IntConversionBehavior {
488 // These two try to convert the input to an int32 using ToNumber and
489 // will fail if the resulting int32 isn't strictly equal to the input.
490 Normal, // Succeeds on -0: converts to 0.
491 NegativeZeroCheck, // Fails on -0.
492 // These two will convert the input to an int32 with loss of precision.
493 Truncate,
494 ClampToUint8,
497 enum class IntConversionInputKind { NumbersOnly, NumbersOrBoolsOnly, Any };
499 // The ordering of this enumeration is important: Anything < Value is a
500 // specialized type. Furthermore, anything < String has trivial conversion to
501 // a number.
502 enum class MIRType : uint8_t {
503 Undefined,
504 Null,
505 Boolean,
506 Int32,
507 Int64,
508 IntPtr,
509 Double,
510 Float32,
511 // Types above have trivial conversion to a number.
512 String,
513 Symbol,
514 BigInt,
515 Simd128,
516 // Types above are primitive (including undefined and null).
517 Object,
518 MagicOptimizedOut, // JS_OPTIMIZED_OUT magic value.
519 MagicHole, // JS_ELEMENTS_HOLE magic value.
520 MagicIsConstructing, // JS_IS_CONSTRUCTING magic value.
521 MagicUninitializedLexical, // JS_UNINITIALIZED_LEXICAL magic value.
522 // Types above are specialized.
523 Value,
524 None, // Invalid, used as a placeholder.
525 Slots, // A slots vector
526 Elements, // An elements vector
527 Pointer, // An opaque pointer that receives no special treatment
528 WasmAnyRef, // Wasm Ref/AnyRef/NullRef: a raw JSObject* or a raw (void*)0
529 StackResults, // Wasm multi-value stack result area, which may contain refs
530 Shape, // A Shape pointer.
531 Last = Shape
534 static inline MIRType TargetWordMIRType() {
535 #ifdef JS_64BIT
536 return MIRType::Int64;
537 #else
538 return MIRType::Int32;
539 #endif
542 static inline MIRType MIRTypeFromValueType(JSValueType type) {
543 // This function does not deal with magic types. Magic constants should be
544 // filtered out in MIRTypeFromValue.
545 switch (type) {
546 case JSVAL_TYPE_DOUBLE:
547 return MIRType::Double;
548 case JSVAL_TYPE_INT32:
549 return MIRType::Int32;
550 case JSVAL_TYPE_UNDEFINED:
551 return MIRType::Undefined;
552 case JSVAL_TYPE_STRING:
553 return MIRType::String;
554 case JSVAL_TYPE_SYMBOL:
555 return MIRType::Symbol;
556 case JSVAL_TYPE_BIGINT:
557 return MIRType::BigInt;
558 case JSVAL_TYPE_BOOLEAN:
559 return MIRType::Boolean;
560 case JSVAL_TYPE_NULL:
561 return MIRType::Null;
562 case JSVAL_TYPE_OBJECT:
563 return MIRType::Object;
564 case JSVAL_TYPE_UNKNOWN:
565 return MIRType::Value;
566 default:
567 MOZ_CRASH("unexpected jsval type");
571 static inline JSValueType ValueTypeFromMIRType(MIRType type) {
572 switch (type) {
573 case MIRType::Undefined:
574 return JSVAL_TYPE_UNDEFINED;
575 case MIRType::Null:
576 return JSVAL_TYPE_NULL;
577 case MIRType::Boolean:
578 return JSVAL_TYPE_BOOLEAN;
579 case MIRType::Int32:
580 return JSVAL_TYPE_INT32;
581 case MIRType::Float32: // Fall through, there's no JSVAL for Float32
582 case MIRType::Double:
583 return JSVAL_TYPE_DOUBLE;
584 case MIRType::String:
585 return JSVAL_TYPE_STRING;
586 case MIRType::Symbol:
587 return JSVAL_TYPE_SYMBOL;
588 case MIRType::BigInt:
589 return JSVAL_TYPE_BIGINT;
590 case MIRType::MagicOptimizedOut:
591 case MIRType::MagicHole:
592 case MIRType::MagicIsConstructing:
593 case MIRType::MagicUninitializedLexical:
594 return JSVAL_TYPE_MAGIC;
595 default:
596 MOZ_ASSERT(type == MIRType::Object);
597 return JSVAL_TYPE_OBJECT;
601 static inline JSValueTag MIRTypeToTag(MIRType type) {
602 return JSVAL_TYPE_TO_TAG(ValueTypeFromMIRType(type));
605 static inline size_t MIRTypeToSize(MIRType type) {
606 switch (type) {
607 case MIRType::Int32:
608 return 4;
609 case MIRType::Int64:
610 return 8;
611 case MIRType::Float32:
612 return 4;
613 case MIRType::Double:
614 return 8;
615 case MIRType::Simd128:
616 return 16;
617 case MIRType::Pointer:
618 case MIRType::WasmAnyRef:
619 return sizeof(uintptr_t);
620 default:
621 MOZ_CRASH("MIRTypeToSize - unhandled case");
625 static inline const char* StringFromMIRType(MIRType type) {
626 switch (type) {
627 case MIRType::Undefined:
628 return "Undefined";
629 case MIRType::Null:
630 return "Null";
631 case MIRType::Boolean:
632 return "Bool";
633 case MIRType::Int32:
634 return "Int32";
635 case MIRType::Int64:
636 return "Int64";
637 case MIRType::IntPtr:
638 return "IntPtr";
639 case MIRType::Double:
640 return "Double";
641 case MIRType::Float32:
642 return "Float32";
643 case MIRType::String:
644 return "String";
645 case MIRType::Symbol:
646 return "Symbol";
647 case MIRType::BigInt:
648 return "BigInt";
649 case MIRType::Object:
650 return "Object";
651 case MIRType::MagicOptimizedOut:
652 return "MagicOptimizedOut";
653 case MIRType::MagicHole:
654 return "MagicHole";
655 case MIRType::MagicIsConstructing:
656 return "MagicIsConstructing";
657 case MIRType::MagicUninitializedLexical:
658 return "MagicUninitializedLexical";
659 case MIRType::Value:
660 return "Value";
661 case MIRType::None:
662 return "None";
663 case MIRType::Slots:
664 return "Slots";
665 case MIRType::Elements:
666 return "Elements";
667 case MIRType::Pointer:
668 return "Pointer";
669 case MIRType::WasmAnyRef:
670 return "WasmAnyRef";
671 case MIRType::StackResults:
672 return "StackResults";
673 case MIRType::Shape:
674 return "Shape";
675 case MIRType::Simd128:
676 return "Simd128";
678 MOZ_CRASH("Unknown MIRType.");
681 static inline bool IsIntType(MIRType type) {
682 return type == MIRType::Int32 || type == MIRType::Int64;
685 static inline bool IsNumberType(MIRType type) {
686 return type == MIRType::Int32 || type == MIRType::Double ||
687 type == MIRType::Float32 || type == MIRType::Int64;
690 static inline bool IsNumericType(MIRType type) {
691 return IsNumberType(type) || type == MIRType::BigInt;
694 static inline bool IsTypeRepresentableAsDouble(MIRType type) {
695 return type == MIRType::Int32 || type == MIRType::Double ||
696 type == MIRType::Float32;
699 static inline bool IsFloatType(MIRType type) {
700 return type == MIRType::Int32 || type == MIRType::Float32;
703 static inline bool IsFloatingPointType(MIRType type) {
704 return type == MIRType::Double || type == MIRType::Float32;
707 static inline bool IsNullOrUndefined(MIRType type) {
708 return type == MIRType::Null || type == MIRType::Undefined;
711 static inline bool IsMagicType(MIRType type) {
712 return type == MIRType::MagicHole || type == MIRType::MagicOptimizedOut ||
713 type == MIRType::MagicIsConstructing ||
714 type == MIRType::MagicUninitializedLexical;
717 static inline bool IsNonGCThing(MIRType type) {
718 return type == MIRType::Undefined || type == MIRType::Null ||
719 type == MIRType::Boolean || IsNumberType(type);
722 static inline MIRType ScalarTypeToMIRType(Scalar::Type type) {
723 switch (type) {
724 case Scalar::Int8:
725 case Scalar::Uint8:
726 case Scalar::Int16:
727 case Scalar::Uint16:
728 case Scalar::Int32:
729 case Scalar::Uint32:
730 case Scalar::Uint8Clamped:
731 return MIRType::Int32;
732 case Scalar::Int64:
733 return MIRType::Int64;
734 case Scalar::Float32:
735 return MIRType::Float32;
736 case Scalar::Float64:
737 return MIRType::Double;
738 case Scalar::BigInt64:
739 case Scalar::BigUint64:
740 MOZ_CRASH("NYI");
741 case Scalar::Simd128:
742 return MIRType::Simd128;
743 case Scalar::MaxTypedArrayViewType:
744 break;
746 MOZ_CRASH("unexpected kind");
749 static constexpr bool NeedsPostBarrier(MIRType type) {
750 MOZ_ASSERT(type != MIRType::Value);
751 return type == MIRType::Object || type == MIRType::String ||
752 type == MIRType::BigInt;
755 #ifdef DEBUG
757 // Track the pipeline of opcodes which has produced a snapshot.
758 # define TRACK_SNAPSHOTS 1
760 // Make sure registers are not modified between an instruction and
761 // its OsiPoint.
762 # define CHECK_OSIPOINT_REGISTERS 1
764 #endif // DEBUG
766 // Rounding modes for round instructions.
767 enum class RoundingMode { Down, Up, NearestTiesToEven, TowardsZero };
769 // If a function contains no calls, we can assume the caller has checked the
770 // stack limit up to this maximum frame size. This works because the jit stack
771 // limit has a generous buffer before the real end of the native stack.
772 static const uint32_t MAX_UNCHECKED_LEAF_FRAME_SIZE = 64;
774 // Truncating conversion modifiers.
775 using TruncFlags = uint32_t;
776 static const TruncFlags TRUNC_UNSIGNED = TruncFlags(1) << 0;
777 static const TruncFlags TRUNC_SATURATING = TruncFlags(1) << 1;
779 enum BranchDirection { FALSE_BRANCH, TRUE_BRANCH };
781 template <typename T>
782 constexpr T SplatByteToUInt(uint8_t val, uint8_t x) {
783 T splatted = val;
784 for (; x > 1; x--) {
785 splatted |= splatted << 8;
787 return splatted;
790 // Resume information for a frame, stored in a resume point.
791 enum class ResumeMode : uint8_t {
792 // Innermost frame. Resume at the next bytecode op when bailing out.
793 ResumeAfter,
795 // Innermost frame. This resume point captures an additional value
796 // that is not on the expression stack. Resume at the next bytecode
797 // op when bailing out, but first check that the intermediate value
798 // is an object. This is used if calling the |return| method for a
799 // CloseIter causes an invalidation bailout.
800 ResumeAfterCheckIsObject,
802 // Similar to ResumeAfterCheckIsObject, but we must check that the result
803 // of a proxy get trap aligns with what the spec requires.
804 ResumeAfterCheckProxyGetResult,
806 // Innermost frame. Resume at the current bytecode op when bailing out.
807 ResumeAt,
809 // Outer frame for an inlined "standard" call at an IsInvokeOp bytecode op.
810 InlinedStandardCall,
812 // Outer frame for an inlined js::fun_call at an IsInvokeOp bytecode op.
813 InlinedFunCall,
815 // Outer frame for an inlined getter/setter at a Get*/Set* bytecode op.
816 InlinedAccessor,
818 Last = InlinedAccessor
821 inline const char* ResumeModeToString(ResumeMode mode) {
822 switch (mode) {
823 case ResumeMode::ResumeAfter:
824 return "ResumeAfter";
825 case ResumeMode::ResumeAt:
826 return "ResumeAt";
827 case ResumeMode::InlinedStandardCall:
828 return "InlinedStandardCall";
829 case ResumeMode::InlinedFunCall:
830 return "InlinedFunCall";
831 case ResumeMode::InlinedAccessor:
832 return "InlinedAccessor";
833 case ResumeMode::ResumeAfterCheckIsObject:
834 return "ResumeAfterCheckIsObject";
835 case ResumeMode::ResumeAfterCheckProxyGetResult:
836 return "ResumeAfterCheckProxyGetResult";
838 MOZ_CRASH("Invalid mode");
841 inline bool IsResumeAfter(ResumeMode mode) {
842 switch (mode) {
843 case ResumeMode::ResumeAfter:
844 case ResumeMode::ResumeAfterCheckIsObject:
845 case ResumeMode::ResumeAfterCheckProxyGetResult:
846 return true;
847 default:
848 return false;
852 // The number of intermediate values captured by this resume point
853 // that aren't on the expression stack, but are needed during bailouts.
854 inline uint32_t NumIntermediateValues(ResumeMode mode) {
855 switch (mode) {
856 case ResumeMode::ResumeAfterCheckProxyGetResult:
857 return 2;
858 case ResumeMode::ResumeAfterCheckIsObject:
859 return 1;
860 default:
861 return 0;
865 } // namespace jit
866 } // namespace js
868 #endif /* jit_IonTypes_h */