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/. */
6 
7 #ifndef jit_IonTypes_h
8 #define jit_IonTypes_h
9 
10 #include "mozilla/HashFunctions.h"
11 
12 #include <algorithm>
13 #include <initializer_list>
14 #include <stdint.h>
15 
16 #include "jstypes.h"
17 
18 #include "js/ScalarType.h"  // js::Scalar::Type
19 #include "js/Value.h"
20 
21 namespace js {
22 
23 // Each IonScript has a unique compilation id. This is used to sweep/ignore
24 // constraints for IonScripts that have been invalidated/destroyed.
25 class IonCompilationId {
26   // Use two 32-bit integers instead of uint64_t to avoid 8-byte alignment on
27   // some 32-bit platforms.
28   uint32_t idLo_;
29   uint32_t idHi_;
30 
31  public:
IonCompilationId(uint64_t id)32   explicit IonCompilationId(uint64_t id)
33       : idLo_(id & UINT32_MAX), idHi_(id >> 32) {}
34   bool operator==(const IonCompilationId& other) const {
35     return idLo_ == other.idLo_ && idHi_ == other.idHi_;
36   }
37   bool operator!=(const IonCompilationId& other) const {
38     return !operator==(other);
39   }
40 };
41 
42 namespace jit {
43 
44 using RecoverOffset = uint32_t;
45 using SnapshotOffset = uint32_t;
46 using BailoutId = uint32_t;
47 
48 // The maximum size of any buffer associated with an assembler or code object.
49 // This is chosen to not overflow a signed integer, leaving room for an extra
50 // bit on offsets.
51 static const uint32_t MAX_BUFFER_SIZE = (1 << 30) - 1;
52 
53 // Maximum number of scripted arg slots.
54 static const uint32_t SNAPSHOT_MAX_NARGS = 127;
55 
56 static const SnapshotOffset INVALID_RECOVER_OFFSET = uint32_t(-1);
57 static const SnapshotOffset INVALID_SNAPSHOT_OFFSET = uint32_t(-1);
58 
59 /*
60  * [SMDOC] Avoiding repeated bailouts / invalidations
61  *
62  * To avoid getting trapped in a "compilation -> bailout -> invalidation ->
63  * recompilation -> bailout -> invalidation -> ..." loop, every snapshot in
64  * Warp code is assigned a BailoutKind. If we bail out at that snapshot,
65  * FinishBailoutToBaseline will examine the BailoutKind and take appropriate
66  * action. In general:
67  *
68  * 1. If the bailing instruction comes from transpiled CacheIR, then when we
69  *    bail out and continue execution in the baseline interpreter, the
70  *    corresponding stub should fail a guard. As a result, we will either
71  *    increment the enteredCount for a subsequent stub or attach a new stub,
72  *    either of which will prevent WarpOracle from transpiling the failing stub
73  *    when we recompile.
74  *
75  *    Note: this means that every CacheIR op that can bail out in Warp must
76  *    have an equivalent guard in the baseline CacheIR implementation.
77  *
78  *    FirstExecution works according to the same principles: we have never hit
79  *    this IC before, but after we bail to baseline we will attach a stub and
80  *    recompile with better CacheIR information.
81  *
82  * 2. If the bailout occurs because an assumption we made in WarpBuilder was
83  *    invalidated, then FinishBailoutToBaseline will set a flag on the script
84  *    to avoid that assumption in the future: for example, UninitializedLexical.
85  *
86  * 3. Similarly, if the bailing instruction is generated or modified by a MIR
87  *    optimization, then FinishBailoutToBaseline will set a flag on the script
88  *    to make that optimization more conservative in the future.  Examples
89  *    include LICM, EagerTruncation, and HoistBoundsCheck.
90  *
91  * 4. Some bailouts can't be handled in Warp, even after a recompile. For
92  *    example, Warp does not support catching exceptions. If this happens
93  *    too often, then the cost of bailing out repeatedly outweighs the
94  *    benefit of Warp compilation, so we invalidate the script and disable
95  *    Warp compilation.
96  *
97  * 5. Some bailouts don't happen in performance-sensitive code: for example,
98  *    the |debugger| statement. We just ignore those.
99  */
100 enum class BailoutKind : uint8_t {
101   Unknown,
102 
103   // An instruction generated by the transpiler. If this instruction bails out,
104   // attaching a new stub in baseline will invalidate the current Warp script
105   // and avoid a bailout loop.
106   TranspiledCacheIR,
107 
108   // An optimistic unbox on the cold path for a non-Value phi failed. If this
109   // instruction bails out, we will invalidate the script and mark the
110   // HadSpeculativePhiBailout flag on the script.
111   SpeculativePhi,
112 
113   // A conversion inserted by a type policy. If this instruction bails out,
114   // we expect to throw an error. If this happens too frequently, we will
115   // invalidate the current Warp script and disable recompilation.
116   TypePolicy,
117 
118   // An instruction hoisted by LICM.  If this instruction bails out, we will
119   // bail out to baseline to see if we attach a new stub. If we do, then the
120   // more than once, we will invalidate the current Warp script and
121   // mark the hadLICMInvalidation flag on the script.
122   LICM,
123 
124   // An instruction moved up by InstructionReordering.  If this
125   // instruction bails out, we will mark the ReorderingBailout flag on
126   // the script. If this happens too frequently, we will invalidate
127   // the script.
128   InstructionReordering,
129 
130   // An instruction created or hoisted by tryHoistBoundsCheck.
131   // If this instruction bails out, we will invalidate the current Warp script
132   // and mark the HoistBoundsCheckBailout flag on the script.
133   HoistBoundsCheck,
134 
135   // An eager truncation generated by range analysis.
136   // If this instruction bails out, we will invalidate the current Warp script
137   // and mark the EagerTruncationBailout flag on the script.
138   EagerTruncation,
139 
140   // A folded unbox instruction generated by FoldLoadsWithUnbox.
141   // If this instruction bails out, we will invalidate the current Warp script
142   // and mark the UnboxFoldingBailout flag on the script.
143   UnboxFolding,
144 
145   // An inevitable bailout (MBail instruction or type barrier that always bails)
146   Inevitable,
147 
148   // Bailing out during a VM call. Many possible causes that are hard
149   // to distinguish statically at snapshot construction time.
150   // We just lump them together.
151   DuringVMCall,
152 
153   // A spread call or funapply had more than JIT_ARGS_LENGTH_MAX arguments.
154   // We bail out to handle this in the VM. If this happens too frequently,
155   // we will invalidate the current Warp script and disable recompilation.
156   TooManyArguments,
157 
158   // We hit an active |debugger;| statement.
159   Debugger,
160 
161   // We hit this code for the first time.
162   FirstExecution,
163 
164   // A lexical check failed. We will set lexical checks as unmovable.
165   UninitializedLexical,
166 
167   // A bailout to baseline from Ion on exception to handle Debugger hooks.
168   IonExceptionDebugMode,
169 
170   // We returned to a stack frame after invalidating its IonScript.
171   OnStackInvalidation,
172 
173   // We have executed code that should be unreachable, and need to assert.
174   Unreachable,
175 
176   Limit
177 };
178 
BailoutKindString(BailoutKind kind)179 inline const char* BailoutKindString(BailoutKind kind) {
180   switch (kind) {
181     case BailoutKind::Unknown:
182       return "Unknown";
183     case BailoutKind::TranspiledCacheIR:
184       return "TranspiledCacheIR";
185     case BailoutKind::SpeculativePhi:
186       return "SpeculativePhi";
187     case BailoutKind::TypePolicy:
188       return "TypePolicy";
189     case BailoutKind::LICM:
190       return "LICM";
191     case BailoutKind::InstructionReordering:
192       return "InstructionReordering";
193     case BailoutKind::HoistBoundsCheck:
194       return "HoistBoundsCheck";
195     case BailoutKind::EagerTruncation:
196       return "EagerTruncation";
197     case BailoutKind::UnboxFolding:
198       return "UnboxFolding";
199     case BailoutKind::Inevitable:
200       return "Inevitable";
201     case BailoutKind::DuringVMCall:
202       return "DuringVMCall";
203     case BailoutKind::TooManyArguments:
204       return "TooManyArguments";
205     case BailoutKind::Debugger:
206       return "Debugger";
207     case BailoutKind::FirstExecution:
208       return "FirstExecution";
209     case BailoutKind::UninitializedLexical:
210       return "UninitializedLexical";
211     case BailoutKind::IonExceptionDebugMode:
212       return "IonExceptionDebugMode";
213     case BailoutKind::OnStackInvalidation:
214       return "OnStackInvalidation";
215     case BailoutKind::Unreachable:
216       return "Unreachable";
217 
218     case BailoutKind::Limit:
219       break;
220   }
221 
222   MOZ_CRASH("Invalid BailoutKind");
223 }
224 
225 static const uint32_t ELEMENT_TYPE_BITS = 5;
226 static const uint32_t ELEMENT_TYPE_SHIFT = 0;
227 static const uint32_t ELEMENT_TYPE_MASK = (1 << ELEMENT_TYPE_BITS) - 1;
228 static const uint32_t VECTOR_TYPE_BITS = 1;
229 static const uint32_t VECTOR_TYPE_SHIFT =
230     ELEMENT_TYPE_BITS + ELEMENT_TYPE_SHIFT;
231 static const uint32_t VECTOR_TYPE_MASK = (1 << VECTOR_TYPE_BITS) - 1;
232 
233 // The integer SIMD types have a lot of operations that do the exact same thing
234 // for signed and unsigned integer types. Sometimes it is simpler to treat
235 // signed and unsigned integer SIMD types as the same type, using a SimdSign to
236 // distinguish the few cases where there is a difference.
237 enum class SimdSign {
238   // Signedness is not applicable to this type. (i.e., Float or Bool).
239   NotApplicable,
240   // Treat as an unsigned integer with a range 0 .. 2^N-1.
241   Unsigned,
242   // Treat as a signed integer in two's complement encoding.
243   Signed,
244 };
245 
246 class SimdConstant {
247  public:
248   enum Type {
249     Int8x16,
250     Int16x8,
251     Int32x4,
252     Int64x2,
253     Float32x4,
254     Float64x2,
255     Undefined = -1
256   };
257 
258   typedef int8_t I8x16[16];
259   typedef int16_t I16x8[8];
260   typedef int32_t I32x4[4];
261   typedef int64_t I64x2[2];
262   typedef float F32x4[4];
263   typedef double F64x2[2];
264 
265  private:
266   Type type_;
267   union {
268     I8x16 i8x16;
269     I16x8 i16x8;
270     I32x4 i32x4;
271     I64x2 i64x2;
272     F32x4 f32x4;
273     F64x2 f64x2;
274   } u;
275 
defined()276   bool defined() const { return type_ != Undefined; }
277 
278  public:
279   // Doesn't have a default constructor, as it would prevent it from being
280   // included in unions.
281 
CreateX16(const int8_t * array)282   static SimdConstant CreateX16(const int8_t* array) {
283     SimdConstant cst;
284     cst.type_ = Int8x16;
285     memcpy(cst.u.i8x16, array, sizeof(cst.u));
286     return cst;
287   }
SplatX16(int8_t v)288   static SimdConstant SplatX16(int8_t v) {
289     SimdConstant cst;
290     cst.type_ = Int8x16;
291     std::fill_n(cst.u.i8x16, 16, v);
292     return cst;
293   }
CreateX8(const int16_t * array)294   static SimdConstant CreateX8(const int16_t* array) {
295     SimdConstant cst;
296     cst.type_ = Int16x8;
297     memcpy(cst.u.i16x8, array, sizeof(cst.u));
298     return cst;
299   }
SplatX8(int16_t v)300   static SimdConstant SplatX8(int16_t v) {
301     SimdConstant cst;
302     cst.type_ = Int16x8;
303     std::fill_n(cst.u.i16x8, 8, v);
304     return cst;
305   }
CreateX4(const int32_t * array)306   static SimdConstant CreateX4(const int32_t* array) {
307     SimdConstant cst;
308     cst.type_ = Int32x4;
309     memcpy(cst.u.i32x4, array, sizeof(cst.u));
310     return cst;
311   }
SplatX4(int32_t v)312   static SimdConstant SplatX4(int32_t v) {
313     SimdConstant cst;
314     cst.type_ = Int32x4;
315     std::fill_n(cst.u.i32x4, 4, v);
316     return cst;
317   }
CreateX2(const int64_t * array)318   static SimdConstant CreateX2(const int64_t* array) {
319     SimdConstant cst;
320     cst.type_ = Int64x2;
321     memcpy(cst.u.i64x2, array, sizeof(cst.u));
322     return cst;
323   }
SplatX2(int64_t v)324   static SimdConstant SplatX2(int64_t v) {
325     SimdConstant cst;
326     cst.type_ = Int64x2;
327     std::fill_n(cst.u.i64x2, 2, v);
328     return cst;
329   }
CreateX4(const float * array)330   static SimdConstant CreateX4(const float* array) {
331     SimdConstant cst;
332     cst.type_ = Float32x4;
333     memcpy(cst.u.f32x4, array, sizeof(cst.u));
334     return cst;
335   }
SplatX4(float v)336   static SimdConstant SplatX4(float v) {
337     SimdConstant cst;
338     cst.type_ = Float32x4;
339     std::fill_n(cst.u.f32x4, 4, v);
340     return cst;
341   }
CreateX2(const double * array)342   static SimdConstant CreateX2(const double* array) {
343     SimdConstant cst;
344     cst.type_ = Float64x2;
345     memcpy(cst.u.f64x2, array, sizeof(cst.u));
346     return cst;
347   }
SplatX2(double v)348   static SimdConstant SplatX2(double v) {
349     SimdConstant cst;
350     cst.type_ = Float64x2;
351     std::fill_n(cst.u.f64x2, 2, v);
352     return cst;
353   }
354 
355   // Overloads for use by templates.
CreateSimd128(const int8_t * array)356   static SimdConstant CreateSimd128(const int8_t* array) {
357     return CreateX16(array);
358   }
CreateSimd128(const int16_t * array)359   static SimdConstant CreateSimd128(const int16_t* array) {
360     return CreateX8(array);
361   }
CreateSimd128(const int32_t * array)362   static SimdConstant CreateSimd128(const int32_t* array) {
363     return CreateX4(array);
364   }
CreateSimd128(const int64_t * array)365   static SimdConstant CreateSimd128(const int64_t* array) {
366     return CreateX2(array);
367   }
CreateSimd128(const float * array)368   static SimdConstant CreateSimd128(const float* array) {
369     return CreateX4(array);
370   }
CreateSimd128(const double * array)371   static SimdConstant CreateSimd128(const double* array) {
372     return CreateX2(array);
373   }
374 
type()375   Type type() const {
376     MOZ_ASSERT(defined());
377     return type_;
378   }
379 
isFloatingType()380   bool isFloatingType() const {
381     MOZ_ASSERT(defined());
382     return type_ >= Float32x4;
383   }
384 
isIntegerType()385   bool isIntegerType() const {
386     MOZ_ASSERT(defined());
387     return type_ <= Int64x2;
388   }
389 
390   // Get the raw bytes of the constant.
bytes()391   const void* bytes() const { return u.i8x16; }
392 
asInt8x16()393   const I8x16& asInt8x16() const {
394     MOZ_ASSERT(defined() && type_ == Int8x16);
395     return u.i8x16;
396   }
397 
asInt16x8()398   const I16x8& asInt16x8() const {
399     MOZ_ASSERT(defined() && type_ == Int16x8);
400     return u.i16x8;
401   }
402 
asInt32x4()403   const I32x4& asInt32x4() const {
404     MOZ_ASSERT(defined() && type_ == Int32x4);
405     return u.i32x4;
406   }
407 
asInt64x2()408   const I64x2& asInt64x2() const {
409     MOZ_ASSERT(defined() && type_ == Int64x2);
410     return u.i64x2;
411   }
412 
asFloat32x4()413   const F32x4& asFloat32x4() const {
414     MOZ_ASSERT(defined() && type_ == Float32x4);
415     return u.f32x4;
416   }
417 
asFloat64x2()418   const F64x2& asFloat64x2() const {
419     MOZ_ASSERT(defined() && type_ == Float64x2);
420     return u.f64x2;
421   }
422 
bitwiseEqual(const SimdConstant & rhs)423   bool bitwiseEqual(const SimdConstant& rhs) const {
424     MOZ_ASSERT(defined() && rhs.defined());
425     return memcmp(&u, &rhs.u, sizeof(u)) == 0;
426   }
427 
isZeroBits()428   bool isZeroBits() const {
429     MOZ_ASSERT(defined());
430     return u.i64x2[0] == 0 && u.i64x2[1] == 0;
431   }
432 
isOneBits()433   bool isOneBits() const {
434     MOZ_ASSERT(defined());
435     return ~u.i64x2[0] == 0 && ~u.i64x2[1] == 0;
436   }
437 
438   // SimdConstant is a HashPolicy.  Currently we discriminate by type, but it
439   // may be that we should only be discriminating by int vs float.
440   using Lookup = SimdConstant;
441 
hash(const SimdConstant & val)442   static HashNumber hash(const SimdConstant& val) {
443     uint32_t hash = mozilla::HashBytes(&val.u, sizeof(val.u));
444     return mozilla::AddToHash(hash, val.type_);
445   }
446 
match(const SimdConstant & lhs,const SimdConstant & rhs)447   static bool match(const SimdConstant& lhs, const SimdConstant& rhs) {
448     return lhs.type() == rhs.type() && lhs.bitwiseEqual(rhs);
449   }
450 };
451 
452 enum class IntConversionBehavior {
453   // These two try to convert the input to an int32 using ToNumber and
454   // will fail if the resulting int32 isn't strictly equal to the input.
455   Normal,             // Succeeds on -0: converts to 0.
456   NegativeZeroCheck,  // Fails on -0.
457   // These three will convert the input to an int32 with loss of precision.
458   Truncate,
459   TruncateNoWrap,
460   ClampToUint8,
461 };
462 
463 enum class IntConversionInputKind { NumbersOnly, NumbersOrBoolsOnly, Any };
464 
465 // The ordering of this enumeration is important: Anything < Value is a
466 // specialized type. Furthermore, anything < String has trivial conversion to
467 // a number.
468 enum class MIRType : uint8_t {
469   Undefined,
470   Null,
471   Boolean,
472   Int32,
473   Int64,
474   IntPtr,
475   Double,
476   Float32,
477   // Types above have trivial conversion to a number.
478   String,
479   Symbol,
480   BigInt,
481   Simd128,
482   // Types above are primitive (including undefined and null).
483   Object,
484   MagicOptimizedOut,          // JS_OPTIMIZED_OUT magic value.
485   MagicHole,                  // JS_ELEMENTS_HOLE magic value.
486   MagicIsConstructing,        // JS_IS_CONSTRUCTING magic value.
487   MagicUninitializedLexical,  // JS_UNINITIALIZED_LEXICAL magic value.
488   // Types above are specialized.
489   Value,
490   None,          // Invalid, used as a placeholder.
491   Slots,         // A slots vector
492   Elements,      // An elements vector
493   Pointer,       // An opaque pointer that receives no special treatment
494   RefOrNull,     // Wasm Ref/AnyRef/NullRef: a raw JSObject* or a raw (void*)0
495   StackResults,  // Wasm multi-value stack result area, which may contain refs
496   Shape,         // A Shape pointer.
497   Last = Shape
498 };
499 
MIRTypeFromValueType(JSValueType type)500 static inline MIRType MIRTypeFromValueType(JSValueType type) {
501   // This function does not deal with magic types. Magic constants should be
502   // filtered out in MIRTypeFromValue.
503   switch (type) {
504     case JSVAL_TYPE_DOUBLE:
505       return MIRType::Double;
506     case JSVAL_TYPE_INT32:
507       return MIRType::Int32;
508     case JSVAL_TYPE_UNDEFINED:
509       return MIRType::Undefined;
510     case JSVAL_TYPE_STRING:
511       return MIRType::String;
512     case JSVAL_TYPE_SYMBOL:
513       return MIRType::Symbol;
514     case JSVAL_TYPE_BIGINT:
515       return MIRType::BigInt;
516     case JSVAL_TYPE_BOOLEAN:
517       return MIRType::Boolean;
518     case JSVAL_TYPE_NULL:
519       return MIRType::Null;
520     case JSVAL_TYPE_OBJECT:
521       return MIRType::Object;
522     case JSVAL_TYPE_UNKNOWN:
523       return MIRType::Value;
524     default:
525       MOZ_CRASH("unexpected jsval type");
526   }
527 }
528 
ValueTypeFromMIRType(MIRType type)529 static inline JSValueType ValueTypeFromMIRType(MIRType type) {
530   switch (type) {
531     case MIRType::Undefined:
532       return JSVAL_TYPE_UNDEFINED;
533     case MIRType::Null:
534       return JSVAL_TYPE_NULL;
535     case MIRType::Boolean:
536       return JSVAL_TYPE_BOOLEAN;
537     case MIRType::Int32:
538       return JSVAL_TYPE_INT32;
539     case MIRType::Float32:  // Fall through, there's no JSVAL for Float32
540     case MIRType::Double:
541       return JSVAL_TYPE_DOUBLE;
542     case MIRType::String:
543       return JSVAL_TYPE_STRING;
544     case MIRType::Symbol:
545       return JSVAL_TYPE_SYMBOL;
546     case MIRType::BigInt:
547       return JSVAL_TYPE_BIGINT;
548     case MIRType::MagicOptimizedOut:
549     case MIRType::MagicHole:
550     case MIRType::MagicIsConstructing:
551     case MIRType::MagicUninitializedLexical:
552       return JSVAL_TYPE_MAGIC;
553     default:
554       MOZ_ASSERT(type == MIRType::Object);
555       return JSVAL_TYPE_OBJECT;
556   }
557 }
558 
MIRTypeToTag(MIRType type)559 static inline JSValueTag MIRTypeToTag(MIRType type) {
560   return JSVAL_TYPE_TO_TAG(ValueTypeFromMIRType(type));
561 }
562 
MIRTypeToSize(MIRType type)563 static inline size_t MIRTypeToSize(MIRType type) {
564   switch (type) {
565     case MIRType::Int32:
566       return 4;
567     case MIRType::Int64:
568       return 8;
569     case MIRType::Float32:
570       return 4;
571     case MIRType::Double:
572       return 8;
573     case MIRType::Simd128:
574       return 16;
575     case MIRType::Pointer:
576     case MIRType::RefOrNull:
577       return sizeof(uintptr_t);
578     default:
579       MOZ_CRASH("MIRTypeToSize - unhandled case");
580   }
581 }
582 
StringFromMIRType(MIRType type)583 static inline const char* StringFromMIRType(MIRType type) {
584   switch (type) {
585     case MIRType::Undefined:
586       return "Undefined";
587     case MIRType::Null:
588       return "Null";
589     case MIRType::Boolean:
590       return "Bool";
591     case MIRType::Int32:
592       return "Int32";
593     case MIRType::Int64:
594       return "Int64";
595     case MIRType::IntPtr:
596       return "IntPtr";
597     case MIRType::Double:
598       return "Double";
599     case MIRType::Float32:
600       return "Float32";
601     case MIRType::String:
602       return "String";
603     case MIRType::Symbol:
604       return "Symbol";
605     case MIRType::BigInt:
606       return "BigInt";
607     case MIRType::Object:
608       return "Object";
609     case MIRType::MagicOptimizedOut:
610       return "MagicOptimizedOut";
611     case MIRType::MagicHole:
612       return "MagicHole";
613     case MIRType::MagicIsConstructing:
614       return "MagicIsConstructing";
615     case MIRType::MagicUninitializedLexical:
616       return "MagicUninitializedLexical";
617     case MIRType::Value:
618       return "Value";
619     case MIRType::None:
620       return "None";
621     case MIRType::Slots:
622       return "Slots";
623     case MIRType::Elements:
624       return "Elements";
625     case MIRType::Pointer:
626       return "Pointer";
627     case MIRType::RefOrNull:
628       return "RefOrNull";
629     case MIRType::StackResults:
630       return "StackResults";
631     case MIRType::Shape:
632       return "Shape";
633     case MIRType::Simd128:
634       return "Simd128";
635   }
636   MOZ_CRASH("Unknown MIRType.");
637 }
638 
IsIntType(MIRType type)639 static inline bool IsIntType(MIRType type) {
640   return type == MIRType::Int32 || type == MIRType::Int64;
641 }
642 
IsNumberType(MIRType type)643 static inline bool IsNumberType(MIRType type) {
644   return type == MIRType::Int32 || type == MIRType::Double ||
645          type == MIRType::Float32 || type == MIRType::Int64;
646 }
647 
IsNumericType(MIRType type)648 static inline bool IsNumericType(MIRType type) {
649   return IsNumberType(type) || type == MIRType::BigInt;
650 }
651 
IsTypeRepresentableAsDouble(MIRType type)652 static inline bool IsTypeRepresentableAsDouble(MIRType type) {
653   return type == MIRType::Int32 || type == MIRType::Double ||
654          type == MIRType::Float32;
655 }
656 
IsFloatType(MIRType type)657 static inline bool IsFloatType(MIRType type) {
658   return type == MIRType::Int32 || type == MIRType::Float32;
659 }
660 
IsFloatingPointType(MIRType type)661 static inline bool IsFloatingPointType(MIRType type) {
662   return type == MIRType::Double || type == MIRType::Float32;
663 }
664 
IsNullOrUndefined(MIRType type)665 static inline bool IsNullOrUndefined(MIRType type) {
666   return type == MIRType::Null || type == MIRType::Undefined;
667 }
668 
IsMagicType(MIRType type)669 static inline bool IsMagicType(MIRType type) {
670   return type == MIRType::MagicHole || type == MIRType::MagicOptimizedOut ||
671          type == MIRType::MagicIsConstructing ||
672          type == MIRType::MagicUninitializedLexical;
673 }
674 
ScalarTypeToMIRType(Scalar::Type type)675 static inline MIRType ScalarTypeToMIRType(Scalar::Type type) {
676   switch (type) {
677     case Scalar::Int8:
678     case Scalar::Uint8:
679     case Scalar::Int16:
680     case Scalar::Uint16:
681     case Scalar::Int32:
682     case Scalar::Uint32:
683     case Scalar::Uint8Clamped:
684       return MIRType::Int32;
685     case Scalar::Int64:
686       return MIRType::Int64;
687     case Scalar::Float32:
688       return MIRType::Float32;
689     case Scalar::Float64:
690       return MIRType::Double;
691     case Scalar::BigInt64:
692     case Scalar::BigUint64:
693       MOZ_CRASH("NYI");
694     case Scalar::Simd128:
695       return MIRType::Simd128;
696     case Scalar::MaxTypedArrayViewType:
697       break;
698   }
699   MOZ_CRASH("unexpected kind");
700 }
701 
NeedsPostBarrier(MIRType type)702 static constexpr bool NeedsPostBarrier(MIRType type) {
703   MOZ_ASSERT(type != MIRType::Value);
704   return type == MIRType::Object || type == MIRType::String ||
705          type == MIRType::BigInt;
706 }
707 
708 #ifdef DEBUG
709 
710 // Track the pipeline of opcodes which has produced a snapshot.
711 #  define TRACK_SNAPSHOTS 1
712 
713 // Make sure registers are not modified between an instruction and
714 // its OsiPoint.
715 #  define CHECK_OSIPOINT_REGISTERS 1
716 
717 #endif  // DEBUG
718 
719 enum ABIArgType {
720   // A pointer sized integer
721   ArgType_General = 0x1,
722   // A 32-bit integer
723   ArgType_Int32 = 0x2,
724   // A 64-bit integer
725   ArgType_Int64 = 0x3,
726   // A 32-bit floating point number
727   ArgType_Float32 = 0x4,
728   // A 64-bit floating point number
729   ArgType_Float64 = 0x5,
730 
731   RetType_Shift = 0x0,
732   ArgType_Shift = 0x3,
733   ArgType_Mask = 0x7
734 };
735 
736 namespace detail {
737 
MakeABIFunctionType(ABIArgType ret,std::initializer_list<ABIArgType> args)738 static constexpr int MakeABIFunctionType(
739     ABIArgType ret, std::initializer_list<ABIArgType> args) {
740   int abiType = ret << RetType_Shift;
741   int i = 1;
742   for (auto arg : args) {
743     abiType |= (arg << (ArgType_Shift * i));
744     i++;
745   }
746   return abiType;
747 }
748 
749 }  // namespace detail
750 
751 enum ABIFunctionType : uint32_t {
752   // The enum must be explicitly typed to avoid UB: some validly constructed
753   // members are larger than any explicitly declared members.
754 
755   // VM functions that take 0-9 non-double arguments
756   // and return a non-double value.
757   Args_General0 = ArgType_General << RetType_Shift,
758   Args_General1 = Args_General0 | (ArgType_General << (ArgType_Shift * 1)),
759   Args_General2 = Args_General1 | (ArgType_General << (ArgType_Shift * 2)),
760   Args_General3 = Args_General2 | (ArgType_General << (ArgType_Shift * 3)),
761   Args_General4 = Args_General3 | (ArgType_General << (ArgType_Shift * 4)),
762   Args_General5 = Args_General4 | (ArgType_General << (ArgType_Shift * 5)),
763   Args_General6 = Args_General5 | (ArgType_General << (ArgType_Shift * 6)),
764   Args_General7 = Args_General6 | (ArgType_General << (ArgType_Shift * 7)),
765   Args_General8 = Args_General7 | (ArgType_General << (ArgType_Shift * 8)),
766 
767   // int64 f(double)
768   Args_Int64_Double =
769       (ArgType_Int64 << RetType_Shift) | (ArgType_Float64 << ArgType_Shift),
770 
771   // double f()
772   Args_Double_None = ArgType_Float64 << RetType_Shift,
773 
774   // int f(double)
775   Args_Int_Double = Args_General0 | (ArgType_Float64 << ArgType_Shift),
776 
777   // int f(float32)
778   Args_Int_Float32 = Args_General0 | (ArgType_Float32 << ArgType_Shift),
779 
780   // float f(float)
781   Args_Float32_Float32 =
782       (ArgType_Float32 << RetType_Shift) | (ArgType_Float32 << ArgType_Shift),
783 
784   // float f(int, int)
785   Args_Float32_IntInt = (ArgType_Float32 << RetType_Shift) |
786                         (ArgType_General << (ArgType_Shift * 1)) |
787                         (ArgType_General << (ArgType_Shift * 2)),
788 
789   // double f(double)
790   Args_Double_Double = Args_Double_None | (ArgType_Float64 << ArgType_Shift),
791 
792   // double f(int)
793   Args_Double_Int = Args_Double_None | (ArgType_General << ArgType_Shift),
794 
795   // double f(int, int)
796   Args_Double_IntInt =
797       Args_Double_Int | (ArgType_General << (ArgType_Shift * 2)),
798 
799   // double f(double, int)
800   Args_Double_DoubleInt = Args_Double_None |
801                           (ArgType_General << (ArgType_Shift * 1)) |
802                           (ArgType_Float64 << (ArgType_Shift * 2)),
803 
804   // double f(double, double)
805   Args_Double_DoubleDouble =
806       Args_Double_Double | (ArgType_Float64 << (ArgType_Shift * 2)),
807 
808   // float f(float, float)
809   Args_Float32_Float32Float32 =
810       Args_Float32_Float32 | (ArgType_Float32 << (ArgType_Shift * 2)),
811 
812   // double f(int, double)
813   Args_Double_IntDouble = Args_Double_None |
814                           (ArgType_Float64 << (ArgType_Shift * 1)) |
815                           (ArgType_General << (ArgType_Shift * 2)),
816 
817   // int f(int, double)
818   Args_Int_IntDouble = Args_General0 |
819                        (ArgType_Float64 << (ArgType_Shift * 1)) |
820                        (ArgType_General << (ArgType_Shift * 2)),
821 
822   // int f(double, int)
823   Args_Int_DoubleInt = Args_General0 |
824                        (ArgType_General << (ArgType_Shift * 1)) |
825                        (ArgType_Float64 << (ArgType_Shift * 2)),
826 
827   // double f(double, double, double)
828   Args_Double_DoubleDoubleDouble =
829       Args_Double_DoubleDouble | (ArgType_Float64 << (ArgType_Shift * 3)),
830 
831   // double f(double, double, double, double)
832   Args_Double_DoubleDoubleDoubleDouble =
833       Args_Double_DoubleDoubleDouble | (ArgType_Float64 << (ArgType_Shift * 4)),
834 
835   // int f(double, int, int)
836   Args_Int_DoubleIntInt = Args_General0 |
837                           (ArgType_General << (ArgType_Shift * 1)) |
838                           (ArgType_General << (ArgType_Shift * 2)) |
839                           (ArgType_Float64 << (ArgType_Shift * 3)),
840 
841   // int f(int, double, int, int)
842   Args_Int_IntDoubleIntInt = Args_General0 |
843                              (ArgType_General << (ArgType_Shift * 1)) |
844                              (ArgType_General << (ArgType_Shift * 2)) |
845                              (ArgType_Float64 << (ArgType_Shift * 3)) |
846                              (ArgType_General << (ArgType_Shift * 4)),
847 
848   Args_Int_GeneralGeneralGeneralInt64 =
849       Args_General0 | (ArgType_General << (ArgType_Shift * 1)) |
850       (ArgType_General << (ArgType_Shift * 2)) |
851       (ArgType_General << (ArgType_Shift * 3)) |
852       (ArgType_Int64 << (ArgType_Shift * 4)),
853 
854   Args_Int_GeneralGeneralInt64Int64 = Args_General0 |
855                                       (ArgType_General << (ArgType_Shift * 1)) |
856                                       (ArgType_General << (ArgType_Shift * 2)) |
857                                       (ArgType_Int64 << (ArgType_Shift * 3)) |
858                                       (ArgType_Int64 << (ArgType_Shift * 4)),
859 
860   Args_Int32_General =
861       detail::MakeABIFunctionType(ArgType_Int32, {ArgType_General}),
862   Args_Int32_GeneralInt32 = detail::MakeABIFunctionType(
863       ArgType_Int32, {ArgType_General, ArgType_Int32}),
864   Args_Int32_GeneralInt32Int32 = detail::MakeABIFunctionType(
865       ArgType_Int32, {ArgType_General, ArgType_Int32, ArgType_Int32}),
866   Args_Int32_GeneralInt32Int32Int32Int32 = detail::MakeABIFunctionType(
867       ArgType_Int32, {ArgType_General, ArgType_Int32, ArgType_Int32,
868                       ArgType_Int32, ArgType_Int32}),
869   Args_Int32_GeneralInt32Int32Int32Int32Int32 = detail::MakeABIFunctionType(
870       ArgType_Int32, {ArgType_General, ArgType_Int32, ArgType_Int32,
871                       ArgType_Int32, ArgType_Int32, ArgType_Int32}),
872   Args_Int32_GeneralInt32Int32Int32General = detail::MakeABIFunctionType(
873       ArgType_Int32, {ArgType_General, ArgType_Int32, ArgType_Int32,
874                       ArgType_Int32, ArgType_General}),
875   Args_Int32_GeneralInt32Int32Int64 = detail::MakeABIFunctionType(
876       ArgType_Int32,
877       {ArgType_General, ArgType_Int32, ArgType_Int32, ArgType_Int64}),
878   Args_Int32_GeneralInt32Int32General = detail::MakeABIFunctionType(
879       ArgType_Int32,
880       {ArgType_General, ArgType_Int32, ArgType_Int32, ArgType_General}),
881   Args_Int32_GeneralInt32Int64Int64 = detail::MakeABIFunctionType(
882       ArgType_Int32,
883       {ArgType_General, ArgType_Int32, ArgType_Int64, ArgType_Int64}),
884   Args_Int32_GeneralInt32GeneralInt32 = detail::MakeABIFunctionType(
885       ArgType_Int32,
886       {ArgType_General, ArgType_Int32, ArgType_General, ArgType_Int32}),
887   Args_Int32_GeneralInt32GeneralInt32Int32 = detail::MakeABIFunctionType(
888       ArgType_Int32, {ArgType_General, ArgType_Int32, ArgType_General,
889                       ArgType_Int32, ArgType_Int32}),
890   Args_Int32_GeneralGeneral = detail::MakeABIFunctionType(
891       ArgType_Int32, {ArgType_General, ArgType_General}),
892   Args_Int32_GeneralGeneralGeneral = detail::MakeABIFunctionType(
893       ArgType_Int32, {ArgType_General, ArgType_General, ArgType_General}),
894   Args_Int32_GeneralGeneralInt32Int32 = detail::MakeABIFunctionType(
895       ArgType_Int32,
896       {ArgType_General, ArgType_General, ArgType_Int32, ArgType_Int32}),
897   Args_General_GeneralInt32 = detail::MakeABIFunctionType(
898       ArgType_General, {ArgType_General, ArgType_Int32}),
899   Args_General_GeneralInt32Int32 = detail::MakeABIFunctionType(
900       ArgType_General, {ArgType_General, ArgType_Int32, ArgType_Int32}),
901   Args_General_GeneralInt32General = detail::MakeABIFunctionType(
902       ArgType_General, {ArgType_General, ArgType_Int32, ArgType_General}),
903 };
904 
MakeABIFunctionType(ABIArgType ret,std::initializer_list<ABIArgType> args)905 static constexpr ABIFunctionType MakeABIFunctionType(
906     ABIArgType ret, std::initializer_list<ABIArgType> args) {
907   return ABIFunctionType(detail::MakeABIFunctionType(ret, args));
908 }
909 
910 // Rounding modes for round instructions.
911 enum class RoundingMode { Down, Up, NearestTiesToEven, TowardsZero };
912 
913 // If a function contains no calls, we can assume the caller has checked the
914 // stack limit up to this maximum frame size. This works because the jit stack
915 // limit has a generous buffer before the real end of the native stack.
916 static const uint32_t MAX_UNCHECKED_LEAF_FRAME_SIZE = 64;
917 
918 // Truncating conversion modifiers.
919 using TruncFlags = uint32_t;
920 static const TruncFlags TRUNC_UNSIGNED = TruncFlags(1) << 0;
921 static const TruncFlags TRUNC_SATURATING = TruncFlags(1) << 1;
922 
923 enum BranchDirection { FALSE_BRANCH, TRUE_BRANCH };
924 
925 template <typename T>
SplatByteToUInt(uint8_t val,uint8_t x)926 constexpr T SplatByteToUInt(uint8_t val, uint8_t x) {
927   T splatted = val;
928   for (; x > 1; x--) {
929     splatted |= splatted << 8;
930   }
931   return splatted;
932 }
933 
934 }  // namespace jit
935 }  // namespace js
936 
937 #endif /* jit_IonTypes_h */
938