michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * vim: set ts=8 sts=4 et sw=4 tw=99: michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef jit_TypePolicy_h michael@0: #define jit_TypePolicy_h michael@0: michael@0: #include "jit/IonAllocPolicy.h" michael@0: #include "jit/IonTypes.h" michael@0: michael@0: namespace js { michael@0: namespace jit { michael@0: michael@0: class MInstruction; michael@0: class MDefinition; michael@0: michael@0: // A type policy directs the type analysis phases, which insert conversion, michael@0: // boxing, unboxing, and type changes as necessary. michael@0: class TypePolicy michael@0: { michael@0: public: michael@0: // Analyze the inputs of the instruction and perform one of the following michael@0: // actions for each input: michael@0: // * Nothing; the input already type-checks. michael@0: // * If untyped, optionally ask the input to try and specialize its value. michael@0: // * Replace the operand with a conversion instruction. michael@0: // * Insert an unconditional deoptimization (no conversion possible). michael@0: virtual bool adjustInputs(TempAllocator &alloc, MInstruction *def) = 0; michael@0: }; michael@0: michael@0: class BoxInputsPolicy : public TypePolicy michael@0: { michael@0: protected: michael@0: static MDefinition *boxAt(TempAllocator &alloc, MInstruction *at, MDefinition *operand); michael@0: michael@0: public: michael@0: static MDefinition *alwaysBoxAt(TempAllocator &alloc, MInstruction *at, MDefinition *operand); michael@0: virtual bool adjustInputs(TempAllocator &alloc, MInstruction *def); michael@0: }; michael@0: michael@0: class ArithPolicy : public BoxInputsPolicy michael@0: { michael@0: protected: michael@0: // Specifies three levels of specialization: michael@0: // - < Value. This input is expected and required. michael@0: // - == Any. Inputs are probably primitive. michael@0: // - == None. This op should not be specialized. michael@0: MIRType specialization_; michael@0: michael@0: public: michael@0: bool adjustInputs(TempAllocator &alloc, MInstruction *def); michael@0: }; michael@0: michael@0: class BitwisePolicy : public BoxInputsPolicy michael@0: { michael@0: protected: michael@0: // Specifies three levels of specialization: michael@0: // - < Value. This input is expected and required. michael@0: // - == Any. Inputs are probably primitive. michael@0: // - == None. This op should not be specialized. michael@0: MIRType specialization_; michael@0: michael@0: public: michael@0: bool adjustInputs(TempAllocator &alloc, MInstruction *def); michael@0: michael@0: MIRType specialization() const { michael@0: return specialization_; michael@0: } michael@0: }; michael@0: michael@0: class ComparePolicy : public BoxInputsPolicy michael@0: { michael@0: bool adjustInputs(TempAllocator &alloc, MInstruction *def); michael@0: }; michael@0: michael@0: // Policy for MTest instructions. michael@0: class TestPolicy : public BoxInputsPolicy michael@0: { michael@0: public: michael@0: bool adjustInputs(TempAllocator &alloc, MInstruction *ins); michael@0: }; michael@0: michael@0: class TypeBarrierPolicy : public BoxInputsPolicy michael@0: { michael@0: public: michael@0: bool adjustInputs(TempAllocator &alloc, MInstruction *ins); michael@0: }; michael@0: michael@0: class CallPolicy : public BoxInputsPolicy michael@0: { michael@0: public: michael@0: bool adjustInputs(TempAllocator &alloc, MInstruction *def); michael@0: }; michael@0: michael@0: // Policy for MPow. First operand Double; second Double or Int32. michael@0: class PowPolicy : public BoxInputsPolicy michael@0: { michael@0: MIRType specialization_; michael@0: michael@0: public: michael@0: PowPolicy(MIRType specialization) michael@0: : specialization_(specialization) michael@0: { } michael@0: michael@0: bool adjustInputs(TempAllocator &alloc, MInstruction *ins); michael@0: }; michael@0: michael@0: // Expect a string for operand Op. If the input is a Value, it is unboxed. michael@0: template michael@0: class StringPolicy : public BoxInputsPolicy michael@0: { michael@0: public: michael@0: static bool staticAdjustInputs(TempAllocator &alloc, MInstruction *def); michael@0: bool adjustInputs(TempAllocator &alloc, MInstruction *def) { michael@0: return staticAdjustInputs(alloc, def); michael@0: } michael@0: }; michael@0: michael@0: // Expect a string for operand Op. Else a ToString instruction is inserted. michael@0: template michael@0: class ConvertToStringPolicy : public BoxInputsPolicy michael@0: { michael@0: public: michael@0: static bool staticAdjustInputs(TempAllocator &alloc, MInstruction *def); michael@0: bool adjustInputs(TempAllocator &alloc, MInstruction *def) { michael@0: return staticAdjustInputs(alloc, def); michael@0: } michael@0: }; michael@0: michael@0: // Expect an Int for operand Op. If the input is a Value, it is unboxed. michael@0: template michael@0: class IntPolicy : public BoxInputsPolicy michael@0: { michael@0: public: michael@0: static bool staticAdjustInputs(TempAllocator &alloc, MInstruction *def); michael@0: bool adjustInputs(TempAllocator &alloc, MInstruction *def) { michael@0: return staticAdjustInputs(alloc, def); michael@0: } michael@0: }; michael@0: michael@0: // Expect an Int for operand Op. Else a ToInt32 instruction is inserted. michael@0: template michael@0: class ConvertToInt32Policy : public BoxInputsPolicy michael@0: { michael@0: public: michael@0: static bool staticAdjustInputs(TempAllocator &alloc, MInstruction *def); michael@0: bool adjustInputs(TempAllocator &alloc, MInstruction *def) { michael@0: return staticAdjustInputs(alloc, def); michael@0: } michael@0: }; michael@0: michael@0: // Expect a double for operand Op. If the input is a Value, it is unboxed. michael@0: template michael@0: class DoublePolicy : public BoxInputsPolicy michael@0: { michael@0: public: michael@0: static bool staticAdjustInputs(TempAllocator &alloc, MInstruction *def); michael@0: bool adjustInputs(TempAllocator &alloc, MInstruction *def) { michael@0: return staticAdjustInputs(alloc, def); michael@0: } michael@0: }; michael@0: michael@0: // Expect a float32 for operand Op. If the input is a Value, it is unboxed. michael@0: template michael@0: class Float32Policy : public BoxInputsPolicy michael@0: { michael@0: public: michael@0: static bool staticAdjustInputs(TempAllocator &alloc, MInstruction *def); michael@0: bool adjustInputs(TempAllocator &alloc, MInstruction *def) { michael@0: return staticAdjustInputs(alloc, def); michael@0: } michael@0: }; michael@0: michael@0: // Expect a float32 OR a double for operand Op, but will prioritize Float32 michael@0: // if the result type is set as such. If the input is a Value, it is unboxed. michael@0: template michael@0: class FloatingPointPolicy : public TypePolicy michael@0: { michael@0: MIRType policyType_; michael@0: michael@0: public: michael@0: bool adjustInputs(TempAllocator &alloc, MInstruction *def) { michael@0: if (policyType_ == MIRType_Double) michael@0: return DoublePolicy::staticAdjustInputs(alloc, def); michael@0: return Float32Policy::staticAdjustInputs(alloc, def); michael@0: } michael@0: void setPolicyType(MIRType type) { michael@0: policyType_ = type; michael@0: } michael@0: }; michael@0: michael@0: template michael@0: class NoFloatPolicy : public TypePolicy michael@0: { michael@0: public: michael@0: static bool staticAdjustInputs(TempAllocator &alloc, MInstruction *def); michael@0: bool adjustInputs(TempAllocator &alloc, MInstruction *def) { michael@0: return staticAdjustInputs(alloc, def); michael@0: } michael@0: }; michael@0: michael@0: // Box objects or strings as an input to a ToDouble instruction. michael@0: class ToDoublePolicy : public BoxInputsPolicy michael@0: { michael@0: public: michael@0: static bool staticAdjustInputs(TempAllocator &alloc, MInstruction *def); michael@0: bool adjustInputs(TempAllocator &alloc, MInstruction *def) { michael@0: return staticAdjustInputs(alloc, def); michael@0: } michael@0: }; michael@0: michael@0: // Box objects, strings and undefined as input to a ToInt32 instruction. michael@0: class ToInt32Policy : public BoxInputsPolicy michael@0: { michael@0: public: michael@0: static bool staticAdjustInputs(TempAllocator &alloc, MInstruction *def); michael@0: bool adjustInputs(TempAllocator &alloc, MInstruction *def) { michael@0: return staticAdjustInputs(alloc, def); michael@0: } michael@0: }; michael@0: michael@0: template michael@0: class ObjectPolicy : public BoxInputsPolicy michael@0: { michael@0: public: michael@0: static bool staticAdjustInputs(TempAllocator &alloc, MInstruction *ins); michael@0: bool adjustInputs(TempAllocator &alloc, MInstruction *ins) { michael@0: return staticAdjustInputs(alloc, ins); michael@0: } michael@0: }; michael@0: michael@0: // Single-object input. If the input is a Value, it is unboxed. If it is michael@0: // a primitive, we use ValueToNonNullObject. michael@0: class SingleObjectPolicy : public ObjectPolicy<0> michael@0: { }; michael@0: michael@0: template michael@0: class BoxPolicy : public BoxInputsPolicy michael@0: { michael@0: public: michael@0: static bool staticAdjustInputs(TempAllocator &alloc, MInstruction *ins); michael@0: bool adjustInputs(TempAllocator &alloc, MInstruction *ins) { michael@0: return staticAdjustInputs(alloc, ins); michael@0: } michael@0: }; michael@0: michael@0: // Boxes everything except inputs of type Type. michael@0: template michael@0: class BoxExceptPolicy : public TypePolicy michael@0: { michael@0: public: michael@0: static bool staticAdjustInputs(TempAllocator &alloc, MInstruction *ins); michael@0: bool adjustInputs(TempAllocator &alloc, MInstruction *ins) { michael@0: return staticAdjustInputs(alloc, ins); michael@0: } michael@0: }; michael@0: michael@0: // Combine multiple policies. michael@0: template michael@0: class MixPolicy : public TypePolicy michael@0: { michael@0: public: michael@0: static bool staticAdjustInputs(TempAllocator &alloc, MInstruction *ins) { michael@0: return Lhs::staticAdjustInputs(alloc, ins) && Rhs::staticAdjustInputs(alloc, ins); michael@0: } michael@0: virtual bool adjustInputs(TempAllocator &alloc, MInstruction *ins) { michael@0: return staticAdjustInputs(alloc, ins); michael@0: } michael@0: }; michael@0: michael@0: // Combine three policies. michael@0: template michael@0: class Mix3Policy : public TypePolicy michael@0: { michael@0: public: michael@0: static bool staticAdjustInputs(TempAllocator &alloc, MInstruction *ins) { michael@0: return Policy1::staticAdjustInputs(alloc, ins) && michael@0: Policy2::staticAdjustInputs(alloc, ins) && michael@0: Policy3::staticAdjustInputs(alloc, ins); michael@0: } michael@0: virtual bool adjustInputs(TempAllocator &alloc, MInstruction *ins) { michael@0: return staticAdjustInputs(alloc, ins); michael@0: } michael@0: }; michael@0: michael@0: class CallSetElementPolicy : public SingleObjectPolicy michael@0: { michael@0: public: michael@0: bool adjustInputs(TempAllocator &alloc, MInstruction *def); michael@0: }; michael@0: michael@0: // First operand will be boxed to a Value (except for an object) michael@0: // Second operand (if specified) will forcefully be unboxed to an object michael@0: class InstanceOfPolicy : public TypePolicy michael@0: { michael@0: public: michael@0: bool adjustInputs(TempAllocator &alloc, MInstruction *def); michael@0: }; michael@0: michael@0: class StoreTypedArrayPolicy : public BoxInputsPolicy michael@0: { michael@0: protected: michael@0: bool adjustValueInput(TempAllocator &alloc, MInstruction *ins, int arrayType, MDefinition *value, int valueOperand); michael@0: michael@0: public: michael@0: bool adjustInputs(TempAllocator &alloc, MInstruction *ins); michael@0: }; michael@0: michael@0: class StoreTypedArrayHolePolicy : public StoreTypedArrayPolicy michael@0: { michael@0: public: michael@0: bool adjustInputs(TempAllocator &alloc, MInstruction *ins); michael@0: }; michael@0: michael@0: class StoreTypedArrayElementStaticPolicy : public StoreTypedArrayPolicy michael@0: { michael@0: public: michael@0: bool adjustInputs(TempAllocator &alloc, MInstruction *ins); michael@0: }; michael@0: michael@0: // Accepts integers and doubles. Everything else is boxed. michael@0: class ClampPolicy : public BoxInputsPolicy michael@0: { michael@0: public: michael@0: bool adjustInputs(TempAllocator &alloc, MInstruction *ins); michael@0: }; michael@0: michael@0: class FilterTypeSetPolicy : public BoxInputsPolicy michael@0: { michael@0: public: michael@0: bool adjustInputs(TempAllocator &alloc, MInstruction *ins); michael@0: }; michael@0: michael@0: static inline bool michael@0: CoercesToDouble(MIRType type) michael@0: { michael@0: if (type == MIRType_Undefined || IsFloatingPointType(type)) michael@0: return true; michael@0: return false; michael@0: } michael@0: michael@0: michael@0: } // namespace jit michael@0: } // namespace js michael@0: michael@0: #endif /* jit_TypePolicy_h */