Bug 1054512: IonMonkey: Run the type policy of added instructions during type analysis, r=jandem
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug1054512.js
@@ -0,0 +1,11 @@
+function f(x) {
+ x((x | 0) + x);
+};
+try {
+ f(1);
+} catch (e) {}
+for (var k = 0; k < 1; ++k) {
+ try {
+ f(Symbol());
+ } catch (e) {}
+}
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -3107,17 +3107,21 @@ class MUnbox : public MUnaryInstruction,
private:
Mode mode_;
BailoutKind bailoutKind_;
MUnbox(MDefinition *ins, MIRType type, Mode mode, BailoutKind kind)
: MUnaryInstruction(ins),
mode_(mode)
{
- JS_ASSERT(ins->type() == MIRType_Value);
+ // Only allow unboxing a non MIRType_Value when input and output types
+ // don't match. This is often used to force a bailout. Boxing happens
+ // during type analysis.
+ JS_ASSERT_IF(ins->type() != MIRType_Value, type != ins->type());
+
JS_ASSERT(type == MIRType_Boolean ||
type == MIRType_Int32 ||
type == MIRType_Double ||
type == MIRType_String ||
type == MIRType_Symbol ||
type == MIRType_Object);
setResultType(type);
@@ -3834,28 +3838,29 @@ class MToInt32
bool isConsistentFloat32Use(MUse *use) const { return true; }
#endif
ALLOW_CLONE(MToInt32)
};
// Converts a value or typed input to a truncated int32, for use with bitwise
// operations. This is an infallible ValueToECMAInt32.
-class MTruncateToInt32 : public MUnaryInstruction
+class MTruncateToInt32
+ : public MUnaryInstruction,
+ public ToInt32Policy
{
explicit MTruncateToInt32(MDefinition *def)
: MUnaryInstruction(def)
{
setResultType(MIRType_Int32);
setMovable();
// An object might have "valueOf", which means it is effectful.
// ToInt32(symbol) throws.
MOZ_ASSERT(def->type() != MIRType_Object);
- MOZ_ASSERT(def->type() != MIRType_Symbol);
if (def->mightBeType(MIRType_Object) || def->mightBeType(MIRType_Symbol))
setGuard();
}
public:
INSTRUCTION_HEADER(TruncateToInt32)
static MTruncateToInt32 *New(TempAllocator &alloc, MDefinition *def) {
return new(alloc) MTruncateToInt32(def);
@@ -3876,16 +3881,20 @@ class MTruncateToInt32 : public MUnaryIn
void computeRange(TempAllocator &alloc);
TruncateKind operandTruncateKind(size_t index) const;
# ifdef DEBUG
bool isConsistentFloat32Use(MUse *use) const {
return true;
}
#endif
+ TypePolicy *typePolicy() {
+ return this;
+ }
+
ALLOW_CLONE(MTruncateToInt32)
};
// Converts any type to a string
class MToString :
public MUnaryInstruction,
public ToStringPolicy
{
@@ -6095,16 +6104,17 @@ class MStringReplace
static MStringReplace *New(TempAllocator &alloc, MDefinition *string, MDefinition *pattern, MDefinition *replacement) {
return new(alloc) MStringReplace(string, pattern, replacement);
}
bool congruentTo(const MDefinition *ins) const {
return congruentIfOperandsEqual(ins);
}
+
AliasSet getAliasSet() const {
return AliasSet::None();
}
};
struct LambdaFunctionInfo
{
// The functions used in lambdas are the canonical original function in
--- a/js/src/jit/TypePolicy.cpp
+++ b/js/src/jit/TypePolicy.cpp
@@ -71,34 +71,28 @@ ArithPolicy::adjustInputs(TempAllocator
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 the input is a string or object, the conversion is not
- // possible--at least, we can't specialize. So box the input.
- if (in->type() == MIRType_Object ||
- in->type() == MIRType_String ||
- (in->type() == MIRType_Undefined && specialization_ == MIRType_Int32))
- {
- in = boxAt(alloc, ins, in);
- }
-
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
ComparePolicy::adjustInputs(TempAllocator &alloc, MInstruction *def)
{
@@ -189,23 +183,16 @@ ComparePolicy::adjustInputs(TempAllocato
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;
- // See ArithPolicy::adjustInputs for an explanation of the following.
- if (in->type() == MIRType_Object || in->type() == MIRType_String ||
- in->type() == MIRType_Undefined)
- {
- in = boxAt(alloc, def, in);
- }
-
switch (type) {
case MIRType_Double: {
MToDouble::ConversionKind convert = MToDouble::NumbersOnly;
if (compare->compareType() == MCompare::Compare_DoubleMaybeCoerceLHS && i == 0)
convert = MToDouble::NonNullNonStringPrimitives;
else if (compare->compareType() == MCompare::Compare_DoubleMaybeCoerceRHS && i == 1)
convert = MToDouble::NonNullNonStringPrimitives;
if (in->type() == MIRType_Null ||
@@ -260,16 +247,19 @@ ComparePolicy::adjustInputs(TempAllocato
replace = MUnbox::New(alloc, in, MIRType_String, MUnbox::Infallible);
break;
default:
MOZ_ASSUME_UNREACHABLE("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)
{
@@ -357,27 +347,22 @@ BitwisePolicy::adjustInputs(TempAllocato
JS_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;
- // See ArithPolicy::adjustInputs for an explanation of the following.
- // MTruncateToInt32 in particular does not support MIRType_Symbol input.
- if (in->type() == MIRType_Object || in->type() == MIRType_String ||
- in->type() == MIRType_Symbol)
- {
- in = boxAt(alloc, ins, in);
- }
-
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)
{
@@ -462,87 +447,53 @@ ConvertToInt32Policy<Op>::staticAdjustIn
{
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 true;
+
+ return replace->typePolicy()->adjustInputs(alloc, replace);
}
template bool ConvertToInt32Policy<0>::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)
return true;
- // Force a bailout. Objects may be effectful; strings and symbols are
- // currently unhandled.
- if (in->type() == MIRType_Object ||
- in->type() == MIRType_String ||
- in->type() == MIRType_Symbol)
- {
- MBox *box = MBox::New(alloc, in);
- def->block()->insertBefore(def, box);
-
- MUnbox *unbox = MUnbox::New(alloc, box, MIRType_Double, MUnbox::Fallible);
- def->block()->insertBefore(def, unbox);
- def->replaceOperand(Op, unbox);
- return true;
- }
-
MToDouble *replace = MToDouble::New(alloc, in);
def->block()->insertBefore(def, replace);
def->replaceOperand(Op, replace);
- return true;
+
+ 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;
- // Force a bailout. Objects may be effectful; strings and symbols are
- // currently unhandled.
- if (in->type() == MIRType_Object ||
- in->type() == MIRType_String ||
- in->type() == MIRType_Symbol)
- {
- MToDouble *toDouble = MToDouble::New(alloc, in);
- def->block()->insertBefore(def, toDouble);
-
- MBox *box = MBox::New(alloc, toDouble);
- def->block()->insertBefore(def, box);
-
- MUnbox *unbox = MUnbox::New(alloc, box, MIRType_Double, MUnbox::Fallible);
- def->block()->insertBefore(def, unbox);
-
- MToFloat32 *toFloat32 = MToFloat32::New(alloc, unbox);
- def->block()->insertBefore(def, toFloat32);
-
- def->replaceOperand(Op, unbox);
- return true;
- }
-
MToFloat32 *replace = MToFloat32::New(alloc, in);
def->block()->insertBefore(def, replace);
def->replaceOperand(Op, replace);
- return true;
+
+ 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
@@ -604,28 +555,34 @@ ToDoublePolicy::staticAdjustInputs(TempA
in = boxAt(alloc, ins, in);
ins->replaceOperand(0, in);
return true;
}
bool
ToInt32Policy::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins)
{
- JS_ASSERT(ins->isToInt32());
+ JS_ASSERT(ins->isToInt32() || ins->isTruncateToInt32());
MDefinition *in = ins->getOperand(0);
switch (in->type()) {
case MIRType_Object:
case MIRType_String:
case MIRType_Symbol:
- case MIRType_Undefined:
- // Objects might be effectful. Undefined and symbols coerce to NaN, not int32.
+ // Objects might be effectful. Symbols give TypeError.
in = boxAt(alloc, ins, in);
ins->replaceOperand(0, in);
break;
+ case MIRType_Undefined:
+ // Undefined coerce to NaN, not int32, when not truncated.
+ if (ins->isToInt32()) {
+ in = boxAt(alloc, ins, in);
+ ins->replaceOperand(0, in);
+ }
+ break;
default:
break;
}
return true;
}
bool
@@ -651,45 +608,41 @@ ObjectPolicy<Op>::staticAdjustInputs(Tem
{
MDefinition *in = ins->getOperand(Op);
if (in->type() == MIRType_Object || in->type() == MIRType_Slots ||
in->type() == MIRType_Elements)
{
return true;
}
- if (in->type() != MIRType_Value)
- in = boxAt(alloc, ins, in);
-
MUnbox *replace = MUnbox::New(alloc, in, MIRType_Object, MUnbox::Fallible);
ins->block()->insertBefore(ins, replace);
ins->replaceOperand(Op, replace);
- return true;
+
+ 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);
bool
CallPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins)
{
MCall *call = ins->toCall();
MDefinition *func = call->getFunction();
if (func->type() != MIRType_Object) {
- // If the function is impossible to call,
- // bail out by causing a subsequent unbox to fail.
- if (func->type() != MIRType_Value)
- func = boxAt(alloc, call, func);
-
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;
}
--- a/js/src/jit/arm/Lowering-arm.cpp
+++ b/js/src/jit/arm/Lowering-arm.cpp
@@ -121,16 +121,17 @@ LIRGeneratorARM::visitBox(MBox *box)
bool
LIRGeneratorARM::visitUnbox(MUnbox *unbox)
{
// An unbox on arm reads in a type tag (either in memory or a register) and
// a payload. Unlike most instructions conusming a box, we ask for the type
// second, so that the result can re-use the first input.
MDefinition *inner = unbox->getOperand(0);
+ JS_ASSERT(inner->type() == MIRType_Value);
if (!ensureDefined(inner))
return false;
if (IsFloatingPointType(unbox->type())) {
LUnboxFloatingPoint *lir = new(alloc()) LUnboxFloatingPoint(unbox->type());
if (unbox->fallible() && !assignSnapshot(lir, unbox->bailoutKind()))
return false;
--- a/js/src/jit/mips/Lowering-mips.cpp
+++ b/js/src/jit/mips/Lowering-mips.cpp
@@ -123,16 +123,17 @@ LIRGeneratorMIPS::visitBox(MBox *box)
bool
LIRGeneratorMIPS::visitUnbox(MUnbox *unbox)
{
// An unbox on mips reads in a type tag (either in memory or a register) and
// a payload. Unlike most instructions consuming a box, we ask for the type
// second, so that the result can re-use the first input.
MDefinition *inner = unbox->getOperand(0);
+ JS_ASSERT(inner->type() == MIRType_Value);
if (!ensureDefined(inner))
return false;
if (IsFloatingPointType(unbox->type())) {
LUnboxFloatingPoint *lir = new(alloc()) LUnboxFloatingPoint(unbox->type());
if (unbox->fallible() && !assignSnapshot(lir, unbox->bailoutKind()))
return false;
--- a/js/src/jit/x64/Lowering-x64.cpp
+++ b/js/src/jit/x64/Lowering-x64.cpp
@@ -70,16 +70,18 @@ LIRGeneratorX64::visitBox(MBox *box)
LBox *ins = new(alloc()) LBox(opd->type(), useRegister(opd));
return define(ins, box, LDefinition(LDefinition::BOX));
}
bool
LIRGeneratorX64::visitUnbox(MUnbox *unbox)
{
MDefinition *box = unbox->getOperand(0);
+ JS_ASSERT(box->type() == MIRType_Value);
+
LUnboxBase *lir;
if (IsFloatingPointType(unbox->type()))
lir = new(alloc()) LUnboxFloatingPoint(useRegisterAtStart(box), unbox->type());
else
lir = new(alloc()) LUnbox(useRegisterAtStart(box));
if (unbox->fallible() && !assignSnapshot(lir, unbox->bailoutKind()))
return false;
--- a/js/src/jit/x86/Lowering-x86.cpp
+++ b/js/src/jit/x86/Lowering-x86.cpp
@@ -114,16 +114,17 @@ LIRGeneratorX86::visitBox(MBox *box)
bool
LIRGeneratorX86::visitUnbox(MUnbox *unbox)
{
// An unbox on x86 reads in a type tag (either in memory or a register) and
// a payload. Unlike most instructions conusming a box, we ask for the type
// second, so that the result can re-use the first input.
MDefinition *inner = unbox->getOperand(0);
+ JS_ASSERT(inner->type() == MIRType_Value);
if (!ensureDefined(inner))
return false;
if (IsFloatingPointType(unbox->type())) {
LUnboxFloatingPoint *lir = new(alloc()) LUnboxFloatingPoint(unbox->type());
if (unbox->fallible() && !assignSnapshot(lir, unbox->bailoutKind()))
return false;