mirror of
https://github.com/classilla/tenfourfox.git
synced 2024-06-24 07:29:44 +00:00
532 lines
15 KiB
C++
532 lines
15 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_TypePolicy_h
|
|
#define jit_TypePolicy_h
|
|
|
|
#include "jit/IonTypes.h"
|
|
#include "jit/JitAllocPolicy.h"
|
|
|
|
namespace js {
|
|
namespace jit {
|
|
|
|
class MInstruction;
|
|
class MDefinition;
|
|
|
|
extern MDefinition*
|
|
AlwaysBoxAt(TempAllocator& alloc, MInstruction* at, MDefinition* operand);
|
|
|
|
// A type policy directs the type analysis phases, which insert conversion,
|
|
// boxing, unboxing, and type changes as necessary.
|
|
class TypePolicy
|
|
{
|
|
public:
|
|
// Analyze the inputs of the instruction and perform one of the following
|
|
// actions for each input:
|
|
// * Nothing; the input already type-checks.
|
|
// * If untyped, optionally ask the input to try and specialize its value.
|
|
// * Replace the operand with a conversion instruction.
|
|
// * Insert an unconditional deoptimization (no conversion possible).
|
|
virtual bool adjustInputs(TempAllocator& alloc, MInstruction* def) = 0;
|
|
};
|
|
|
|
struct TypeSpecializationData
|
|
{
|
|
protected:
|
|
// Specifies three levels of specialization:
|
|
// - < Value. This input is expected and required.
|
|
// - == None. This op should not be specialized.
|
|
MIRType specialization_;
|
|
|
|
MIRType thisTypeSpecialization() {
|
|
return specialization_;
|
|
}
|
|
|
|
public:
|
|
MIRType specialization() const {
|
|
return specialization_;
|
|
}
|
|
};
|
|
|
|
#define EMPTY_DATA_ \
|
|
struct Data \
|
|
{ \
|
|
static TypePolicy* thisTypePolicy(); \
|
|
}
|
|
|
|
#define INHERIT_DATA_(DATA_TYPE) \
|
|
struct Data : public DATA_TYPE \
|
|
{ \
|
|
static TypePolicy* thisTypePolicy(); \
|
|
}
|
|
|
|
#define SPECIALIZATION_DATA_ INHERIT_DATA_(TypeSpecializationData)
|
|
|
|
class NoTypePolicy
|
|
{
|
|
public:
|
|
struct Data
|
|
{
|
|
static TypePolicy* thisTypePolicy() {
|
|
return nullptr;
|
|
}
|
|
};
|
|
};
|
|
|
|
class BoxInputsPolicy final : public TypePolicy
|
|
{
|
|
public:
|
|
SPECIALIZATION_DATA_;
|
|
static bool staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
|
|
virtual bool adjustInputs(TempAllocator& alloc, MInstruction* def) override {
|
|
return staticAdjustInputs(alloc, def);
|
|
}
|
|
};
|
|
|
|
class ArithPolicy final : public TypePolicy
|
|
{
|
|
public:
|
|
SPECIALIZATION_DATA_;
|
|
virtual bool adjustInputs(TempAllocator& alloc, MInstruction* def) override;
|
|
};
|
|
|
|
class AllDoublePolicy final : public TypePolicy
|
|
{
|
|
public:
|
|
EMPTY_DATA_;
|
|
bool adjustInputs(TempAllocator& alloc, MInstruction* def);
|
|
};
|
|
|
|
class BitwisePolicy final : public TypePolicy
|
|
{
|
|
public:
|
|
SPECIALIZATION_DATA_;
|
|
virtual bool adjustInputs(TempAllocator& alloc, MInstruction* def) override;
|
|
};
|
|
|
|
class ComparePolicy final : public TypePolicy
|
|
{
|
|
public:
|
|
EMPTY_DATA_;
|
|
virtual bool adjustInputs(TempAllocator& alloc, MInstruction* def) override;
|
|
};
|
|
|
|
// Policy for MTest instructions.
|
|
class TestPolicy final : public TypePolicy
|
|
{
|
|
public:
|
|
EMPTY_DATA_;
|
|
virtual bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override;
|
|
};
|
|
|
|
class TypeBarrierPolicy final : public TypePolicy
|
|
{
|
|
public:
|
|
EMPTY_DATA_;
|
|
virtual bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override;
|
|
};
|
|
|
|
class CallPolicy final : public TypePolicy
|
|
{
|
|
public:
|
|
EMPTY_DATA_;
|
|
virtual bool adjustInputs(TempAllocator& alloc, MInstruction* def) override;
|
|
};
|
|
|
|
// Policy for MPow. First operand Double; second Double or Int32.
|
|
class PowPolicy final : public TypePolicy
|
|
{
|
|
public:
|
|
SPECIALIZATION_DATA_;
|
|
virtual bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override;
|
|
};
|
|
|
|
// Expect a string for operand Op. If the input is a Value, it is unboxed.
|
|
template <unsigned Op>
|
|
class StringPolicy final : public TypePolicy
|
|
{
|
|
public:
|
|
EMPTY_DATA_;
|
|
static bool staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
|
|
virtual bool adjustInputs(TempAllocator& alloc, MInstruction* def) override {
|
|
return staticAdjustInputs(alloc, def);
|
|
}
|
|
};
|
|
|
|
// Expect a string for operand Op. Else a ToString instruction is inserted.
|
|
template <unsigned Op>
|
|
class ConvertToStringPolicy final : public TypePolicy
|
|
{
|
|
public:
|
|
EMPTY_DATA_;
|
|
static bool staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
|
|
virtual bool adjustInputs(TempAllocator& alloc, MInstruction* def) override {
|
|
return staticAdjustInputs(alloc, def);
|
|
}
|
|
};
|
|
|
|
// Expect an Int for operand Op. If the input is a Value, it is unboxed.
|
|
template <unsigned Op>
|
|
class IntPolicy final : private TypePolicy
|
|
{
|
|
public:
|
|
EMPTY_DATA_;
|
|
static bool staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
|
|
virtual bool adjustInputs(TempAllocator& alloc, MInstruction* def) override {
|
|
return staticAdjustInputs(alloc, def);
|
|
}
|
|
};
|
|
|
|
// Expect an Int for operand Op. Else a ToInt32 instruction is inserted.
|
|
template <unsigned Op>
|
|
class ConvertToInt32Policy final : public TypePolicy
|
|
{
|
|
public:
|
|
EMPTY_DATA_;
|
|
static bool staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
|
|
virtual bool adjustInputs(TempAllocator& alloc, MInstruction* def) override {
|
|
return staticAdjustInputs(alloc, def);
|
|
}
|
|
};
|
|
|
|
// Expect an Int for operand Op. Else a TruncateToInt32 instruction is inserted.
|
|
template <unsigned Op>
|
|
class TruncateToInt32Policy final : public TypePolicy
|
|
{
|
|
public:
|
|
EMPTY_DATA_;
|
|
static bool staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
|
|
virtual bool adjustInputs(TempAllocator& alloc, MInstruction* def) override {
|
|
return staticAdjustInputs(alloc, def);
|
|
}
|
|
};
|
|
|
|
// Expect a double for operand Op. If the input is a Value, it is unboxed.
|
|
template <unsigned Op>
|
|
class DoublePolicy final : public TypePolicy
|
|
{
|
|
public:
|
|
EMPTY_DATA_;
|
|
static bool staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
|
|
virtual bool adjustInputs(TempAllocator& alloc, MInstruction* def) override {
|
|
return staticAdjustInputs(alloc, def);
|
|
}
|
|
};
|
|
|
|
// Expect a float32 for operand Op. If the input is a Value, it is unboxed.
|
|
template <unsigned Op>
|
|
class Float32Policy final : public TypePolicy
|
|
{
|
|
public:
|
|
EMPTY_DATA_;
|
|
static bool staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
|
|
virtual bool adjustInputs(TempAllocator& alloc, MInstruction* def) override {
|
|
return staticAdjustInputs(alloc, def);
|
|
}
|
|
};
|
|
|
|
// Expect a float32 OR a double for operand Op, but will prioritize Float32
|
|
// if the result type is set as such. If the input is a Value, it is unboxed.
|
|
template <unsigned Op>
|
|
class FloatingPointPolicy final : public TypePolicy
|
|
{
|
|
public:
|
|
SPECIALIZATION_DATA_;
|
|
virtual bool adjustInputs(TempAllocator& alloc, MInstruction* def) override;
|
|
};
|
|
|
|
template <unsigned Op>
|
|
class NoFloatPolicy final : public TypePolicy
|
|
{
|
|
public:
|
|
EMPTY_DATA_;
|
|
static bool staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
|
|
virtual bool adjustInputs(TempAllocator& alloc, MInstruction* def) override {
|
|
return staticAdjustInputs(alloc, def);
|
|
}
|
|
};
|
|
|
|
// Policy for guarding variadic instructions such as object / array state
|
|
// instructions.
|
|
template <unsigned FirstOp>
|
|
class NoFloatPolicyAfter final : public TypePolicy
|
|
{
|
|
public:
|
|
EMPTY_DATA_;
|
|
virtual bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override;
|
|
};
|
|
|
|
// Box objects or strings as an input to a ToDouble instruction.
|
|
class ToDoublePolicy final : public TypePolicy
|
|
{
|
|
public:
|
|
EMPTY_DATA_;
|
|
static bool staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
|
|
virtual bool adjustInputs(TempAllocator& alloc, MInstruction* def) override {
|
|
return staticAdjustInputs(alloc, def);
|
|
}
|
|
};
|
|
|
|
// Box objects, strings and undefined as input to a ToInt32 instruction.
|
|
class ToInt32Policy final : public TypePolicy
|
|
{
|
|
public:
|
|
EMPTY_DATA_;
|
|
static bool staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
|
|
virtual bool adjustInputs(TempAllocator& alloc, MInstruction* def) override {
|
|
return staticAdjustInputs(alloc, def);
|
|
}
|
|
};
|
|
|
|
// Box objects as input to a ToString instruction.
|
|
class ToStringPolicy final : public TypePolicy
|
|
{
|
|
public:
|
|
EMPTY_DATA_;
|
|
static bool staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
|
|
virtual bool adjustInputs(TempAllocator& alloc, MInstruction* def) override {
|
|
return staticAdjustInputs(alloc, def);
|
|
}
|
|
};
|
|
|
|
template <unsigned Op>
|
|
class ObjectPolicy final : public TypePolicy
|
|
{
|
|
public:
|
|
EMPTY_DATA_;
|
|
static bool staticAdjustInputs(TempAllocator& alloc, MInstruction* ins);
|
|
virtual bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override {
|
|
return staticAdjustInputs(alloc, ins);
|
|
}
|
|
};
|
|
|
|
// Single-object input. If the input is a Value, it is unboxed. If it is
|
|
// a primitive, we use ValueToNonNullObject.
|
|
typedef ObjectPolicy<0> SingleObjectPolicy;
|
|
|
|
// Convert an operand to have a type identical to the scalar type of the
|
|
// returned type of the instruction.
|
|
template <unsigned Op>
|
|
class SimdScalarPolicy final : public TypePolicy
|
|
{
|
|
public:
|
|
EMPTY_DATA_;
|
|
static bool staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
|
|
virtual bool adjustInputs(TempAllocator& alloc, MInstruction* def) override {
|
|
return staticAdjustInputs(alloc, def);
|
|
}
|
|
};
|
|
|
|
class SimdAllPolicy final : public TypePolicy
|
|
{
|
|
public:
|
|
SPECIALIZATION_DATA_;
|
|
virtual bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override;
|
|
};
|
|
|
|
template <unsigned Op>
|
|
class SimdPolicy final : public TypePolicy
|
|
{
|
|
public:
|
|
SPECIALIZATION_DATA_;
|
|
virtual bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override;
|
|
};
|
|
|
|
class SimdSelectPolicy final : public TypePolicy
|
|
{
|
|
public:
|
|
SPECIALIZATION_DATA_;
|
|
virtual bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override;
|
|
};
|
|
|
|
class SimdShufflePolicy final : public TypePolicy
|
|
{
|
|
public:
|
|
SPECIALIZATION_DATA_;
|
|
virtual bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override;
|
|
};
|
|
|
|
// SIMD value-type policy, use the returned type of the instruction to determine
|
|
// how to unbox its operand.
|
|
template <unsigned Op>
|
|
class SimdSameAsReturnedTypePolicy final : public TypePolicy
|
|
{
|
|
public:
|
|
EMPTY_DATA_;
|
|
static bool staticAdjustInputs(TempAllocator& alloc, MInstruction* ins);
|
|
virtual bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override {
|
|
return staticAdjustInputs(alloc, ins);
|
|
}
|
|
};
|
|
|
|
template <unsigned Op>
|
|
class BoxPolicy final : public TypePolicy
|
|
{
|
|
public:
|
|
EMPTY_DATA_;
|
|
static bool staticAdjustInputs(TempAllocator& alloc, MInstruction* ins);
|
|
virtual bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override {
|
|
return staticAdjustInputs(alloc, ins);
|
|
}
|
|
};
|
|
|
|
// Boxes everything except inputs of type Type.
|
|
template <unsigned Op, MIRType Type>
|
|
class BoxExceptPolicy final : public TypePolicy
|
|
{
|
|
public:
|
|
EMPTY_DATA_;
|
|
static bool staticAdjustInputs(TempAllocator& alloc, MInstruction* ins);
|
|
bool adjustInputs(TempAllocator& alloc, MInstruction* ins) {
|
|
return staticAdjustInputs(alloc, ins);
|
|
}
|
|
};
|
|
|
|
// Box if not a typical property id (string, symbol, int32).
|
|
template <unsigned Op>
|
|
class CacheIdPolicy final : public TypePolicy
|
|
{
|
|
public:
|
|
EMPTY_DATA_;
|
|
static bool staticAdjustInputs(TempAllocator& alloc, MInstruction* ins);
|
|
bool adjustInputs(TempAllocator& alloc, MInstruction* ins) {
|
|
return staticAdjustInputs(alloc, ins);
|
|
}
|
|
};
|
|
|
|
// Combine multiple policies.
|
|
template <class Lhs, class Rhs>
|
|
class MixPolicy final : public TypePolicy
|
|
{
|
|
public:
|
|
EMPTY_DATA_;
|
|
static bool staticAdjustInputs(TempAllocator& alloc, MInstruction* ins) {
|
|
return Lhs::staticAdjustInputs(alloc, ins) && Rhs::staticAdjustInputs(alloc, ins);
|
|
}
|
|
virtual bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override {
|
|
return staticAdjustInputs(alloc, ins);
|
|
}
|
|
};
|
|
|
|
// Combine three policies.
|
|
template <class Policy1, class Policy2, class Policy3>
|
|
class Mix3Policy final : public TypePolicy
|
|
{
|
|
public:
|
|
EMPTY_DATA_;
|
|
static bool staticAdjustInputs(TempAllocator& alloc, MInstruction* ins) {
|
|
return Policy1::staticAdjustInputs(alloc, ins) &&
|
|
Policy2::staticAdjustInputs(alloc, ins) &&
|
|
Policy3::staticAdjustInputs(alloc, ins);
|
|
}
|
|
virtual bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override {
|
|
return staticAdjustInputs(alloc, ins);
|
|
}
|
|
};
|
|
|
|
// Combine four policies. (Missing variadic templates yet?)
|
|
template <class Policy1, class Policy2, class Policy3, class Policy4>
|
|
class Mix4Policy : public TypePolicy
|
|
{
|
|
public:
|
|
EMPTY_DATA_;
|
|
static bool staticAdjustInputs(TempAllocator& alloc, MInstruction* ins) {
|
|
return Policy1::staticAdjustInputs(alloc, ins) &&
|
|
Policy2::staticAdjustInputs(alloc, ins) &&
|
|
Policy3::staticAdjustInputs(alloc, ins) &&
|
|
Policy4::staticAdjustInputs(alloc, ins);
|
|
}
|
|
virtual bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override {
|
|
return staticAdjustInputs(alloc, ins);
|
|
}
|
|
};
|
|
|
|
class CallSetElementPolicy final : public TypePolicy
|
|
{
|
|
public:
|
|
EMPTY_DATA_;
|
|
virtual bool adjustInputs(TempAllocator& alloc, MInstruction* def) override;
|
|
};
|
|
|
|
// First operand will be boxed to a Value (except for an object)
|
|
// Second operand (if specified) will forcefully be unboxed to an object
|
|
class InstanceOfPolicy final : public TypePolicy
|
|
{
|
|
public:
|
|
EMPTY_DATA_;
|
|
virtual bool adjustInputs(TempAllocator& alloc, MInstruction* def) override;
|
|
};
|
|
|
|
class StoreTypedArrayHolePolicy;
|
|
class StoreTypedArrayElementStaticPolicy;
|
|
|
|
class StoreUnboxedScalarPolicy : public TypePolicy
|
|
{
|
|
private:
|
|
static bool adjustValueInput(TempAllocator& alloc, MInstruction* ins, Scalar::Type arrayType,
|
|
MDefinition* value, int valueOperand);
|
|
|
|
friend class StoreTypedArrayHolePolicy;
|
|
friend class StoreTypedArrayElementStaticPolicy;
|
|
|
|
public:
|
|
EMPTY_DATA_;
|
|
virtual bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override;
|
|
};
|
|
|
|
class StoreTypedArrayHolePolicy final : public StoreUnboxedScalarPolicy
|
|
{
|
|
public:
|
|
EMPTY_DATA_;
|
|
virtual bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override;
|
|
};
|
|
|
|
class StoreTypedArrayElementStaticPolicy final : public StoreUnboxedScalarPolicy
|
|
{
|
|
public:
|
|
EMPTY_DATA_;
|
|
virtual bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override;
|
|
};
|
|
|
|
class StoreUnboxedObjectOrNullPolicy final : public TypePolicy
|
|
{
|
|
public:
|
|
EMPTY_DATA_;
|
|
virtual bool adjustInputs(TempAllocator& alloc, MInstruction* def) override;
|
|
};
|
|
|
|
// Accepts integers and doubles. Everything else is boxed.
|
|
class ClampPolicy final : public TypePolicy
|
|
{
|
|
public:
|
|
EMPTY_DATA_;
|
|
virtual bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override;
|
|
};
|
|
|
|
class FilterTypeSetPolicy final : public TypePolicy
|
|
{
|
|
public:
|
|
EMPTY_DATA_;
|
|
virtual bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override;
|
|
};
|
|
|
|
static inline bool
|
|
CoercesToDouble(MIRType type)
|
|
{
|
|
if (type == MIRType_Undefined || IsFloatingPointType(type))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
#undef SPECIALIZATION_DATA_
|
|
#undef INHERIT_DATA_
|
|
#undef EMPTY_DATA_
|
|
|
|
} // namespace jit
|
|
} // namespace js
|
|
|
|
#endif /* jit_TypePolicy_h */
|