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