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