876 lines
26 KiB
C++
876 lines
26 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#ifndef jit_IonTypes_h
|
|
#define jit_IonTypes_h
|
|
|
|
#include "mozilla/HashFunctions.h"
|
|
|
|
#include <algorithm>
|
|
|
|
#include "jsfriendapi.h"
|
|
#include "jstypes.h"
|
|
|
|
#include "js/GCAPI.h"
|
|
#include "js/Value.h"
|
|
#include "vm/String.h"
|
|
|
|
namespace js {
|
|
namespace jit {
|
|
|
|
typedef uint32_t RecoverOffset;
|
|
typedef uint32_t SnapshotOffset;
|
|
typedef uint32_t BailoutId;
|
|
|
|
// The maximum size of any buffer associated with an assembler or code object.
|
|
// This is chosen to not overflow a signed integer, leaving room for an extra
|
|
// bit on offsets.
|
|
static const uint32_t MAX_BUFFER_SIZE = (1 << 30) - 1;
|
|
|
|
// Maximum number of scripted arg slots.
|
|
static const uint32_t SNAPSHOT_MAX_NARGS = 127;
|
|
|
|
static const SnapshotOffset INVALID_RECOVER_OFFSET = uint32_t(-1);
|
|
static const SnapshotOffset INVALID_SNAPSHOT_OFFSET = uint32_t(-1);
|
|
|
|
// Different kinds of bailouts. When extending this enum, make sure to check
|
|
// the bits reserved for bailout kinds in Bailouts.h
|
|
enum BailoutKind
|
|
{
|
|
// Normal bailouts, that don't need to be handled specially when restarting
|
|
// in baseline.
|
|
|
|
// An inevitable bailout (MBail instruction or type barrier that always bails)
|
|
Bailout_Inevitable,
|
|
|
|
// Bailing out during a VM call. Many possible causes that are hard
|
|
// to distinguish statically at snapshot construction time.
|
|
// We just lump them together.
|
|
Bailout_DuringVMCall,
|
|
|
|
// Call to a non-JSFunction (problem for |apply|)
|
|
Bailout_NonJSFunctionCallee,
|
|
|
|
// Dynamic scope chain lookup produced |undefined|
|
|
Bailout_DynamicNameNotFound,
|
|
|
|
// Input string contains 'arguments' or 'eval'
|
|
Bailout_StringArgumentsEval,
|
|
|
|
// Bailout on overflow, but don't immediately invalidate.
|
|
// Used for abs, sub and LoadUnboxedScalar (when loading a uint32 that
|
|
// doesn't fit in an int32).
|
|
Bailout_Overflow,
|
|
|
|
// floor, ceiling and round bail if input is NaN, if output would be -0 or
|
|
// doesn't fit in int32 range
|
|
Bailout_Round,
|
|
|
|
// Non-primitive value used as input for ToDouble, ToInt32, ToString, etc.
|
|
// For ToInt32, can also mean that input can't be converted without precision
|
|
// loss (e.g. 5.5).
|
|
Bailout_NonPrimitiveInput,
|
|
|
|
// For ToInt32, would lose precision when converting (e.g. 5.5).
|
|
Bailout_PrecisionLoss,
|
|
|
|
// We tripped a type barrier (object was not in the expected TypeSet)
|
|
Bailout_TypeBarrierO,
|
|
// We tripped a type barrier (value was not in the expected TypeSet)
|
|
Bailout_TypeBarrierV,
|
|
// We tripped a type monitor (wrote an unexpected type in a property)
|
|
Bailout_MonitorTypes,
|
|
|
|
// We hit a hole in an array.
|
|
Bailout_Hole,
|
|
|
|
// Array access with negative index
|
|
Bailout_NegativeIndex,
|
|
|
|
// Pretty specific case:
|
|
// - need a type barrier on a property write
|
|
// - all but one of the observed types have property types that reflect the value
|
|
// - we need to guard that we're not given an object of that one other type
|
|
// also used for the unused GuardClass instruction
|
|
Bailout_ObjectIdentityOrTypeGuard,
|
|
|
|
// Unbox expects a given type, bails out if it doesn't get it.
|
|
Bailout_NonInt32Input,
|
|
Bailout_NonNumericInput, // unboxing a double works with int32 too
|
|
Bailout_NonBooleanInput,
|
|
Bailout_NonObjectInput,
|
|
Bailout_NonStringInput,
|
|
Bailout_NonSymbolInput,
|
|
|
|
// SIMD Unbox expects a given type, bails out if it doesn't match.
|
|
Bailout_UnexpectedSimdInput,
|
|
|
|
// Atomic operations require shared memory, bail out if the typed array
|
|
// maps unshared memory.
|
|
Bailout_NonSharedTypedArrayInput,
|
|
|
|
// We hit a |debugger;| statement.
|
|
Bailout_Debugger,
|
|
|
|
// |this| used uninitialized in a derived constructor
|
|
Bailout_UninitializedThis,
|
|
|
|
// Derived constructors must return object or undefined
|
|
Bailout_BadDerivedConstructorReturn,
|
|
|
|
// We hit this code for the first time.
|
|
Bailout_FirstExecution,
|
|
|
|
// END Normal bailouts
|
|
|
|
// Bailouts caused by invalid assumptions based on Baseline code.
|
|
// Causes immediate invalidation.
|
|
|
|
// Like Bailout_Overflow, but causes immediate invalidation.
|
|
Bailout_OverflowInvalidate,
|
|
|
|
// Like NonStringInput, but should cause immediate invalidation.
|
|
// Used for jsop_iternext.
|
|
Bailout_NonStringInputInvalidate,
|
|
|
|
// Used for integer division, multiplication and modulo.
|
|
// If there's a remainder, bails to return a double.
|
|
// Can also signal overflow or result of -0.
|
|
// Can also signal division by 0 (returns inf, a double).
|
|
Bailout_DoubleOutput,
|
|
|
|
// END Invalid assumptions bailouts
|
|
|
|
|
|
// A bailout at the very start of a function indicates that there may be
|
|
// a type mismatch in the arguments that necessitates a reflow.
|
|
Bailout_ArgumentCheck,
|
|
|
|
// A bailout triggered by a bounds-check failure.
|
|
Bailout_BoundsCheck,
|
|
// A bailout triggered by a typed object whose backing buffer was detached.
|
|
Bailout_Detached,
|
|
|
|
// A shape guard based on TI information failed.
|
|
// (We saw an object whose shape does not match that / any of those observed
|
|
// by the baseline IC.)
|
|
Bailout_ShapeGuard,
|
|
|
|
// When we're trying to use an uninitialized lexical.
|
|
Bailout_UninitializedLexical,
|
|
|
|
// A bailout to baseline from Ion on exception to handle Debugger hooks.
|
|
Bailout_IonExceptionDebugMode
|
|
};
|
|
|
|
inline const char*
|
|
BailoutKindString(BailoutKind kind)
|
|
{
|
|
switch (kind) {
|
|
// Normal bailouts.
|
|
case Bailout_Inevitable:
|
|
return "Bailout_Inevitable";
|
|
case Bailout_DuringVMCall:
|
|
return "Bailout_DuringVMCall";
|
|
case Bailout_NonJSFunctionCallee:
|
|
return "Bailout_NonJSFunctionCallee";
|
|
case Bailout_DynamicNameNotFound:
|
|
return "Bailout_DynamicNameNotFound";
|
|
case Bailout_StringArgumentsEval:
|
|
return "Bailout_StringArgumentsEval";
|
|
case Bailout_Overflow:
|
|
return "Bailout_Overflow";
|
|
case Bailout_Round:
|
|
return "Bailout_Round";
|
|
case Bailout_NonPrimitiveInput:
|
|
return "Bailout_NonPrimitiveInput";
|
|
case Bailout_PrecisionLoss:
|
|
return "Bailout_PrecisionLoss";
|
|
case Bailout_TypeBarrierO:
|
|
return "Bailout_TypeBarrierO";
|
|
case Bailout_TypeBarrierV:
|
|
return "Bailout_TypeBarrierV";
|
|
case Bailout_MonitorTypes:
|
|
return "Bailout_MonitorTypes";
|
|
case Bailout_Hole:
|
|
return "Bailout_Hole";
|
|
case Bailout_NegativeIndex:
|
|
return "Bailout_NegativeIndex";
|
|
case Bailout_ObjectIdentityOrTypeGuard:
|
|
return "Bailout_ObjectIdentityOrTypeGuard";
|
|
case Bailout_NonInt32Input:
|
|
return "Bailout_NonInt32Input";
|
|
case Bailout_NonNumericInput:
|
|
return "Bailout_NonNumericInput";
|
|
case Bailout_NonBooleanInput:
|
|
return "Bailout_NonBooleanInput";
|
|
case Bailout_NonObjectInput:
|
|
return "Bailout_NonObjectInput";
|
|
case Bailout_NonStringInput:
|
|
return "Bailout_NonStringInput";
|
|
case Bailout_NonSymbolInput:
|
|
return "Bailout_NonSymbolInput";
|
|
case Bailout_UnexpectedSimdInput:
|
|
return "Bailout_UnexpectedSimdInput";
|
|
case Bailout_NonSharedTypedArrayInput:
|
|
return "Bailout_NonSharedTypedArrayInput";
|
|
case Bailout_Debugger:
|
|
return "Bailout_Debugger";
|
|
case Bailout_UninitializedThis:
|
|
return "Bailout_UninitializedThis";
|
|
case Bailout_BadDerivedConstructorReturn:
|
|
return "Bailout_BadDerivedConstructorReturn";
|
|
case Bailout_FirstExecution:
|
|
return "Bailout_FirstExecution";
|
|
|
|
// Bailouts caused by invalid assumptions.
|
|
case Bailout_OverflowInvalidate:
|
|
return "Bailout_OverflowInvalidate";
|
|
case Bailout_NonStringInputInvalidate:
|
|
return "Bailout_NonStringInputInvalidate";
|
|
case Bailout_DoubleOutput:
|
|
return "Bailout_DoubleOutput";
|
|
|
|
// Other bailouts.
|
|
case Bailout_ArgumentCheck:
|
|
return "Bailout_ArgumentCheck";
|
|
case Bailout_BoundsCheck:
|
|
return "Bailout_BoundsCheck";
|
|
case Bailout_Detached:
|
|
return "Bailout_Detached";
|
|
case Bailout_ShapeGuard:
|
|
return "Bailout_ShapeGuard";
|
|
case Bailout_UninitializedLexical:
|
|
return "Bailout_UninitializedLexical";
|
|
case Bailout_IonExceptionDebugMode:
|
|
return "Bailout_IonExceptionDebugMode";
|
|
default:
|
|
MOZ_CRASH("Invalid BailoutKind");
|
|
}
|
|
}
|
|
|
|
static const uint32_t ELEMENT_TYPE_BITS = 5;
|
|
static const uint32_t ELEMENT_TYPE_SHIFT = 0;
|
|
static const uint32_t ELEMENT_TYPE_MASK = (1 << ELEMENT_TYPE_BITS) - 1;
|
|
static const uint32_t VECTOR_SCALE_BITS = 3;
|
|
static const uint32_t VECTOR_SCALE_SHIFT = ELEMENT_TYPE_BITS + ELEMENT_TYPE_SHIFT;
|
|
static const uint32_t VECTOR_SCALE_MASK = (1 << VECTOR_SCALE_BITS) - 1;
|
|
|
|
class SimdConstant {
|
|
public:
|
|
enum Type {
|
|
Int8x16,
|
|
Int16x8,
|
|
Int32x4,
|
|
Float32x4,
|
|
Undefined = -1
|
|
};
|
|
|
|
typedef int8_t I8x16[16];
|
|
typedef int16_t I16x8[8];
|
|
typedef int32_t I32x4[4];
|
|
typedef float F32x4[4];
|
|
|
|
private:
|
|
Type type_;
|
|
union {
|
|
I8x16 i8x16;
|
|
I16x8 i16x8;
|
|
I32x4 i32x4;
|
|
F32x4 f32x4;
|
|
} u;
|
|
|
|
bool defined() const {
|
|
return type_ != Undefined;
|
|
}
|
|
|
|
public:
|
|
// Doesn't have a default constructor, as it would prevent it from being
|
|
// included in unions.
|
|
|
|
static SimdConstant CreateX16(const int8_t* array) {
|
|
SimdConstant cst;
|
|
cst.type_ = Int8x16;
|
|
memcpy(cst.u.i8x16, array, sizeof(cst.u));
|
|
return cst;
|
|
}
|
|
static SimdConstant SplatX16(int8_t v) {
|
|
SimdConstant cst;
|
|
cst.type_ = Int8x16;
|
|
std::fill_n(cst.u.i8x16, 16, v);
|
|
return cst;
|
|
}
|
|
static SimdConstant CreateX8(const int16_t* array) {
|
|
SimdConstant cst;
|
|
cst.type_ = Int16x8;
|
|
memcpy(cst.u.i16x8, array, sizeof(cst.u));
|
|
return cst;
|
|
}
|
|
static SimdConstant SplatX8(int16_t v) {
|
|
SimdConstant cst;
|
|
cst.type_ = Int16x8;
|
|
std::fill_n(cst.u.i16x8, 8, v);
|
|
return cst;
|
|
}
|
|
static SimdConstant CreateX4(const int32_t* array) {
|
|
SimdConstant cst;
|
|
cst.type_ = Int32x4;
|
|
memcpy(cst.u.i32x4, array, sizeof(cst.u));
|
|
return cst;
|
|
}
|
|
static SimdConstant SplatX4(int32_t v) {
|
|
SimdConstant cst;
|
|
cst.type_ = Int32x4;
|
|
std::fill_n(cst.u.i32x4, 4, v);
|
|
return cst;
|
|
}
|
|
static SimdConstant CreateX4(const float* array) {
|
|
SimdConstant cst;
|
|
cst.type_ = Float32x4;
|
|
memcpy(cst.u.f32x4, array, sizeof(cst.u));
|
|
return cst;
|
|
}
|
|
static SimdConstant SplatX4(float v) {
|
|
SimdConstant cst;
|
|
cst.type_ = Float32x4;
|
|
std::fill_n(cst.u.f32x4, 4, v);
|
|
return cst;
|
|
}
|
|
|
|
// Overloads for use by templates.
|
|
static SimdConstant CreateSimd128(const int8_t* array) { return CreateX16(array); }
|
|
static SimdConstant CreateSimd128(const int16_t* array) { return CreateX8(array); }
|
|
static SimdConstant CreateSimd128(const int32_t* array) { return CreateX4(array); }
|
|
static SimdConstant CreateSimd128(const float* array) { return CreateX4(array); }
|
|
|
|
Type type() const {
|
|
MOZ_ASSERT(defined());
|
|
return type_;
|
|
}
|
|
|
|
// Get the raw bytes of the constant.
|
|
const void* bytes() const {
|
|
return u.i8x16;
|
|
}
|
|
|
|
const I8x16& asInt8x16() const {
|
|
MOZ_ASSERT(defined() && type_ == Int8x16);
|
|
return u.i8x16;
|
|
}
|
|
|
|
const I16x8& asInt16x8() const {
|
|
MOZ_ASSERT(defined() && type_ == Int16x8);
|
|
return u.i16x8;
|
|
}
|
|
|
|
const I32x4& asInt32x4() const {
|
|
MOZ_ASSERT(defined() && type_ == Int32x4);
|
|
return u.i32x4;
|
|
}
|
|
|
|
const F32x4& asFloat32x4() const {
|
|
MOZ_ASSERT(defined() && type_ == Float32x4);
|
|
return u.f32x4;
|
|
}
|
|
|
|
bool operator==(const SimdConstant& rhs) const {
|
|
MOZ_ASSERT(defined() && rhs.defined());
|
|
if (type() != rhs.type())
|
|
return false;
|
|
// Takes negative zero into accuont, as it's a bit comparison.
|
|
return memcmp(&u, &rhs.u, sizeof(u)) == 0;
|
|
}
|
|
bool operator!=(const SimdConstant& rhs) const {
|
|
return !operator==(rhs);
|
|
}
|
|
|
|
// SimdConstant is a HashPolicy
|
|
typedef SimdConstant Lookup;
|
|
static HashNumber hash(const SimdConstant& val) {
|
|
uint32_t hash = mozilla::HashBytes(&val.u, sizeof(val.u));
|
|
return mozilla::AddToHash(hash, val.type_);
|
|
}
|
|
static bool match(const SimdConstant& lhs, const SimdConstant& rhs) {
|
|
return lhs == rhs;
|
|
}
|
|
};
|
|
|
|
// The ordering of this enumeration is important: Anything < Value is a
|
|
// specialized type. Furthermore, anything < String has trivial conversion to
|
|
// a number.
|
|
enum class MIRType
|
|
{
|
|
Undefined,
|
|
Null,
|
|
Boolean,
|
|
Int32,
|
|
Int64,
|
|
Double,
|
|
Float32,
|
|
// Types above have trivial conversion to a number.
|
|
String,
|
|
Symbol,
|
|
// Types above are primitive (including undefined and null).
|
|
Object,
|
|
MagicOptimizedArguments, // JS_OPTIMIZED_ARGUMENTS magic value.
|
|
MagicOptimizedOut, // JS_OPTIMIZED_OUT magic value.
|
|
MagicHole, // JS_ELEMENTS_HOLE magic value.
|
|
MagicIsConstructing, // JS_IS_CONSTRUCTING magic value.
|
|
MagicUninitializedLexical, // JS_UNINITIALIZED_LEXICAL magic value.
|
|
// Types above are specialized.
|
|
Value,
|
|
SinCosDouble, // Optimizing a sin/cos to sincos.
|
|
ObjectOrNull,
|
|
None, // Invalid, used as a placeholder.
|
|
Slots, // A slots vector
|
|
Elements, // An elements vector
|
|
Pointer, // An opaque pointer that receives no special treatment
|
|
Shape, // A Shape pointer.
|
|
ObjectGroup, // An ObjectGroup pointer.
|
|
Last = ObjectGroup,
|
|
// Representing both SIMD.IntBxN and SIMD.UintBxN.
|
|
Int8x16 = Int32 | (4 << VECTOR_SCALE_SHIFT),
|
|
Int16x8 = Int32 | (3 << VECTOR_SCALE_SHIFT),
|
|
Int32x4 = Int32 | (2 << VECTOR_SCALE_SHIFT),
|
|
Float32x4 = Float32 | (2 << VECTOR_SCALE_SHIFT),
|
|
Bool8x16 = Boolean | (4 << VECTOR_SCALE_SHIFT),
|
|
Bool16x8 = Boolean | (3 << VECTOR_SCALE_SHIFT),
|
|
Bool32x4 = Boolean | (2 << VECTOR_SCALE_SHIFT),
|
|
Doublex2 = Double | (1 << VECTOR_SCALE_SHIFT)
|
|
};
|
|
|
|
static inline bool
|
|
IsSimdType(MIRType type)
|
|
{
|
|
return ((unsigned(type) >> VECTOR_SCALE_SHIFT) & VECTOR_SCALE_MASK) != 0;
|
|
}
|
|
|
|
// Returns the number of vector elements (hereby called "length") for a given
|
|
// SIMD kind. It is the Y part of the name "Foo x Y".
|
|
static inline unsigned
|
|
SimdTypeToLength(MIRType type)
|
|
{
|
|
MOZ_ASSERT(IsSimdType(type));
|
|
return 1 << ((unsigned(type) >> VECTOR_SCALE_SHIFT) & VECTOR_SCALE_MASK);
|
|
}
|
|
|
|
// Get the type of the individual lanes in a SIMD type.
|
|
// For example, Int32x4 -> Int32, Float32x4 -> Float32 etc.
|
|
static inline MIRType
|
|
SimdTypeToLaneType(MIRType type)
|
|
{
|
|
MOZ_ASSERT(IsSimdType(type));
|
|
static_assert(unsigned(MIRType::Last) <= ELEMENT_TYPE_MASK,
|
|
"ELEMENT_TYPE_MASK should be larger than the last MIRType");
|
|
return MIRType((unsigned(type) >> ELEMENT_TYPE_SHIFT) & ELEMENT_TYPE_MASK);
|
|
}
|
|
|
|
// Get the type expected when inserting a lane into a SIMD type.
|
|
// This is the argument type expected by the MSimdValue constructors as well as
|
|
// MSimdSplat and MSimdInsertElement.
|
|
static inline MIRType
|
|
SimdTypeToLaneArgumentType(MIRType type)
|
|
{
|
|
MIRType laneType = SimdTypeToLaneType(type);
|
|
|
|
// Boolean lanes should be pre-converted to an Int32 with the values 0 or -1.
|
|
// All other lane types are inserted directly.
|
|
return laneType == MIRType::Boolean ? MIRType::Int32 : laneType;
|
|
}
|
|
|
|
static inline MIRType
|
|
MIRTypeFromValueType(JSValueType type)
|
|
{
|
|
// This function does not deal with magic types. Magic constants should be
|
|
// filtered out in MIRTypeFromValue.
|
|
switch (type) {
|
|
case JSVAL_TYPE_DOUBLE:
|
|
return MIRType::Double;
|
|
case JSVAL_TYPE_INT32:
|
|
return MIRType::Int32;
|
|
case JSVAL_TYPE_UNDEFINED:
|
|
return MIRType::Undefined;
|
|
case JSVAL_TYPE_STRING:
|
|
return MIRType::String;
|
|
case JSVAL_TYPE_SYMBOL:
|
|
return MIRType::Symbol;
|
|
case JSVAL_TYPE_BOOLEAN:
|
|
return MIRType::Boolean;
|
|
case JSVAL_TYPE_NULL:
|
|
return MIRType::Null;
|
|
case JSVAL_TYPE_OBJECT:
|
|
return MIRType::Object;
|
|
case JSVAL_TYPE_UNKNOWN:
|
|
return MIRType::Value;
|
|
default:
|
|
MOZ_CRASH("unexpected jsval type");
|
|
}
|
|
}
|
|
|
|
static inline JSValueType
|
|
ValueTypeFromMIRType(MIRType type)
|
|
{
|
|
switch (type) {
|
|
case MIRType::Undefined:
|
|
return JSVAL_TYPE_UNDEFINED;
|
|
case MIRType::Null:
|
|
return JSVAL_TYPE_NULL;
|
|
case MIRType::Boolean:
|
|
return JSVAL_TYPE_BOOLEAN;
|
|
case MIRType::Int32:
|
|
return JSVAL_TYPE_INT32;
|
|
case MIRType::Float32: // Fall through, there's no JSVAL for Float32
|
|
case MIRType::Double:
|
|
return JSVAL_TYPE_DOUBLE;
|
|
case MIRType::String:
|
|
return JSVAL_TYPE_STRING;
|
|
case MIRType::Symbol:
|
|
return JSVAL_TYPE_SYMBOL;
|
|
case MIRType::MagicOptimizedArguments:
|
|
case MIRType::MagicOptimizedOut:
|
|
case MIRType::MagicHole:
|
|
case MIRType::MagicIsConstructing:
|
|
case MIRType::MagicUninitializedLexical:
|
|
return JSVAL_TYPE_MAGIC;
|
|
default:
|
|
MOZ_ASSERT(type == MIRType::Object);
|
|
return JSVAL_TYPE_OBJECT;
|
|
}
|
|
}
|
|
|
|
static inline JSValueTag
|
|
MIRTypeToTag(MIRType type)
|
|
{
|
|
return JSVAL_TYPE_TO_TAG(ValueTypeFromMIRType(type));
|
|
}
|
|
|
|
static inline const char*
|
|
StringFromMIRType(MIRType type)
|
|
{
|
|
switch (type) {
|
|
case MIRType::Undefined:
|
|
return "Undefined";
|
|
case MIRType::Null:
|
|
return "Null";
|
|
case MIRType::Boolean:
|
|
return "Bool";
|
|
case MIRType::Int32:
|
|
return "Int32";
|
|
case MIRType::Int64:
|
|
return "Int64";
|
|
case MIRType::Double:
|
|
return "Double";
|
|
case MIRType::Float32:
|
|
return "Float32";
|
|
case MIRType::String:
|
|
return "String";
|
|
case MIRType::Symbol:
|
|
return "Symbol";
|
|
case MIRType::Object:
|
|
return "Object";
|
|
case MIRType::MagicOptimizedArguments:
|
|
return "MagicOptimizedArguments";
|
|
case MIRType::MagicOptimizedOut:
|
|
return "MagicOptimizedOut";
|
|
case MIRType::MagicHole:
|
|
return "MagicHole";
|
|
case MIRType::MagicIsConstructing:
|
|
return "MagicIsConstructing";
|
|
case MIRType::MagicUninitializedLexical:
|
|
return "MagicUninitializedLexical";
|
|
case MIRType::Value:
|
|
return "Value";
|
|
case MIRType::SinCosDouble:
|
|
return "SinCosDouble";
|
|
case MIRType::ObjectOrNull:
|
|
return "ObjectOrNull";
|
|
case MIRType::None:
|
|
return "None";
|
|
case MIRType::Slots:
|
|
return "Slots";
|
|
case MIRType::Elements:
|
|
return "Elements";
|
|
case MIRType::Pointer:
|
|
return "Pointer";
|
|
case MIRType::Shape:
|
|
return "Shape";
|
|
case MIRType::ObjectGroup:
|
|
return "ObjectGroup";
|
|
case MIRType::Int32x4:
|
|
return "Int32x4";
|
|
case MIRType::Int16x8:
|
|
return "Int16x8";
|
|
case MIRType::Int8x16:
|
|
return "Int8x16";
|
|
case MIRType::Float32x4:
|
|
return "Float32x4";
|
|
case MIRType::Bool32x4:
|
|
return "Bool32x4";
|
|
case MIRType::Bool16x8:
|
|
return "Bool16x8";
|
|
case MIRType::Bool8x16:
|
|
return "Bool8x16";
|
|
case MIRType::Doublex2:
|
|
return "Doublex2";
|
|
}
|
|
MOZ_CRASH("Unknown MIRType.");
|
|
}
|
|
|
|
static inline bool
|
|
IsIntType(MIRType type)
|
|
{
|
|
return type == MIRType::Int32 ||
|
|
type == MIRType::Int64;
|
|
}
|
|
|
|
static inline bool
|
|
IsNumberType(MIRType type)
|
|
{
|
|
return type == MIRType::Int32 ||
|
|
type == MIRType::Double ||
|
|
type == MIRType::Float32 ||
|
|
type == MIRType::Int64;
|
|
}
|
|
|
|
static inline bool
|
|
IsTypeRepresentableAsDouble(MIRType type)
|
|
{
|
|
return type == MIRType::Int32 ||
|
|
type == MIRType::Double ||
|
|
type == MIRType::Float32;
|
|
}
|
|
|
|
static inline bool
|
|
IsFloatType(MIRType type)
|
|
{
|
|
return type == MIRType::Int32 || type == MIRType::Float32;
|
|
}
|
|
|
|
static inline bool
|
|
IsFloatingPointType(MIRType type)
|
|
{
|
|
return type == MIRType::Double || type == MIRType::Float32;
|
|
}
|
|
|
|
static inline bool
|
|
IsNullOrUndefined(MIRType type)
|
|
{
|
|
return type == MIRType::Null || type == MIRType::Undefined;
|
|
}
|
|
|
|
static inline bool
|
|
IsFloatingPointSimdType(MIRType type)
|
|
{
|
|
return type == MIRType::Float32x4;
|
|
}
|
|
|
|
static inline bool
|
|
IsIntegerSimdType(MIRType type)
|
|
{
|
|
return IsSimdType(type) && SimdTypeToLaneType(type) == MIRType::Int32;
|
|
}
|
|
|
|
static inline bool
|
|
IsBooleanSimdType(MIRType type)
|
|
{
|
|
return IsSimdType(type) && SimdTypeToLaneType(type) == MIRType::Boolean;
|
|
}
|
|
|
|
static inline bool
|
|
IsMagicType(MIRType type)
|
|
{
|
|
return type == MIRType::MagicHole ||
|
|
type == MIRType::MagicOptimizedOut ||
|
|
type == MIRType::MagicIsConstructing ||
|
|
type == MIRType::MagicOptimizedArguments ||
|
|
type == MIRType::MagicUninitializedLexical;
|
|
}
|
|
|
|
static inline MIRType
|
|
ScalarTypeToMIRType(Scalar::Type type)
|
|
{
|
|
switch (type) {
|
|
case Scalar::Int8:
|
|
case Scalar::Uint8:
|
|
case Scalar::Int16:
|
|
case Scalar::Uint16:
|
|
case Scalar::Int32:
|
|
case Scalar::Uint32:
|
|
case Scalar::Uint8Clamped:
|
|
return MIRType::Int32;
|
|
case Scalar::Int64:
|
|
return MIRType::Int64;
|
|
case Scalar::Float32:
|
|
return MIRType::Float32;
|
|
case Scalar::Float64:
|
|
return MIRType::Double;
|
|
case Scalar::Float32x4:
|
|
return MIRType::Float32x4;
|
|
case Scalar::Int8x16:
|
|
return MIRType::Int8x16;
|
|
case Scalar::Int16x8:
|
|
return MIRType::Int16x8;
|
|
case Scalar::Int32x4:
|
|
return MIRType::Int32x4;
|
|
case Scalar::MaxTypedArrayViewType:
|
|
break;
|
|
}
|
|
MOZ_CRASH("unexpected SIMD kind");
|
|
}
|
|
|
|
static inline unsigned
|
|
ScalarTypeToLength(Scalar::Type type)
|
|
{
|
|
switch (type) {
|
|
case Scalar::Int8:
|
|
case Scalar::Uint8:
|
|
case Scalar::Int16:
|
|
case Scalar::Uint16:
|
|
case Scalar::Int32:
|
|
case Scalar::Uint32:
|
|
case Scalar::Int64:
|
|
case Scalar::Float32:
|
|
case Scalar::Float64:
|
|
case Scalar::Uint8Clamped:
|
|
return 1;
|
|
case Scalar::Float32x4:
|
|
case Scalar::Int32x4:
|
|
return 4;
|
|
case Scalar::Int16x8:
|
|
return 8;
|
|
case Scalar::Int8x16:
|
|
return 16;
|
|
case Scalar::MaxTypedArrayViewType:
|
|
break;
|
|
}
|
|
MOZ_CRASH("unexpected SIMD kind");
|
|
}
|
|
|
|
static inline const char*
|
|
PropertyNameToExtraName(PropertyName* name)
|
|
{
|
|
JS::AutoCheckCannotGC nogc;
|
|
if (!name->hasLatin1Chars())
|
|
return nullptr;
|
|
return reinterpret_cast<const char *>(name->latin1Chars(nogc));
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
|
|
// Track the pipeline of opcodes which has produced a snapshot.
|
|
#define TRACK_SNAPSHOTS 1
|
|
|
|
// Make sure registers are not modified between an instruction and
|
|
// its OsiPoint.
|
|
#define CHECK_OSIPOINT_REGISTERS 1
|
|
|
|
#endif // DEBUG
|
|
|
|
enum {
|
|
ArgType_General = 0x1,
|
|
ArgType_Double = 0x2,
|
|
ArgType_Float32 = 0x3,
|
|
ArgType_Int64 = 0x4,
|
|
|
|
RetType_Shift = 0x0,
|
|
ArgType_Shift = 0x3,
|
|
ArgType_Mask = 0x7
|
|
};
|
|
|
|
enum ABIFunctionType
|
|
{
|
|
// VM functions that take 0-9 non-double arguments
|
|
// and return a non-double value.
|
|
Args_General0 = ArgType_General << RetType_Shift,
|
|
Args_General1 = Args_General0 | (ArgType_General << (ArgType_Shift * 1)),
|
|
Args_General2 = Args_General1 | (ArgType_General << (ArgType_Shift * 2)),
|
|
Args_General3 = Args_General2 | (ArgType_General << (ArgType_Shift * 3)),
|
|
Args_General4 = Args_General3 | (ArgType_General << (ArgType_Shift * 4)),
|
|
Args_General5 = Args_General4 | (ArgType_General << (ArgType_Shift * 5)),
|
|
Args_General6 = Args_General5 | (ArgType_General << (ArgType_Shift * 6)),
|
|
Args_General7 = Args_General6 | (ArgType_General << (ArgType_Shift * 7)),
|
|
Args_General8 = Args_General7 | (ArgType_General << (ArgType_Shift * 8)),
|
|
|
|
// int64 f(double)
|
|
Args_Int64_Double = (ArgType_Int64 << RetType_Shift) | (ArgType_Double << ArgType_Shift),
|
|
|
|
// double f()
|
|
Args_Double_None = ArgType_Double << RetType_Shift,
|
|
|
|
// int f(double)
|
|
Args_Int_Double = Args_General0 | (ArgType_Double << ArgType_Shift),
|
|
|
|
// float f(float)
|
|
Args_Float32_Float32 = (ArgType_Float32 << RetType_Shift) | (ArgType_Float32 << ArgType_Shift),
|
|
|
|
// double f(double)
|
|
Args_Double_Double = Args_Double_None | (ArgType_Double << ArgType_Shift),
|
|
|
|
// double f(int)
|
|
Args_Double_Int = Args_Double_None | (ArgType_General << ArgType_Shift),
|
|
|
|
// double f(int, int)
|
|
Args_Double_IntInt = Args_Double_Int | (ArgType_General << (ArgType_Shift * 2)),
|
|
|
|
// double f(double, int)
|
|
Args_Double_DoubleInt = Args_Double_None |
|
|
(ArgType_General << (ArgType_Shift * 1)) |
|
|
(ArgType_Double << (ArgType_Shift * 2)),
|
|
|
|
// double f(double, double)
|
|
Args_Double_DoubleDouble = Args_Double_Double | (ArgType_Double << (ArgType_Shift * 2)),
|
|
|
|
// double f(int, double)
|
|
Args_Double_IntDouble = Args_Double_None |
|
|
(ArgType_Double << (ArgType_Shift * 1)) |
|
|
(ArgType_General << (ArgType_Shift * 2)),
|
|
|
|
// int f(int, double)
|
|
Args_Int_IntDouble = Args_General0 |
|
|
(ArgType_Double << (ArgType_Shift * 1)) |
|
|
(ArgType_General << (ArgType_Shift * 2)),
|
|
|
|
// double f(double, double, double)
|
|
Args_Double_DoubleDoubleDouble = Args_Double_DoubleDouble | (ArgType_Double << (ArgType_Shift * 3)),
|
|
|
|
// double f(double, double, double, double)
|
|
Args_Double_DoubleDoubleDoubleDouble = Args_Double_DoubleDoubleDouble | (ArgType_Double << (ArgType_Shift * 4)),
|
|
|
|
// int f(double, int, int)
|
|
Args_Int_DoubleIntInt = Args_General0 |
|
|
(ArgType_General << (ArgType_Shift * 1)) |
|
|
(ArgType_General << (ArgType_Shift * 2)) |
|
|
(ArgType_Double << (ArgType_Shift * 3)),
|
|
|
|
// int f(int, double, int, int)
|
|
Args_Int_IntDoubleIntInt = Args_General0 |
|
|
(ArgType_General << (ArgType_Shift * 1)) |
|
|
(ArgType_General << (ArgType_Shift * 2)) |
|
|
(ArgType_Double << (ArgType_Shift * 3)) |
|
|
(ArgType_General << (ArgType_Shift * 4))
|
|
|
|
};
|
|
|
|
enum class BarrierKind : uint32_t {
|
|
// No barrier is needed.
|
|
NoBarrier,
|
|
|
|
// The barrier only has to check the value's type tag is in the TypeSet.
|
|
// Specific object types don't have to be checked.
|
|
TypeTagOnly,
|
|
|
|
// Check if the value is in the TypeSet, including the object type if it's
|
|
// an object.
|
|
TypeSet
|
|
};
|
|
|
|
enum ReprotectCode { Reprotect = true, DontReprotect = false };
|
|
|
|
} // namespace jit
|
|
} // namespace js
|
|
|
|
#endif /* jit_IonTypes_h */
|