mirror of
https://github.com/classilla/tenfourfox.git
synced 2024-06-27 02:29:35 +00:00
1317 lines
47 KiB
C++
1317 lines
47 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/. */
|
|
|
|
#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;
|
|
|
|
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
|
|
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);
|
|
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_String>::staticAdjustInputs(TempAllocator& alloc,
|
|
MInstruction* ins);
|
|
template bool BoxExceptPolicy<1, MIRType_String>::staticAdjustInputs(TempAllocator& alloc,
|
|
MInstruction* ins);
|
|
template bool BoxExceptPolicy<2, MIRType_String>::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);
|
|
|
|
static bool
|
|
MaybeSimdUnbox(TempAllocator& alloc, MInstruction* ins, MIRType type, unsigned op)
|
|
{
|
|
MOZ_ASSERT(IsSimdType(type));
|
|
MDefinition* in = ins->getOperand(op);
|
|
if (in->type() == type)
|
|
return true;
|
|
|
|
MSimdUnbox* replace = MSimdUnbox::New(alloc, in, type);
|
|
ins->block()->insertBefore(ins, replace);
|
|
ins->replaceOperand(op, replace);
|
|
|
|
return replace->typePolicy()->adjustInputs(alloc, replace);
|
|
}
|
|
|
|
template <unsigned Op>
|
|
bool
|
|
SimdSameAsReturnedTypePolicy<Op>::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins)
|
|
{
|
|
return MaybeSimdUnbox(alloc, ins, ins->type(), Op);
|
|
}
|
|
|
|
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)
|
|
{
|
|
MIRType specialization = ins->typePolicySpecialization();
|
|
for (unsigned i = 0, e = ins->numOperands(); i < e; i++) {
|
|
if (!MaybeSimdUnbox(alloc, ins, specialization, i))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
template <unsigned Op>
|
|
bool
|
|
SimdPolicy<Op>::adjustInputs(TempAllocator& alloc, MInstruction* ins)
|
|
{
|
|
return MaybeSimdUnbox(alloc, ins, ins->typePolicySpecialization(), Op);
|
|
}
|
|
|
|
template bool
|
|
SimdPolicy<0>::adjustInputs(TempAllocator& alloc, MInstruction* ins);
|
|
|
|
bool
|
|
SimdShufflePolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins)
|
|
{
|
|
MIRType specialization = ins->typePolicySpecialization();
|
|
|
|
MSimdGeneralShuffle* s = ins->toSimdGeneralShuffle();
|
|
|
|
for (unsigned i = 0; i < s->numVectors(); i++) {
|
|
if (!MaybeSimdUnbox(alloc, ins, specialization, i))
|
|
return false;
|
|
}
|
|
|
|
// 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)
|
|
{
|
|
MIRType specialization = ins->typePolicySpecialization();
|
|
|
|
// First input is the mask, which has to be an int32x4 (for now).
|
|
if (!MaybeSimdUnbox(alloc, ins, MIRType_Int32x4, 0))
|
|
return false;
|
|
|
|
// Next inputs are the two vectors of a particular type.
|
|
for (unsigned i = 1; i < 3; i++) {
|
|
if (!MaybeSimdUnbox(alloc, ins, specialization, i))
|
|
return false;
|
|
}
|
|
|
|
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++)
|
|
EnsureOperandNotFloat32(alloc, call, MCall::IndexOfStackArg(i));
|
|
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
CallSetElementPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins)
|
|
{
|
|
// The first operand should be an object.
|
|
SingleObjectPolicy::staticAdjustInputs(alloc, ins);
|
|
|
|
// 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)
|
|
BoxPolicy<0>::staticAdjustInputs(alloc, def);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
StoreUnboxedScalarPolicy::adjustValueInput(TempAllocator& alloc, MInstruction* ins,
|
|
Scalar::Type writeType, MDefinition* value,
|
|
int valueOperand)
|
|
{
|
|
// Storing a SIMD value just implies that we might need a SimdUnbox.
|
|
if (Scalar::isSimdType(writeType))
|
|
return MaybeSimdUnbox(alloc, ins, ScalarTypeToMIRType(writeType), valueOperand);
|
|
|
|
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)
|
|
{
|
|
SingleObjectPolicy::staticAdjustInputs(alloc, ins);
|
|
|
|
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)
|
|
{
|
|
ObjectPolicy<0>::staticAdjustInputs(alloc, ins);
|
|
ObjectPolicy<3>::staticAdjustInputs(alloc, ins);
|
|
|
|
// 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_String>) \
|
|
_(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> >) \
|
|
_(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<ObjectPolicy<0>, BoxPolicy<1> >) \
|
|
_(MixPolicy<ObjectPolicy<0>, CacheIdPolicy<1>>) \
|
|
_(MixPolicy<ObjectPolicy<0>, ConvertToStringPolicy<1> >) \
|
|
_(MixPolicy<ObjectPolicy<0>, IntPolicy<1> >) \
|
|
_(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_
|