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