diff options
author | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
---|---|---|
committer | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
commit | 5f8de423f190bbb79a62f804151bc24824fa32d8 (patch) | |
tree | 10027f336435511475e392454359edea8e25895d /js/src/jit/TypePolicy.cpp | |
parent | 49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff) | |
download | UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip |
Add m-esr52 at 52.6.0
Diffstat (limited to 'js/src/jit/TypePolicy.cpp')
-rw-r--r-- | js/src/jit/TypePolicy.cpp | 1330 |
1 files changed, 1330 insertions, 0 deletions
diff --git a/js/src/jit/TypePolicy.cpp b/js/src/jit/TypePolicy.cpp new file mode 100644 index 000000000..2a7480c39 --- /dev/null +++ b/js/src/jit/TypePolicy.cpp @@ -0,0 +1,1330 @@ +/* -*- 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/. */ + +#include "jit/TypePolicy.h" + +#include "jit/Lowering.h" +#include "jit/MIR.h" +#include "jit/MIRGraph.h" + +#include "jit/shared/Lowering-shared-inl.h" + +using namespace js; +using namespace js::jit; + +using JS::DoubleNaNValue; + +static void +EnsureOperandNotFloat32(TempAllocator& alloc, MInstruction* def, unsigned op) +{ + MDefinition* in = def->getOperand(op); + if (in->type() == MIRType::Float32) { + MToDouble* replace = MToDouble::New(alloc, in); + def->block()->insertBefore(def, replace); + if (def->isRecoveredOnBailout()) + replace->setRecoveredOnBailout(); + def->replaceOperand(op, replace); + } +} + +MDefinition* +js::jit::AlwaysBoxAt(TempAllocator& alloc, MInstruction* at, MDefinition* operand) +{ + MDefinition* boxedOperand = operand; + // Replace Float32 by double + if (operand->type() == MIRType::Float32) { + MInstruction* replace = MToDouble::New(alloc, operand); + at->block()->insertBefore(at, replace); + boxedOperand = replace; + } + MBox* box = MBox::New(alloc, boxedOperand); + at->block()->insertBefore(at, box); + return box; +} + +static MDefinition* +BoxAt(TempAllocator& alloc, MInstruction* at, MDefinition* operand) +{ + if (operand->isUnbox()) + return operand->toUnbox()->input(); + return AlwaysBoxAt(alloc, at, operand); +} + +bool +BoxInputsPolicy::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins) +{ + for (size_t i = 0, e = ins->numOperands(); i < e; i++) { + MDefinition* in = ins->getOperand(i); + if (in->type() == MIRType::Value) + continue; + ins->replaceOperand(i, BoxAt(alloc, ins, in)); + } + return true; +} + +bool +ArithPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) +{ + MIRType specialization = ins->typePolicySpecialization(); + if (specialization == MIRType::None) + return BoxInputsPolicy::staticAdjustInputs(alloc, ins); + + MOZ_ASSERT(ins->type() == MIRType::Double || ins->type() == MIRType::Int32 || ins->type() == MIRType::Float32); + + for (size_t i = 0, e = ins->numOperands(); i < e; i++) { + MDefinition* in = ins->getOperand(i); + if (in->type() == ins->type()) + continue; + + MInstruction* replace; + + if (ins->type() == MIRType::Double) + replace = MToDouble::New(alloc, in); + else if (ins->type() == MIRType::Float32) + replace = MToFloat32::New(alloc, in); + else + replace = MToInt32::New(alloc, in); + + ins->block()->insertBefore(ins, replace); + ins->replaceOperand(i, replace); + + if (!replace->typePolicy()->adjustInputs(alloc, replace)) + return false; + } + + return true; +} + +bool +AllDoublePolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) +{ + for (size_t i = 0, e = ins->numOperands(); i < e; i++) { + MDefinition* in = ins->getOperand(i); + if (in->type() == MIRType::Double) + continue; + + if (!alloc.ensureBallast()) + return false; + MInstruction* replace = MToDouble::New(alloc, in); + + ins->block()->insertBefore(ins, replace); + ins->replaceOperand(i, replace); + + if (!replace->typePolicy()->adjustInputs(alloc, replace)) + return false; + } + + return true; +} + +bool +ComparePolicy::adjustInputs(TempAllocator& alloc, MInstruction* def) +{ + MOZ_ASSERT(def->isCompare()); + MCompare* compare = def->toCompare(); + + // Convert Float32 operands to doubles + for (size_t i = 0; i < 2; i++) { + MDefinition* in = def->getOperand(i); + if (in->type() == MIRType::Float32) { + MInstruction* replace = MToDouble::New(alloc, in); + def->block()->insertBefore(def, replace); + def->replaceOperand(i, replace); + } + } + + // Box inputs to get value + if (compare->compareType() == MCompare::Compare_Unknown || + compare->compareType() == MCompare::Compare_Bitwise) + { + return BoxInputsPolicy::staticAdjustInputs(alloc, def); + } + + // Compare_Boolean specialization is done for "Anything === Bool" + // If the LHS is boolean, we set the specialization to Compare_Int32. + // This matches other comparisons of the form bool === bool and + // generated code of Compare_Int32 is more efficient. + if (compare->compareType() == MCompare::Compare_Boolean && + def->getOperand(0)->type() == MIRType::Boolean) + { + compare->setCompareType(MCompare::Compare_Int32MaybeCoerceBoth); + } + + // Compare_Boolean specialization is done for "Anything === Bool" + // As of previous line Anything can't be Boolean + if (compare->compareType() == MCompare::Compare_Boolean) { + // Unbox rhs that is definitely Boolean + MDefinition* rhs = def->getOperand(1); + if (rhs->type() != MIRType::Boolean) { + MInstruction* unbox = MUnbox::New(alloc, rhs, MIRType::Boolean, MUnbox::Infallible); + def->block()->insertBefore(def, unbox); + def->replaceOperand(1, unbox); + if (!unbox->typePolicy()->adjustInputs(alloc, unbox)) + return false; + } + + MOZ_ASSERT(def->getOperand(0)->type() != MIRType::Boolean); + MOZ_ASSERT(def->getOperand(1)->type() == MIRType::Boolean); + return true; + } + + // Compare_StrictString specialization is done for "Anything === String" + // If the LHS is string, we set the specialization to Compare_String. + if (compare->compareType() == MCompare::Compare_StrictString && + def->getOperand(0)->type() == MIRType::String) + { + compare->setCompareType(MCompare::Compare_String); + } + + // Compare_StrictString specialization is done for "Anything === String" + // As of previous line Anything can't be String + if (compare->compareType() == MCompare::Compare_StrictString) { + // Unbox rhs that is definitely String + MDefinition* rhs = def->getOperand(1); + if (rhs->type() != MIRType::String) { + MInstruction* unbox = MUnbox::New(alloc, rhs, MIRType::String, MUnbox::Infallible); + def->block()->insertBefore(def, unbox); + def->replaceOperand(1, unbox); + if (!unbox->typePolicy()->adjustInputs(alloc, unbox)) + return false; + } + + MOZ_ASSERT(def->getOperand(0)->type() != MIRType::String); + MOZ_ASSERT(def->getOperand(1)->type() == MIRType::String); + return true; + } + + if (compare->compareType() == MCompare::Compare_Undefined || + compare->compareType() == MCompare::Compare_Null) + { + // Nothing to do for undefined and null, lowering handles all types. + return true; + } + + // Convert all inputs to the right input type + MIRType type = compare->inputType(); + MOZ_ASSERT(type == MIRType::Int32 || type == MIRType::Double || + type == MIRType::Object || type == MIRType::String || type == MIRType::Float32); + for (size_t i = 0; i < 2; i++) { + MDefinition* in = def->getOperand(i); + if (in->type() == type) + continue; + + MInstruction* replace; + + switch (type) { + case MIRType::Double: { + MToFPInstruction::ConversionKind convert = MToFPInstruction::NumbersOnly; + if (compare->compareType() == MCompare::Compare_DoubleMaybeCoerceLHS && i == 0) + convert = MToFPInstruction::NonNullNonStringPrimitives; + else if (compare->compareType() == MCompare::Compare_DoubleMaybeCoerceRHS && i == 1) + convert = MToFPInstruction::NonNullNonStringPrimitives; + replace = MToDouble::New(alloc, in, convert); + break; + } + case MIRType::Float32: { + MToFPInstruction::ConversionKind convert = MToFPInstruction::NumbersOnly; + if (compare->compareType() == MCompare::Compare_DoubleMaybeCoerceLHS && i == 0) + convert = MToFPInstruction::NonNullNonStringPrimitives; + else if (compare->compareType() == MCompare::Compare_DoubleMaybeCoerceRHS && i == 1) + convert = MToFPInstruction::NonNullNonStringPrimitives; + replace = MToFloat32::New(alloc, in, convert); + break; + } + case MIRType::Int32: { + MacroAssembler::IntConversionInputKind convert = MacroAssembler::IntConversion_NumbersOnly; + if (compare->compareType() == MCompare::Compare_Int32MaybeCoerceBoth || + (compare->compareType() == MCompare::Compare_Int32MaybeCoerceLHS && i == 0) || + (compare->compareType() == MCompare::Compare_Int32MaybeCoerceRHS && i == 1)) + { + convert = MacroAssembler::IntConversion_NumbersOrBoolsOnly; + } + replace = MToInt32::New(alloc, in, convert); + break; + } + case MIRType::Object: + replace = MUnbox::New(alloc, in, MIRType::Object, MUnbox::Infallible); + break; + case MIRType::String: + replace = MUnbox::New(alloc, in, MIRType::String, MUnbox::Infallible); + break; + default: + MOZ_CRASH("Unknown compare specialization"); + } + + def->block()->insertBefore(def, replace); + def->replaceOperand(i, replace); + + if (!replace->typePolicy()->adjustInputs(alloc, replace)) + return false; + } + + return true; +} + +bool +TypeBarrierPolicy::adjustInputs(TempAllocator& alloc, MInstruction* def) +{ + MTypeBarrier* ins = def->toTypeBarrier(); + MIRType inputType = ins->getOperand(0)->type(); + MIRType outputType = ins->type(); + + // Input and output type are already in accordance. + if (inputType == outputType) + return true; + + // Output is a value, currently box the input. + if (outputType == MIRType::Value) { + // XXX: Possible optimization: decrease resultTypeSet to only include + // the inputType. This will remove the need for boxing. + MOZ_ASSERT(inputType != MIRType::Value); + ins->replaceOperand(0, BoxAt(alloc, ins, ins->getOperand(0))); + return true; + } + + // Box input if needed. + if (inputType != MIRType::Value) { + MOZ_ASSERT(ins->alwaysBails()); + ins->replaceOperand(0, BoxAt(alloc, ins, ins->getOperand(0))); + } + + // We can't unbox a value to null/undefined/lazyargs. So keep output + // also a value. + // Note: Using setResultType shouldn't be done in TypePolicies, + // Here it is fine, since the type barrier has no uses. + if (IsNullOrUndefined(outputType) || outputType == MIRType::MagicOptimizedArguments) { + MOZ_ASSERT(!ins->hasDefUses()); + ins->setResultType(MIRType::Value); + return true; + } + + // Unbox / propagate the right type. + MUnbox::Mode mode = MUnbox::TypeBarrier; + MInstruction* replace = MUnbox::New(alloc, ins->getOperand(0), ins->type(), mode); + if (!ins->isMovable()) + replace->setNotMovable(); + + ins->block()->insertBefore(ins, replace); + ins->replaceOperand(0, replace); + if (!replace->typePolicy()->adjustInputs(alloc, replace)) + return false; + + // The TypeBarrier is equivalent to removing branches with unexpected + // types. The unexpected types would have changed Range Analysis + // predictions. As such, we need to prevent destructive optimizations. + ins->block()->flagOperandsOfPrunedBranches(replace); + + return true; +} + +bool +TestPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) +{ + MDefinition* op = ins->getOperand(0); + switch (op->type()) { + case MIRType::Value: + case MIRType::Null: + case MIRType::Undefined: + case MIRType::Boolean: + case MIRType::Int32: + case MIRType::Double: + case MIRType::Float32: + case MIRType::Symbol: + case MIRType::Object: + break; + + case MIRType::String: + { + MStringLength* length = MStringLength::New(alloc, op); + ins->block()->insertBefore(ins, length); + ins->replaceOperand(0, length); + break; + } + + default: + ins->replaceOperand(0, BoxAt(alloc, ins, op)); + break; + } + return true; +} + +bool +BitwisePolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) +{ + MIRType specialization = ins->typePolicySpecialization(); + if (specialization == MIRType::None) + return BoxInputsPolicy::staticAdjustInputs(alloc, ins); + + MOZ_ASSERT(ins->type() == specialization); + MOZ_ASSERT(specialization == MIRType::Int32 || specialization == MIRType::Double); + + // This policy works for both unary and binary bitwise operations. + for (size_t i = 0, e = ins->numOperands(); i < e; i++) { + MDefinition* in = ins->getOperand(i); + if (in->type() == MIRType::Int32) + continue; + + MInstruction* replace = MTruncateToInt32::New(alloc, in); + ins->block()->insertBefore(ins, replace); + ins->replaceOperand(i, replace); + + if (!replace->typePolicy()->adjustInputs(alloc, replace)) + return false; + } + + return true; +} + +bool +PowPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) +{ + MIRType specialization = ins->typePolicySpecialization(); + MOZ_ASSERT(specialization == MIRType::Int32 || specialization == MIRType::Double); + + // Input must be a double. + if (!DoublePolicy<0>::staticAdjustInputs(alloc, ins)) + return false; + + // Power may be an int32 or a double. Integers receive a faster path. + if (specialization == MIRType::Double) + return DoublePolicy<1>::staticAdjustInputs(alloc, ins); + return IntPolicy<1>::staticAdjustInputs(alloc, ins); +} + +template <unsigned Op> +bool +StringPolicy<Op>::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins) +{ + MDefinition* in = ins->getOperand(Op); + if (in->type() == MIRType::String) + return true; + + MUnbox* replace = MUnbox::New(alloc, in, MIRType::String, MUnbox::Fallible); + ins->block()->insertBefore(ins, replace); + ins->replaceOperand(Op, replace); + + return replace->typePolicy()->adjustInputs(alloc, replace); +} + +template bool StringPolicy<0>::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins); +template bool StringPolicy<1>::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins); +template bool StringPolicy<2>::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins); + +template <unsigned Op> +bool +ConvertToStringPolicy<Op>::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins) +{ + MDefinition* in = ins->getOperand(Op); + if (in->type() == MIRType::String) + return true; + + MToString* replace = MToString::New(alloc, in); + ins->block()->insertBefore(ins, replace); + ins->replaceOperand(Op, replace); + + if (!ToStringPolicy::staticAdjustInputs(alloc, replace)) + return false; + + return true; +} + +template bool ConvertToStringPolicy<0>::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins); +template bool ConvertToStringPolicy<1>::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins); +template bool ConvertToStringPolicy<2>::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins); + +template <unsigned Op> +bool +BooleanPolicy<Op>::staticAdjustInputs(TempAllocator& alloc, MInstruction* def) +{ + MDefinition* in = def->getOperand(Op); + if (in->type() == MIRType::Boolean) + return true; + + MUnbox* replace = MUnbox::New(alloc, in, MIRType::Boolean, MUnbox::Fallible); + def->block()->insertBefore(def, replace); + def->replaceOperand(Op, replace); + + return replace->typePolicy()->adjustInputs(alloc, replace); +} + +template bool BooleanPolicy<3>::staticAdjustInputs(TempAllocator& alloc, MInstruction* def); + +template <unsigned Op> +bool +IntPolicy<Op>::staticAdjustInputs(TempAllocator& alloc, MInstruction* def) +{ + MDefinition* in = def->getOperand(Op); + if (in->type() == MIRType::Int32) + return true; + + MUnbox* replace = MUnbox::New(alloc, in, MIRType::Int32, MUnbox::Fallible); + def->block()->insertBefore(def, replace); + def->replaceOperand(Op, replace); + + return replace->typePolicy()->adjustInputs(alloc, replace); +} + +template bool IntPolicy<0>::staticAdjustInputs(TempAllocator& alloc, MInstruction* def); +template bool IntPolicy<1>::staticAdjustInputs(TempAllocator& alloc, MInstruction* def); +template bool IntPolicy<2>::staticAdjustInputs(TempAllocator& alloc, MInstruction* def); +template bool IntPolicy<3>::staticAdjustInputs(TempAllocator& alloc, MInstruction* def); + +template <unsigned Op> +bool +ConvertToInt32Policy<Op>::staticAdjustInputs(TempAllocator& alloc, MInstruction* def) +{ + MDefinition* in = def->getOperand(Op); + if (in->type() == MIRType::Int32) + return true; + + MToInt32* replace = MToInt32::New(alloc, in); + def->block()->insertBefore(def, replace); + def->replaceOperand(Op, replace); + + return replace->typePolicy()->adjustInputs(alloc, replace); +} + +template bool ConvertToInt32Policy<0>::staticAdjustInputs(TempAllocator& alloc, MInstruction* def); + +template <unsigned Op> +bool +TruncateToInt32Policy<Op>::staticAdjustInputs(TempAllocator& alloc, MInstruction* def) +{ + MDefinition* in = def->getOperand(Op); + if (in->type() == MIRType::Int32) + return true; + + MTruncateToInt32* replace = MTruncateToInt32::New(alloc, in); + def->block()->insertBefore(def, replace); + def->replaceOperand(Op, replace); + + return replace->typePolicy()->adjustInputs(alloc, replace); +} + +template bool TruncateToInt32Policy<2>::staticAdjustInputs(TempAllocator& alloc, MInstruction* def); +template bool TruncateToInt32Policy<3>::staticAdjustInputs(TempAllocator& alloc, MInstruction* def); + +template <unsigned Op> +bool +DoublePolicy<Op>::staticAdjustInputs(TempAllocator& alloc, MInstruction* def) +{ + MDefinition* in = def->getOperand(Op); + if (in->type() == MIRType::Double || in->type() == MIRType::SinCosDouble) + return true; + + MToDouble* replace = MToDouble::New(alloc, in); + def->block()->insertBefore(def, replace); + def->replaceOperand(Op, replace); + + return replace->typePolicy()->adjustInputs(alloc, replace); +} + +template bool DoublePolicy<0>::staticAdjustInputs(TempAllocator& alloc, MInstruction* def); +template bool DoublePolicy<1>::staticAdjustInputs(TempAllocator& alloc, MInstruction* def); + +template <unsigned Op> +bool +Float32Policy<Op>::staticAdjustInputs(TempAllocator& alloc, MInstruction* def) +{ + MDefinition* in = def->getOperand(Op); + if (in->type() == MIRType::Float32) + return true; + + MToFloat32* replace = MToFloat32::New(alloc, in); + def->block()->insertBefore(def, replace); + def->replaceOperand(Op, replace); + + return replace->typePolicy()->adjustInputs(alloc, replace); +} + +template bool Float32Policy<0>::staticAdjustInputs(TempAllocator& alloc, MInstruction* def); +template bool Float32Policy<1>::staticAdjustInputs(TempAllocator& alloc, MInstruction* def); +template bool Float32Policy<2>::staticAdjustInputs(TempAllocator& alloc, MInstruction* def); + +template <unsigned Op> +bool +FloatingPointPolicy<Op>::adjustInputs(TempAllocator& alloc, MInstruction* def) +{ + MIRType policyType = def->typePolicySpecialization(); + if (policyType == MIRType::Double) + return DoublePolicy<Op>::staticAdjustInputs(alloc, def); + return Float32Policy<Op>::staticAdjustInputs(alloc, def); +} + +template bool FloatingPointPolicy<0>::adjustInputs(TempAllocator& alloc, MInstruction* def); + +template <unsigned Op> +bool +NoFloatPolicy<Op>::staticAdjustInputs(TempAllocator& alloc, MInstruction* def) +{ + EnsureOperandNotFloat32(alloc, def, Op); + return true; +} + +template bool NoFloatPolicy<0>::staticAdjustInputs(TempAllocator& alloc, MInstruction* def); +template bool NoFloatPolicy<1>::staticAdjustInputs(TempAllocator& alloc, MInstruction* def); +template bool NoFloatPolicy<2>::staticAdjustInputs(TempAllocator& alloc, MInstruction* def); +template bool NoFloatPolicy<3>::staticAdjustInputs(TempAllocator& alloc, MInstruction* def); + +template <unsigned FirstOp> +bool +NoFloatPolicyAfter<FirstOp>::adjustInputs(TempAllocator& alloc, MInstruction* def) +{ + for (size_t op = FirstOp, e = def->numOperands(); op < e; op++) + EnsureOperandNotFloat32(alloc, def, op); + return true; +} + +template bool NoFloatPolicyAfter<1>::adjustInputs(TempAllocator& alloc, MInstruction* def); +template bool NoFloatPolicyAfter<2>::adjustInputs(TempAllocator& alloc, MInstruction* def); + +template <unsigned Op> +bool +SimdScalarPolicy<Op>::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins) +{ + MOZ_ASSERT(IsSimdType(ins->type())); + MIRType laneType = SimdTypeToLaneType(ins->type()); + + MDefinition* in = ins->getOperand(Op); + + // A vector with boolean lanes requires Int32 inputs that have already been + // converted to 0/-1. + // We can't insert a MIRType::Boolean lane directly - it requires conversion. + if (laneType == MIRType::Boolean) { + MOZ_ASSERT(in->type() == MIRType::Int32, "Boolean SIMD vector requires Int32 lanes."); + return true; + } + + if (in->type() == laneType) + return true; + + MInstruction* replace; + if (laneType == MIRType::Int32) { + replace = MTruncateToInt32::New(alloc, in); + } else { + MOZ_ASSERT(laneType == MIRType::Float32); + replace = MToFloat32::New(alloc, in); + } + + ins->block()->insertBefore(ins, replace); + ins->replaceOperand(Op, replace); + + return replace->typePolicy()->adjustInputs(alloc, replace); +} + +template bool SimdScalarPolicy<0>::staticAdjustInputs(TempAllocator& alloc, MInstruction* def); +template bool SimdScalarPolicy<1>::staticAdjustInputs(TempAllocator& alloc, MInstruction* def); +template bool SimdScalarPolicy<2>::staticAdjustInputs(TempAllocator& alloc, MInstruction* def); +template bool SimdScalarPolicy<3>::staticAdjustInputs(TempAllocator& alloc, MInstruction* def); + +template <unsigned Op> +bool +BoxPolicy<Op>::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins) +{ + MDefinition* in = ins->getOperand(Op); + if (in->type() == MIRType::Value) + return true; + + ins->replaceOperand(Op, BoxAt(alloc, ins, in)); + return true; +} + +template bool BoxPolicy<0>::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins); +template bool BoxPolicy<1>::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins); +template bool BoxPolicy<2>::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins); + +template <unsigned Op, MIRType Type> +bool +BoxExceptPolicy<Op, Type>::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins) +{ + MDefinition* in = ins->getOperand(Op); + if (in->type() == Type) + return true; + return BoxPolicy<Op>::staticAdjustInputs(alloc, ins); +} + +template bool BoxExceptPolicy<0, MIRType::Object>::staticAdjustInputs(TempAllocator& alloc, + MInstruction* ins); + +template <unsigned Op> +bool +CacheIdPolicy<Op>::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins) +{ + MDefinition* in = ins->getOperand(Op); + switch (in->type()) { + case MIRType::Int32: + case MIRType::String: + case MIRType::Symbol: + return true; + default: + return BoxPolicy<Op>::staticAdjustInputs(alloc, ins); + } +} + +template bool CacheIdPolicy<1>::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins); + +bool +ToDoublePolicy::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins) +{ + MOZ_ASSERT(ins->isToDouble() || ins->isToFloat32()); + + MDefinition* in = ins->getOperand(0); + MToFPInstruction::ConversionKind conversion; + if (ins->isToDouble()) + conversion = ins->toToDouble()->conversion(); + else + conversion = ins->toToFloat32()->conversion(); + + switch (in->type()) { + case MIRType::Int32: + case MIRType::Float32: + case MIRType::Double: + case MIRType::Value: + // No need for boxing for these types. + return true; + case MIRType::Null: + // No need for boxing, when we will convert. + if (conversion == MToFPInstruction::NonStringPrimitives) + return true; + break; + case MIRType::Undefined: + case MIRType::Boolean: + // No need for boxing, when we will convert. + if (conversion == MToFPInstruction::NonStringPrimitives) + return true; + if (conversion == MToFPInstruction::NonNullNonStringPrimitives) + return true; + break; + case MIRType::Object: + case MIRType::String: + case MIRType::Symbol: + // Objects might be effectful. Symbols give TypeError. + break; + default: + break; + } + + in = BoxAt(alloc, ins, in); + ins->replaceOperand(0, in); + return true; +} + +bool +ToInt32Policy::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins) +{ + MOZ_ASSERT(ins->isToInt32() || ins->isTruncateToInt32()); + + MacroAssembler::IntConversionInputKind conversion = MacroAssembler::IntConversion_Any; + if (ins->isToInt32()) + conversion = ins->toToInt32()->conversion(); + + MDefinition* in = ins->getOperand(0); + switch (in->type()) { + case MIRType::Int32: + case MIRType::Float32: + case MIRType::Double: + case MIRType::Value: + // No need for boxing for these types. + return true; + case MIRType::Undefined: + // No need for boxing when truncating. + if (ins->isTruncateToInt32()) + return true; + break; + case MIRType::Null: + // No need for boxing, when we will convert. + if (conversion == MacroAssembler::IntConversion_Any) + return true; + break; + case MIRType::Boolean: + // No need for boxing, when we will convert. + if (conversion == MacroAssembler::IntConversion_Any) + return true; + if (conversion == MacroAssembler::IntConversion_NumbersOrBoolsOnly) + return true; + break; + case MIRType::Object: + case MIRType::String: + case MIRType::Symbol: + // Objects might be effectful. Symbols give TypeError. + break; + default: + break; + } + + in = BoxAt(alloc, ins, in); + ins->replaceOperand(0, in); + return true; +} + +bool +ToStringPolicy::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins) +{ + MOZ_ASSERT(ins->isToString()); + + MIRType type = ins->getOperand(0)->type(); + if (type == MIRType::Object || type == MIRType::Symbol) { + ins->replaceOperand(0, BoxAt(alloc, ins, ins->getOperand(0))); + return true; + } + + // TODO remove the following line once 966957 has landed + EnsureOperandNotFloat32(alloc, ins, 0); + + return true; +} + +template <unsigned Op> +bool +ObjectPolicy<Op>::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins) +{ + MDefinition* in = ins->getOperand(Op); + if (in->type() == MIRType::Object || in->type() == MIRType::Slots || + in->type() == MIRType::Elements) + { + return true; + } + + MUnbox* replace = MUnbox::New(alloc, in, MIRType::Object, MUnbox::Fallible); + ins->block()->insertBefore(ins, replace); + ins->replaceOperand(Op, replace); + + return replace->typePolicy()->adjustInputs(alloc, replace); +} + +template bool ObjectPolicy<0>::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins); +template bool ObjectPolicy<1>::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins); +template bool ObjectPolicy<2>::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins); +template bool ObjectPolicy<3>::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins); + +template <unsigned Op> +bool +SimdSameAsReturnedTypePolicy<Op>::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins) +{ + MOZ_ASSERT(ins->type() == ins->getOperand(Op)->type()); + return true; +} + +template bool +SimdSameAsReturnedTypePolicy<0>::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins); +template bool +SimdSameAsReturnedTypePolicy<1>::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins); + +bool +SimdAllPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) +{ + for (unsigned i = 0, e = ins->numOperands(); i < e; i++) + MOZ_ASSERT(ins->getOperand(i)->type() == ins->typePolicySpecialization()); + return true; +} + +template <unsigned Op> +bool +SimdPolicy<Op>::adjustInputs(TempAllocator& alloc, MInstruction* ins) +{ + MOZ_ASSERT(ins->typePolicySpecialization() == ins->getOperand(Op)->type()); + return true; +} + +template bool +SimdPolicy<0>::adjustInputs(TempAllocator& alloc, MInstruction* ins); + +bool +SimdShufflePolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) +{ + MSimdGeneralShuffle* s = ins->toSimdGeneralShuffle(); + + for (unsigned i = 0; i < s->numVectors(); i++) + MOZ_ASSERT(ins->getOperand(i)->type() == ins->typePolicySpecialization()); + + // Next inputs are the lanes, which need to be int32 + for (unsigned i = 0; i < s->numLanes(); i++) { + MDefinition* in = ins->getOperand(s->numVectors() + i); + if (in->type() == MIRType::Int32) + continue; + + MInstruction* replace = MToInt32::New(alloc, in, MacroAssembler::IntConversion_NumbersOnly); + ins->block()->insertBefore(ins, replace); + ins->replaceOperand(s->numVectors() + i, replace); + if (!replace->typePolicy()->adjustInputs(alloc, replace)) + return false; + } + + return true; +} + +bool +SimdSelectPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) +{ + // First input is the mask, which has to be a boolean. + MOZ_ASSERT(IsBooleanSimdType(ins->getOperand(0)->type())); + + // Next inputs are the two vectors of a particular type. + for (unsigned i = 1; i < 3; i++) + MOZ_ASSERT(ins->getOperand(i)->type() == ins->typePolicySpecialization()); + + return true; +} + +bool +CallPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) +{ + MCall* call = ins->toCall(); + + MDefinition* func = call->getFunction(); + if (func->type() != MIRType::Object) { + MInstruction* unbox = MUnbox::New(alloc, func, MIRType::Object, MUnbox::Fallible); + call->block()->insertBefore(call, unbox); + call->replaceFunction(unbox); + + if (!unbox->typePolicy()->adjustInputs(alloc, unbox)) + return false; + } + + for (uint32_t i = 0; i < call->numStackArgs(); i++) { + if (!alloc.ensureBallast()) + return false; + EnsureOperandNotFloat32(alloc, call, MCall::IndexOfStackArg(i)); + } + + return true; +} + +bool +CallSetElementPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) +{ + // The first operand should be an object. + if (!SingleObjectPolicy::staticAdjustInputs(alloc, ins)) + return false; + + // Box the index and value operands. + for (size_t i = 1, e = ins->numOperands(); i < e; i++) { + MDefinition* in = ins->getOperand(i); + if (in->type() == MIRType::Value) + continue; + ins->replaceOperand(i, BoxAt(alloc, ins, in)); + } + return true; +} + +bool +InstanceOfPolicy::adjustInputs(TempAllocator& alloc, MInstruction* def) +{ + // Box first operand if it isn't object + if (def->getOperand(0)->type() != MIRType::Object) + if (!BoxPolicy<0>::staticAdjustInputs(alloc, def)) + return false; + + return true; +} + +bool +StoreUnboxedScalarPolicy::adjustValueInput(TempAllocator& alloc, MInstruction* ins, + Scalar::Type writeType, MDefinition* value, + int valueOperand) +{ + // Storing a SIMD value requires a valueOperand that has already been + // SimdUnboxed. See IonBuilder::inlineSimdStore(() + if (Scalar::isSimdType(writeType)) { + MOZ_ASSERT(IsSimdType(value->type())); + return true; + } + + MDefinition* curValue = value; + // First, ensure the value is int32, boolean, double or Value. + // The conversion is based on TypedArrayObjectTemplate::setElementTail. + switch (value->type()) { + case MIRType::Int32: + case MIRType::Double: + case MIRType::Float32: + case MIRType::Boolean: + case MIRType::Value: + break; + case MIRType::Null: + value->setImplicitlyUsedUnchecked(); + value = MConstant::New(alloc, Int32Value(0)); + ins->block()->insertBefore(ins, value->toInstruction()); + break; + case MIRType::Undefined: + value->setImplicitlyUsedUnchecked(); + value = MConstant::New(alloc, DoubleNaNValue()); + ins->block()->insertBefore(ins, value->toInstruction()); + break; + case MIRType::Object: + case MIRType::String: + case MIRType::Symbol: + value = BoxAt(alloc, ins, value); + break; + default: + MOZ_CRASH("Unexpected type"); + } + + if (value != curValue) { + ins->replaceOperand(valueOperand, value); + curValue = value; + } + + MOZ_ASSERT(value->type() == MIRType::Int32 || + value->type() == MIRType::Boolean || + value->type() == MIRType::Double || + value->type() == MIRType::Float32 || + value->type() == MIRType::Value); + + switch (writeType) { + case Scalar::Int8: + case Scalar::Uint8: + case Scalar::Int16: + case Scalar::Uint16: + case Scalar::Int32: + case Scalar::Uint32: + if (value->type() != MIRType::Int32) { + value = MTruncateToInt32::New(alloc, value); + ins->block()->insertBefore(ins, value->toInstruction()); + } + break; + case Scalar::Uint8Clamped: + // IonBuilder should have inserted ClampToUint8. + MOZ_ASSERT(value->type() == MIRType::Int32); + break; + case Scalar::Float32: + if (value->type() != MIRType::Float32) { + value = MToFloat32::New(alloc, value); + ins->block()->insertBefore(ins, value->toInstruction()); + } + break; + case Scalar::Float64: + if (value->type() != MIRType::Double) { + value = MToDouble::New(alloc, value); + ins->block()->insertBefore(ins, value->toInstruction()); + } + break; + default: + MOZ_CRASH("Invalid array type"); + } + + if (value != curValue) + ins->replaceOperand(valueOperand, value); + + return true; +} + +bool +StoreUnboxedScalarPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) +{ + if (!SingleObjectPolicy::staticAdjustInputs(alloc, ins)) + return false; + + MStoreUnboxedScalar* store = ins->toStoreUnboxedScalar(); + MOZ_ASSERT(IsValidElementsType(store->elements(), store->offsetAdjustment())); + MOZ_ASSERT(store->index()->type() == MIRType::Int32); + + return adjustValueInput(alloc, store, store->writeType(), store->value(), 2); +} + +bool +StoreTypedArrayHolePolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) +{ + MStoreTypedArrayElementHole* store = ins->toStoreTypedArrayElementHole(); + MOZ_ASSERT(store->elements()->type() == MIRType::Elements); + MOZ_ASSERT(store->index()->type() == MIRType::Int32); + MOZ_ASSERT(store->length()->type() == MIRType::Int32); + + return StoreUnboxedScalarPolicy::adjustValueInput(alloc, ins, store->arrayType(), store->value(), 3); +} + +bool +StoreTypedArrayElementStaticPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) +{ + MStoreTypedArrayElementStatic* store = ins->toStoreTypedArrayElementStatic(); + + return ConvertToInt32Policy<0>::staticAdjustInputs(alloc, ins) && + StoreUnboxedScalarPolicy::adjustValueInput(alloc, ins, store->accessType(), store->value(), 1); +} + +bool +StoreUnboxedObjectOrNullPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) +{ + if (!ObjectPolicy<0>::staticAdjustInputs(alloc, ins)) + return false; + + if (!ObjectPolicy<3>::staticAdjustInputs(alloc, ins)) + return false; + + // Change the value input to a ToObjectOrNull instruction if it might be + // a non-null primitive. Insert a post barrier for the instruction's object + // and whatever its new value is, unless the value is definitely null. + MStoreUnboxedObjectOrNull* store = ins->toStoreUnboxedObjectOrNull(); + + MOZ_ASSERT(store->typedObj()->type() == MIRType::Object); + + MDefinition* value = store->value(); + if (value->type() == MIRType::Object || + value->type() == MIRType::Null || + value->type() == MIRType::ObjectOrNull) + { + if (value->type() != MIRType::Null) { + MInstruction* barrier = MPostWriteBarrier::New(alloc, store->typedObj(), value); + store->block()->insertBefore(store, barrier); + } + return true; + } + + MToObjectOrNull* replace = MToObjectOrNull::New(alloc, value); + store->block()->insertBefore(store, replace); + store->setValue(replace); + + if (!BoxPolicy<0>::staticAdjustInputs(alloc, replace)) + return false; + + MInstruction* barrier = MPostWriteBarrier::New(alloc, store->typedObj(), replace); + store->block()->insertBefore(store, barrier); + + return true; +} + +bool +ClampPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) +{ + MDefinition* in = ins->toClampToUint8()->input(); + + switch (in->type()) { + case MIRType::Int32: + case MIRType::Double: + case MIRType::Value: + break; + default: + ins->replaceOperand(0, BoxAt(alloc, ins, in)); + break; + } + + return true; +} + +bool +FilterTypeSetPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) +{ + MOZ_ASSERT(ins->numOperands() == 1); + MIRType inputType = ins->getOperand(0)->type(); + MIRType outputType = ins->type(); + + // Special case when output is a Float32, but input isn't. + if (outputType == MIRType::Float32 && inputType != MIRType::Float32) { + // Create a MToFloat32 to add between the MFilterTypeSet and + // its uses. + MInstruction* replace = MToFloat32::New(alloc, ins); + ins->justReplaceAllUsesWithExcept(replace); + ins->block()->insertAfter(ins, replace); + + // Reset the type to not MIRType::Float32 + // Note: setResultType shouldn't happen in TypePolicies, + // Here it is fine, since there is just one use we just + // added ourself. And the resulting type after MToFloat32 + // equals the original type. + ins->setResultType(ins->resultTypeSet()->getKnownMIRType()); + outputType = ins->type(); + + // Do the type analysis + if (!replace->typePolicy()->adjustInputs(alloc, replace)) + return false; + + // Fall through to let the MFilterTypeSet adjust its input based + // on its new type. + } + + // Input and output type are already in accordance. + if (inputType == outputType) + return true; + + // Output is a value, box the input. + if (outputType == MIRType::Value) { + MOZ_ASSERT(inputType != MIRType::Value); + ins->replaceOperand(0, BoxAt(alloc, ins, ins->getOperand(0))); + return true; + } + + // The outputType should be a subset of the inputType else we are in code + // that has never executed yet. Bail to see the new type (if that hasn't + // happened yet). + if (inputType != MIRType::Value) { + MBail* bail = MBail::New(alloc); + ins->block()->insertBefore(ins, bail); + bail->setDependency(ins->dependency()); + ins->setDependency(bail); + ins->replaceOperand(0, BoxAt(alloc, ins, ins->getOperand(0))); + } + + // We can't unbox a value to null/undefined/lazyargs. So keep output + // also a value. + // Note: Using setResultType shouldn't be done in TypePolicies, + // Here it is fine, since the type barrier has no uses. + if (IsNullOrUndefined(outputType) || outputType == MIRType::MagicOptimizedArguments) { + MOZ_ASSERT(!ins->hasDefUses()); + ins->setResultType(MIRType::Value); + return true; + } + + // Unbox / propagate the right type. + MUnbox::Mode mode = MUnbox::Infallible; + MInstruction* replace = MUnbox::New(alloc, ins->getOperand(0), ins->type(), mode); + + ins->block()->insertBefore(ins, replace); + ins->replaceOperand(0, replace); + if (!replace->typePolicy()->adjustInputs(alloc, replace)) + return false; + + // Carry over the dependency the MFilterTypeSet had. + replace->setDependency(ins->dependency()); + + return true; +} + +// Lists of all TypePolicy specializations which are used by MIR Instructions. +#define TYPE_POLICY_LIST(_) \ + _(ArithPolicy) \ + _(BitwisePolicy) \ + _(BoxInputsPolicy) \ + _(CallPolicy) \ + _(CallSetElementPolicy) \ + _(ClampPolicy) \ + _(ComparePolicy) \ + _(FilterTypeSetPolicy) \ + _(InstanceOfPolicy) \ + _(PowPolicy) \ + _(SimdAllPolicy) \ + _(SimdSelectPolicy) \ + _(SimdShufflePolicy) \ + _(StoreTypedArrayElementStaticPolicy) \ + _(StoreTypedArrayHolePolicy) \ + _(StoreUnboxedScalarPolicy) \ + _(StoreUnboxedObjectOrNullPolicy) \ + _(TestPolicy) \ + _(AllDoublePolicy) \ + _(ToDoublePolicy) \ + _(ToInt32Policy) \ + _(ToStringPolicy) \ + _(TypeBarrierPolicy) + +#define TEMPLATE_TYPE_POLICY_LIST(_) \ + _(BoxExceptPolicy<0, MIRType::Object>) \ + _(BoxPolicy<0>) \ + _(ConvertToInt32Policy<0>) \ + _(ConvertToStringPolicy<0>) \ + _(ConvertToStringPolicy<2>) \ + _(DoublePolicy<0>) \ + _(FloatingPointPolicy<0>) \ + _(IntPolicy<0>) \ + _(IntPolicy<1>) \ + _(Mix3Policy<ObjectPolicy<0>, StringPolicy<1>, BoxPolicy<2> >) \ + _(Mix3Policy<ObjectPolicy<0>, BoxPolicy<1>, BoxPolicy<2> >) \ + _(Mix3Policy<ObjectPolicy<0>, BoxPolicy<1>, ObjectPolicy<2> >) \ + _(Mix3Policy<ObjectPolicy<0>, IntPolicy<1>, BoxPolicy<2> >) \ + _(Mix3Policy<ObjectPolicy<0>, IntPolicy<1>, IntPolicy<2> >) \ + _(Mix3Policy<ObjectPolicy<0>, IntPolicy<1>, TruncateToInt32Policy<2> >) \ + _(Mix3Policy<ObjectPolicy<0>, ObjectPolicy<1>, BoxPolicy<2> >) \ + _(Mix3Policy<ObjectPolicy<0>, ObjectPolicy<1>, IntPolicy<2> >) \ + _(Mix3Policy<ObjectPolicy<0>, ObjectPolicy<1>, ObjectPolicy<2> >) \ + _(Mix3Policy<StringPolicy<0>, IntPolicy<1>, IntPolicy<2>>) \ + _(Mix3Policy<StringPolicy<0>, ObjectPolicy<1>, StringPolicy<2> >) \ + _(Mix3Policy<StringPolicy<0>, StringPolicy<1>, StringPolicy<2> >) \ + _(Mix3Policy<ObjectPolicy<0>, StringPolicy<1>, IntPolicy<2>>) \ + _(Mix4Policy<ObjectPolicy<0>, IntPolicy<1>, IntPolicy<2>, IntPolicy<3>>) \ + _(Mix4Policy<ObjectPolicy<0>, IntPolicy<1>, TruncateToInt32Policy<2>, TruncateToInt32Policy<3> >) \ + _(Mix3Policy<ObjectPolicy<0>, CacheIdPolicy<1>, NoFloatPolicy<2>>) \ + _(Mix4Policy<SimdScalarPolicy<0>, SimdScalarPolicy<1>, SimdScalarPolicy<2>, SimdScalarPolicy<3> >) \ + _(MixPolicy<BoxPolicy<0>, ObjectPolicy<1> >) \ + _(MixPolicy<ConvertToStringPolicy<0>, ConvertToStringPolicy<1> >) \ + _(MixPolicy<ConvertToStringPolicy<0>, ObjectPolicy<1> >) \ + _(MixPolicy<DoublePolicy<0>, DoublePolicy<1> >) \ + _(MixPolicy<IntPolicy<0>, IntPolicy<1> >) \ + _(MixPolicy<ObjectPolicy<0>, BoxPolicy<1> >) \ + _(MixPolicy<ObjectPolicy<0>, CacheIdPolicy<1>>) \ + _(MixPolicy<ObjectPolicy<0>, ConvertToStringPolicy<1> >) \ + _(MixPolicy<ObjectPolicy<0>, IntPolicy<1> >) \ + _(MixPolicy<ObjectPolicy<0>, IntPolicy<2> >) \ + _(MixPolicy<ObjectPolicy<0>, NoFloatPolicy<1> >) \ + _(MixPolicy<ObjectPolicy<0>, NoFloatPolicy<2> >) \ + _(MixPolicy<ObjectPolicy<0>, NoFloatPolicy<3> >) \ + _(MixPolicy<ObjectPolicy<0>, ObjectPolicy<1> >) \ + _(MixPolicy<ObjectPolicy<0>, StringPolicy<1> >) \ + _(MixPolicy<ObjectPolicy<0>, ConvertToStringPolicy<2> >) \ + _(MixPolicy<ObjectPolicy<1>, ConvertToStringPolicy<0> >) \ + _(MixPolicy<SimdSameAsReturnedTypePolicy<0>, SimdSameAsReturnedTypePolicy<1> >) \ + _(MixPolicy<SimdSameAsReturnedTypePolicy<0>, SimdScalarPolicy<1> >) \ + _(MixPolicy<StringPolicy<0>, IntPolicy<1> >) \ + _(MixPolicy<StringPolicy<0>, StringPolicy<1> >) \ + _(MixPolicy<BoxPolicy<0>, BoxPolicy<1> >) \ + _(NoFloatPolicy<0>) \ + _(NoFloatPolicyAfter<1>) \ + _(NoFloatPolicyAfter<2>) \ + _(ObjectPolicy<0>) \ + _(ObjectPolicy<1>) \ + _(ObjectPolicy<3>) \ + _(SimdPolicy<0>) \ + _(SimdSameAsReturnedTypePolicy<0>) \ + _(SimdScalarPolicy<0>) \ + _(StringPolicy<0>) + + +namespace js { +namespace jit { + +// Define for all used TypePolicy specialization, the definition for +// |TypePolicy::Data::thisTypePolicy|. This function returns one constant +// instance of the TypePolicy which is shared among all MIR Instructions of the +// same type. +// +// This Macro use __VA_ARGS__ to account for commas of template parameters. +#define DEFINE_TYPE_POLICY_SINGLETON_INSTANCES_(...) \ + TypePolicy * \ + __VA_ARGS__::Data::thisTypePolicy() \ + { \ + static __VA_ARGS__ singletonType; \ + return &singletonType; \ + } + + TYPE_POLICY_LIST(DEFINE_TYPE_POLICY_SINGLETON_INSTANCES_) + TEMPLATE_TYPE_POLICY_LIST(template<> DEFINE_TYPE_POLICY_SINGLETON_INSTANCES_) +#undef DEFINE_TYPE_POLICY_SINGLETON_INSTANCES_ + +} // namespace jit +} // namespace js + +namespace { + +// For extra-good measure in case an unqualified use is ever introduced. (The +// main use in the macro below is explicitly qualified so as not to consult +// this scope and find this function.) +inline TypePolicy* +thisTypePolicy() = delete; + +static MIRType +thisTypeSpecialization() +{ + MOZ_CRASH("TypeSpecialization lacks definition of thisTypeSpecialization."); +} + +} // namespace + +// For each MIR Instruction, this macro define the |typePolicy| method which is +// using the |thisTypePolicy| method. The |thisTypePolicy| method is either a +// member of the MIR Instruction, such as with MGetElementCache, a member +// inherited from the TypePolicy::Data structure, or a member inherited from +// NoTypePolicy if the MIR instruction has no type policy. +#define DEFINE_MIR_TYPEPOLICY_MEMBERS_(op) \ + TypePolicy * \ + js::jit::M##op::typePolicy() \ + { \ + return M##op::thisTypePolicy(); \ + } \ + \ + MIRType \ + js::jit::M##op::typePolicySpecialization() \ + { \ + return thisTypeSpecialization(); \ + } + + MIR_OPCODE_LIST(DEFINE_MIR_TYPEPOLICY_MEMBERS_) +#undef DEFINE_MIR_TYPEPOLICY_MEMBERS_ |