From c8ce17bf8e19809be4457d75fe2a5c3224c1d360 Mon Sep 17 00:00:00 2001 From: Hannes Verschore Date: Mon, 22 Dec 2014 13:16:48 +0100 Subject: [PATCH] Bug 1107328 - IonMonkey: Also check for boxed constants when checking for constants, r=jandem --- js/src/jit/EffectiveAddressAnalysis.cpp | 12 +- js/src/jit/IonAnalysis.cpp | 14 +- js/src/jit/IonBuilder.cpp | 29 ++-- js/src/jit/Lowering.cpp | 12 +- js/src/jit/MCallOptimize.cpp | 34 ++--- js/src/jit/MIR.cpp | 167 +++++++++++++++--------- js/src/jit/MIR.h | 7 + js/src/jit/RangeAnalysis.cpp | 38 +++--- js/src/jit/ScalarReplacement.cpp | 6 +- js/src/jit/arm/Lowering-arm.cpp | 12 +- js/src/jit/mips/Lowering-mips.cpp | 12 +- 11 files changed, 194 insertions(+), 149 deletions(-) diff --git a/js/src/jit/EffectiveAddressAnalysis.cpp b/js/src/jit/EffectiveAddressAnalysis.cpp index 34559a3620b..04552edcea9 100644 --- a/js/src/jit/EffectiveAddressAnalysis.cpp +++ b/js/src/jit/EffectiveAddressAnalysis.cpp @@ -21,10 +21,10 @@ AnalyzeLsh(TempAllocator &alloc, MLsh *lsh) MOZ_ASSERT(index->type() == MIRType_Int32); MDefinition *shift = lsh->rhs(); - if (!shift->isConstant()) + if (!shift->isConstantValue()) return; - Value shiftValue = shift->toConstant()->value(); + Value shiftValue = shift->constantValue(); if (!shiftValue.isInt32() || !IsShiftInScaleRange(shiftValue.toInt32())) return; @@ -47,8 +47,8 @@ AnalyzeLsh(TempAllocator &alloc, MLsh *lsh) MDefinition *other = add->getOperand(1 - add->indexOf(*use)); - if (other->isConstant()) { - displacement += other->toConstant()->value().toInt32(); + if (other->isConstantValue()) { + displacement += other->constantValue().toInt32(); } else { if (base) break; @@ -72,11 +72,11 @@ AnalyzeLsh(TempAllocator &alloc, MLsh *lsh) MBitAnd *bitAnd = use->consumer()->toDefinition()->toBitAnd(); MDefinition *other = bitAnd->getOperand(1 - bitAnd->indexOf(*use)); - if (!other->isConstant() || !other->toConstant()->value().isInt32()) + if (!other->isConstantValue() || !other->constantValue().isInt32()) return; uint32_t bitsClearedByShift = elemSize - 1; - uint32_t bitsClearedByMask = ~uint32_t(other->toConstant()->value().toInt32()); + uint32_t bitsClearedByMask = ~uint32_t(other->constantValue().toInt32()); if ((bitsClearedByShift & bitsClearedByMask) != bitsClearedByMask) return; diff --git a/js/src/jit/IonAnalysis.cpp b/js/src/jit/IonAnalysis.cpp index a19b39d5d84..3a8caf55275 100644 --- a/js/src/jit/IonAnalysis.cpp +++ b/js/src/jit/IonAnalysis.cpp @@ -260,7 +260,7 @@ MaybeFoldConditionBlock(MIRGraph &graph, MBasicBlock *initialBlock) MBasicBlock *trueTarget = trueBranch; if (BlockComputesConstant(trueBranch, trueResult)) { - trueTarget = trueResult->toConstant()->valueToBoolean() + trueTarget = trueResult->constantToBoolean() ? finalTest->ifTrue() : finalTest->ifFalse(); testBlock->removePredecessor(trueBranch); @@ -272,7 +272,7 @@ MaybeFoldConditionBlock(MIRGraph &graph, MBasicBlock *initialBlock) MBasicBlock *falseTarget = falseBranch; if (BlockComputesConstant(falseBranch, falseResult)) { - falseTarget = falseResult->toConstant()->valueToBoolean() + falseTarget = falseResult->constantToBoolean() ? finalTest->ifTrue() : finalTest->ifFalse(); testBlock->removePredecessor(falseBranch); @@ -2270,8 +2270,8 @@ jit::ExtractLinearSum(MDefinition *ins) if (ins->type() != MIRType_Int32) return SimpleLinearSum(ins, 0); - if (ins->isConstant()) { - const Value &v = ins->toConstant()->value(); + if (ins->isConstantValue()) { + const Value &v = ins->constantValue(); MOZ_ASSERT(v.isInt32()); return SimpleLinearSum(nullptr, v.toInt32()); } else if (ins->isAdd() || ins->isSub()) { @@ -2672,8 +2672,8 @@ LinearSum::add(MDefinition *term, int32_t scale) if (scale == 0) return true; - if (term->isConstant()) { - int32_t constant = term->toConstant()->value().toInt32(); + if (term->isConstantValue()) { + int32_t constant = term->constantValue().toInt32(); if (!SafeMul(constant, scale, &constant)) return false; return add(constant); @@ -2751,7 +2751,7 @@ jit::ConvertLinearSum(TempAllocator &alloc, MBasicBlock *block, const LinearSum for (size_t i = 0; i < sum.numTerms(); i++) { LinearTerm term = sum.term(i); - MOZ_ASSERT(!term.term->isConstant()); + MOZ_ASSERT(!term.term->isConstantValue()); if (term.scale == 1) { if (def) { def = MAdd::New(alloc, def, term.term); diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index af82e4fec42..7be54d2071f 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -2261,9 +2261,8 @@ IonBuilder::processDoWhileCondEnd(CFGState &state) return ControlStatus_Error; // Test for do {} while(false) and don't create a loop in that case. - if (vins->isConstant()) { - MConstant *cte = vins->toConstant(); - if (cte->value().isBoolean() && !cte->value().toBoolean()) { + if (vins->isConstantValue() && !vins->constantValue().isMagic()) { + if (!vins->constantToBoolean()) { current->end(MGoto::New(alloc(), successor)); current = nullptr; @@ -4568,7 +4567,7 @@ IonBuilder::makeInliningDecision(JSObject *targetArg, CallInfo &callInfo) bool hasOpportunities = false; for (size_t i = 0, e = callInfo.argv().length(); !hasOpportunities && i < e; i++) { MDefinition *arg = callInfo.argv()[i]; - hasOpportunities = arg->isLambda() || arg->isConstant(); + hasOpportunities = arg->isLambda() || arg->isConstantValue(); } if (!hasOpportunities) @@ -5930,10 +5929,10 @@ IonBuilder::jsop_eval(uint32_t argc) // name on the scope chain and the eval is performing a call on that // value. Use a dynamic scope chain lookup rather than a full eval. if (string->isConcat() && - string->getOperand(1)->isConstant() && - string->getOperand(1)->toConstant()->value().isString()) + string->getOperand(1)->isConstantValue() && + string->getOperand(1)->constantValue().isString()) { - JSAtom *atom = &string->getOperand(1)->toConstant()->value().toString()->asAtom(); + JSAtom *atom = &string->getOperand(1)->constantValue().toString()->asAtom(); if (StringEqualsAscii(atom, "()")) { MDefinition *name = string->getOperand(0); @@ -7846,10 +7845,10 @@ IonBuilder::getElemTryArgumentsInlined(bool *emitted, MDefinition *obj, MDefinit MOZ_ASSERT(!info().argsObjAliasesFormals()); // When the id is constant, we can just return the corresponding inlined argument - if (index->isConstant() && index->toConstant()->value().isInt32()) { + if (index->isConstantValue() && index->constantValue().isInt32()) { MOZ_ASSERT(inliningDepth_ > 0); - int32_t id = index->toConstant()->value().toInt32(); + int32_t id = index->constantValue().toInt32(); index->setImplicitlyUsedUnchecked(); if (id < (int32_t)inlineCallInfo_->argc() && id >= 0) @@ -8065,8 +8064,8 @@ IonBuilder::addTypedArrayLengthAndData(MDefinition *obj, MOZ_ASSERT((index != nullptr) == (elements != nullptr)); JSObject *tarr = nullptr; - if (obj->isConstant() && obj->toConstant()->value().isObject()) - tarr = &obj->toConstant()->value().toObject(); + if (obj->isConstantValue() && obj->constantValue().isObject()) + tarr = &obj->constantValue().toObject(); else if (obj->resultTypeSet()) tarr = obj->resultTypeSet()->getSingleton(); @@ -8123,8 +8122,8 @@ IonBuilder::convertShiftToMaskForStaticTypedArray(MDefinition *id, // If the index is an already shifted constant, undo the shift to get the // absolute offset being accessed. - if (id->isConstant() && id->toConstant()->value().isInt32()) { - int32_t index = id->toConstant()->value().toInt32(); + if (id->isConstantValue() && id->constantValue().isInt32()) { + int32_t index = id->constantValue().toInt32(); MConstant *offset = MConstant::New(alloc(), Int32Value(index << TypedArrayShift(viewType))); current->add(offset); return offset; @@ -8132,9 +8131,9 @@ IonBuilder::convertShiftToMaskForStaticTypedArray(MDefinition *id, if (!id->isRsh() || id->isEffectful()) return nullptr; - if (!id->getOperand(1)->isConstant()) + if (!id->getOperand(1)->isConstantValue()) return nullptr; - const Value &value = id->getOperand(1)->toConstant()->value(); + const Value &value = id->getOperand(1)->constantValue(); if (!value.isInt32() || uint32_t(value.toInt32()) != TypedArrayShift(viewType)) return nullptr; diff --git a/js/src/jit/Lowering.cpp b/js/src/jit/Lowering.cpp index 1d724cf4fc9..96d7179ea46 100644 --- a/js/src/jit/Lowering.cpp +++ b/js/src/jit/Lowering.cpp @@ -623,7 +623,7 @@ ReorderComparison(JSOp op, MDefinition **lhsp, MDefinition **rhsp) MDefinition *lhs = *lhsp; MDefinition *rhs = *rhsp; - if (lhs->isConstant()) { + if (lhs->isConstantValue()) { *rhsp = lhs; *lhsp = rhs; return ReverseCompareOp(op); @@ -643,8 +643,8 @@ LIRGenerator::visitTest(MTest *test) MOZ_ASSERT(opd->type() != MIRType_String); // Testing a constant. - if (opd->isConstant()) { - bool result = opd->toConstant()->valueToBoolean(); + if (opd->isConstantValue() && !opd->constantValue().isMagic()) { + bool result = opd->constantToBoolean(); add(new(alloc()) LGoto(result ? ifTrue : ifFalse)); return; } @@ -1491,7 +1491,7 @@ LIRGenerator::visitMul(MMul *ins) // If our RHS is a constant -1 and we don't have to worry about // overflow, we can optimize to an LNegI. - if (!ins->fallible() && rhs->isConstant() && rhs->toConstant()->value() == Int32Value(-1)) + if (!ins->fallible() && rhs->isConstantValue() && rhs->constantValue() == Int32Value(-1)) defineReuseInput(new(alloc()) LNegI(useRegisterAtStart(lhs)), ins, 0); else lowerMulI(ins, lhs, rhs); @@ -1500,7 +1500,7 @@ LIRGenerator::visitMul(MMul *ins) ReorderCommutative(&lhs, &rhs, ins); // If our RHS is a constant -1.0, we can optimize to an LNegD. - if (rhs->isConstant() && rhs->toConstant()->value() == DoubleValue(-1.0)) + if (rhs->isConstantValue() && rhs->constantValue() == DoubleValue(-1.0)) defineReuseInput(new(alloc()) LNegD(useRegisterAtStart(lhs)), ins, 0); else lowerForFPU(new(alloc()) LMathD(JSOP_MUL), ins, lhs, rhs); @@ -1509,7 +1509,7 @@ LIRGenerator::visitMul(MMul *ins) ReorderCommutative(&lhs, &rhs, ins); // We apply the same optimizations as for doubles - if (rhs->isConstant() && rhs->toConstant()->value() == Float32Value(-1.0f)) + if (rhs->isConstantValue() && rhs->constantValue() == Float32Value(-1.0f)) defineReuseInput(new(alloc()) LNegF(useRegisterAtStart(lhs)), ins, 0); else lowerForFPU(new(alloc()) LMathF(JSOP_MUL), ins, lhs, rhs); diff --git a/js/src/jit/MCallOptimize.cpp b/js/src/jit/MCallOptimize.cpp index c422f9a07a0..73d2413b7b7 100644 --- a/js/src/jit/MCallOptimize.cpp +++ b/js/src/jit/MCallOptimize.cpp @@ -378,7 +378,7 @@ IonBuilder::inlineArray(CallInfo &callInfo) return InliningStatus_NotInlined; MDefinition *arg = callInfo.getArg(0); - if (!arg->isConstant()) { + if (!arg->isConstantValue()) { callInfo.setImplicitlyUsedUnchecked(); ArrayObject *templateArray = &templateObject->as(); MNewArrayDynamicLength *ins = @@ -391,7 +391,7 @@ IonBuilder::inlineArray(CallInfo &callInfo) } // Negative lengths generate a RangeError, unhandled by the inline path. - initLength = arg->toConstant()->value().toInt32(); + initLength = arg->constantValue().toInt32(); if (initLength >= NativeObject::NELEMENTS_LIMIT) return InliningStatus_NotInlined; @@ -1038,10 +1038,10 @@ IonBuilder::inlineMathPow(CallInfo &callInfo) MDefinition *output = nullptr; // Optimize some constant powers. - if (callInfo.getArg(1)->isConstant() && - callInfo.getArg(1)->toConstant()->value().isNumber()) + if (callInfo.getArg(1)->isConstantValue() && + callInfo.getArg(1)->constantValue().isNumber()) { - double pow = callInfo.getArg(1)->toConstant()->value().toNumber(); + double pow = callInfo.getArg(1)->constantValue().toNumber(); // Math.pow(x, 0.5) is a sqrt with edge-case detection. if (pow == 0.5) { @@ -1216,8 +1216,8 @@ IonBuilder::inlineMathMinMax(CallInfo &callInfo, bool max) case MIRType_Float32: // Don't force a double MMinMax for arguments that would be a NOP // when doing an integer MMinMax. - if (arg->isConstant()) { - double cte = arg->toConstant()->value().toDouble(); + if (arg->isConstantValue()) { + double cte = arg->constantValue().toDouble(); // min(int32, cte >= INT32_MAX) = int32 if (cte >= INT32_MAX && !max) break; @@ -1368,14 +1368,14 @@ IonBuilder::inlineStrCharCodeAt(CallInfo &callInfo) IonBuilder::InliningStatus IonBuilder::inlineConstantCharCodeAt(CallInfo &callInfo) { - if (!callInfo.thisArg()->isConstant()) + if (!callInfo.thisArg()->isConstantValue()) return InliningStatus_NotInlined; - if (!callInfo.getArg(0)->isConstant()) + if (!callInfo.getArg(0)->isConstantValue()) return InliningStatus_NotInlined; - const js::Value *strval = callInfo.thisArg()->toConstant()->vp(); - const js::Value *idxval = callInfo.getArg(0)->toConstant()->vp(); + const js::Value *strval = callInfo.thisArg()->constantVp(); + const js::Value *idxval = callInfo.getArg(0)->constantVp(); if (!strval->isString() || !idxval->isInt32()) return InliningStatus_NotInlined; @@ -2033,9 +2033,9 @@ IonBuilder::inlineUnsafeSetReservedSlot(CallInfo &callInfo) // Don't inline if we don't have a constant slot. MDefinition *arg = callInfo.getArg(1); - if (!arg->isConstant()) + if (!arg->isConstantValue()) return InliningStatus_NotInlined; - uint32_t slot = arg->toConstant()->value().toPrivateUint32(); + uint32_t slot = arg->constantValue().toPrivateUint32(); callInfo.setImplicitlyUsedUnchecked(); @@ -2061,9 +2061,9 @@ IonBuilder::inlineUnsafeGetReservedSlot(CallInfo &callInfo) // Don't inline if we don't have a constant slot. MDefinition *arg = callInfo.getArg(1); - if (!arg->isConstant()) + if (!arg->isConstantValue()) return InliningStatus_NotInlined; - uint32_t slot = arg->toConstant()->value().toPrivateUint32(); + uint32_t slot = arg->constantValue().toPrivateUint32(); callInfo.setImplicitlyUsedUnchecked(); @@ -2259,9 +2259,9 @@ IonBuilder::inlineAssertFloat32(CallInfo &callInfo) MDefinition *secondArg = callInfo.getArg(1); MOZ_ASSERT(secondArg->type() == MIRType_Boolean); - MOZ_ASSERT(secondArg->isConstant()); + MOZ_ASSERT(secondArg->isConstantValue()); - bool mustBeFloat32 = secondArg->toConstant()->value().toBoolean(); + bool mustBeFloat32 = secondArg->constantValue().toBoolean(); current->add(MAssertFloat32::New(alloc(), callInfo.getArg(0), mustBeFloat32)); MConstant *undefined = MConstant::New(alloc(), UndefinedValue()); diff --git a/js/src/jit/MIR.cpp b/js/src/jit/MIR.cpp index ca19104a079..bf8895fa182 100644 --- a/js/src/jit/MIR.cpp +++ b/js/src/jit/MIR.cpp @@ -71,17 +71,45 @@ MDefinition::PrintOpcodeName(FILE *fp, MDefinition::Opcode op) fprintf(fp, "%c", tolower(name[i])); } +const Value & +MDefinition::constantValue() +{ + MOZ_ASSERT(isConstantValue()); + + if (isBox()) + return getOperand(0)->constantValue(); + return toConstant()->value(); +} + +const Value * +MDefinition::constantVp() +{ + MOZ_ASSERT(isConstantValue()); + if (isBox()) + return getOperand(0)->constantVp(); + return toConstant()->vp(); +} + +bool +MDefinition::constantToBoolean() +{ + MOZ_ASSERT(isConstantValue()); + if (isBox()) + return getOperand(0)->constantToBoolean(); + return toConstant()->valueToBoolean(); +} + static MConstant * EvaluateConstantOperands(TempAllocator &alloc, MBinaryInstruction *ins, bool *ptypeChange = nullptr) { MDefinition *left = ins->getOperand(0); MDefinition *right = ins->getOperand(1); - if (!left->isConstant() || !right->isConstant()) + if (!left->isConstantValue() || !right->isConstantValue()) return nullptr; - Value lhs = left->toConstant()->value(); - Value rhs = right->toConstant()->value(); + Value lhs = left->constantValue(); + Value rhs = right->constantValue(); Value ret = UndefinedValue(); switch (ins->op()) { @@ -146,10 +174,10 @@ EvaluateExactReciprocal(TempAllocator &alloc, MDiv *ins) MDefinition *left = ins->getOperand(0); MDefinition *right = ins->getOperand(1); - if (!right->isConstant()) + if (!right->isConstantValue()) return nullptr; - Value rhs = right->toConstant()->value(); + Value rhs = right->constantValue(); int32_t num; if (!mozilla::NumberIsInt32(rhs.toNumber(), &num)) @@ -355,8 +383,8 @@ MTest::foldsTo(TempAllocator &alloc) return MTest::New(alloc, op->toNot()->input(), ifFalse(), ifTrue()); } - if (op->isConstant()) - return MGoto::New(alloc, op->toConstant()->valueToBoolean() ? ifTrue() : ifFalse()); + if (op->isConstantValue() && !op->constantValue().isMagic()) + return MGoto::New(alloc, op->constantToBoolean() ? ifTrue() : ifFalse()); switch (op->type()) { case MIRType_Undefined: @@ -768,7 +796,7 @@ MSimdValueX4::foldsTo(TempAllocator &alloc) for (size_t i = 0; i < 4; ++i) { MDefinition *op = getOperand(i); MOZ_ASSERT(op->type() == scalarType); - if (!op->isConstant()) + if (!op->isConstantValue()) allConstants = false; if (i > 0 && op != getOperand(i - 1)) allSame = false; @@ -783,14 +811,14 @@ MSimdValueX4::foldsTo(TempAllocator &alloc) case MIRType_Int32x4: { int32_t a[4]; for (size_t i = 0; i < 4; ++i) - a[i] = getOperand(i)->toConstant()->value().toInt32(); + a[i] = getOperand(i)->constantValue().toInt32(); cst = SimdConstant::CreateX4(a); break; } case MIRType_Float32x4: { float a[4]; for (size_t i = 0; i < 4; ++i) - a[i] = getOperand(i)->toConstant()->value().toNumber(); + a[i] = getOperand(i)->constantValue().toNumber(); cst = SimdConstant::CreateX4(a); break; } @@ -809,7 +837,7 @@ MSimdSplatX4::foldsTo(TempAllocator &alloc) { DebugOnly scalarType = SimdTypeToScalarType(type()); MDefinition *op = getOperand(0); - if (!op->isConstant()) + if (!op->isConstantValue()) return this; MOZ_ASSERT(op->type() == scalarType); @@ -817,7 +845,7 @@ MSimdSplatX4::foldsTo(TempAllocator &alloc) switch (type()) { case MIRType_Int32x4: { int32_t a[4]; - int32_t v = getOperand(0)->toConstant()->value().toInt32(); + int32_t v = getOperand(0)->constantValue().toInt32(); for (size_t i = 0; i < 4; ++i) a[i] = v; cst = SimdConstant::CreateX4(a); @@ -825,7 +853,7 @@ MSimdSplatX4::foldsTo(TempAllocator &alloc) } case MIRType_Float32x4: { float a[4]; - float v = getOperand(0)->toConstant()->value().toNumber(); + float v = getOperand(0)->constantValue().toNumber(); for (size_t i = 0; i < 4; ++i) a[i] = v; cst = SimdConstant::CreateX4(a); @@ -1096,8 +1124,8 @@ MApplyArgs::New(TempAllocator &alloc, JSFunction *target, MDefinition *fun, MDef MDefinition* MStringLength::foldsTo(TempAllocator &alloc) { - if ((type() == MIRType_Int32) && (string()->isConstant())) { - Value value = string()->toConstant()->value(); + if ((type() == MIRType_Int32) && (string()->isConstantValue())) { + Value value = string()->constantValue(); JSAtom *atom = &value.toString()->asAtom(); return MConstant::New(alloc, Int32Value(atom->length())); } @@ -1884,12 +1912,10 @@ MMinMax::foldsTo(TempAllocator &alloc) if (!lhs()->isConstant() && !rhs()->isConstant()) return this; - MDefinition *operand = lhs()->isConstant() ? rhs() : lhs(); - MConstant *constant = lhs()->isConstant() ? lhs()->toConstant() : rhs()->toConstant(); + MDefinition *operand = lhs()->isConstantValue() ? rhs() : lhs(); + const js::Value &val = lhs()->isConstantValue() ? lhs()->constantValue() : rhs()->constantValue(); if (operand->isToDouble() && operand->getOperand(0)->type() == MIRType_Int32) { - const js::Value &val = constant->value(); - // min(int32, cte >= INT32_MAX) = int32 if (val.isDouble() && val.toDouble() >= INT32_MAX && !isMax()) { MLimitedTruncate *limit = @@ -1959,25 +1985,25 @@ MDiv::analyzeEdgeCasesForward() return; // Try removing divide by zero check - if (rhs()->isConstant() && !rhs()->toConstant()->value().isInt32(0)) + if (rhs()->isConstantValue() && !rhs()->constantValue().isInt32(0)) canBeDivideByZero_ = false; // If lhs is a constant int != INT32_MIN, then // negative overflow check can be skipped. - if (lhs()->isConstant() && !lhs()->toConstant()->value().isInt32(INT32_MIN)) + if (lhs()->isConstantValue() && !lhs()->constantValue().isInt32(INT32_MIN)) canBeNegativeOverflow_ = false; // If rhs is a constant int != -1, likewise. - if (rhs()->isConstant() && !rhs()->toConstant()->value().isInt32(-1)) + if (rhs()->isConstantValue() && !rhs()->constantValue().isInt32(-1)) canBeNegativeOverflow_ = false; // If lhs is != 0, then negative zero check can be skipped. - if (lhs()->isConstant() && !lhs()->toConstant()->value().isInt32(0)) + if (lhs()->isConstantValue() && !lhs()->constantValue().isInt32(0)) setCanBeNegativeZero(false); // If rhs is >= 0, likewise. - if (rhs()->isConstant()) { - const js::Value &val = rhs()->toConstant()->value(); + if (rhs()->isConstantValue()) { + const js::Value &val = rhs()->constantValue(); if (val.isInt32() && val.toInt32() >= 0) setCanBeNegativeZero(false); } @@ -2015,11 +2041,11 @@ MMod::analyzeEdgeCasesForward() if (specialization_ != MIRType_Int32) return; - if (rhs()->isConstant() && !rhs()->toConstant()->value().isInt32(0)) + if (rhs()->isConstantValue() && !rhs()->constantValue().isInt32(0)) canBeDivideByZero_ = false; - if (rhs()->isConstant()) { - int32_t n = rhs()->toConstant()->value().toInt32(); + if (rhs()->isConstantValue()) { + int32_t n = rhs()->constantValue().toInt32(); if (n > 0 && !IsPowerOfTwo(n)) canBePowerOfTwoDivisor_ = false; } @@ -2093,15 +2119,15 @@ MMul::analyzeEdgeCasesForward() return; // If lhs is > 0, no need for negative zero check. - if (lhs()->isConstant()) { - const js::Value &val = lhs()->toConstant()->value(); + if (lhs()->isConstantValue()) { + const js::Value &val = lhs()->constantValue(); if (val.isInt32() && val.toInt32() > 0) setCanBeNegativeZero(false); } // If rhs is > 0, likewise. - if (rhs()->isConstant()) { - const js::Value &val = rhs()->toConstant()->value(); + if (rhs()->isConstantValue()) { + const js::Value &val = rhs()->constantValue(); if (val.isInt32() && val.toInt32() > 0) setCanBeNegativeZero(false); } @@ -2370,15 +2396,15 @@ MustBeUInt32(MDefinition *def, MDefinition **pwrapped) *pwrapped = def->toUrsh()->getOperand(0); MDefinition *rhs = def->toUrsh()->getOperand(1); return !def->toUrsh()->bailoutsDisabled() - && rhs->isConstant() - && rhs->toConstant()->value().isInt32() - && rhs->toConstant()->value().toInt32() == 0; + && rhs->isConstantValue() + && rhs->constantValue().isInt32() + && rhs->constantValue().toInt32() == 0; } - if (def->isConstant()) { + if (def->isConstantValue()) { *pwrapped = def; - return def->toConstant()->value().isInt32() - && def->toConstant()->value().toInt32() >= 0; + return def->constantValue().isInt32() + && def->constantValue().toInt32() >= 0; } return false; @@ -2553,7 +2579,7 @@ MBitNot::foldsTo(TempAllocator &alloc) MDefinition *input = getOperand(0); if (input->isConstant()) { - js::Value v = Int32Value(~(input->toConstant()->value().toInt32())); + js::Value v = Int32Value(~(input->constantValue().toInt32())); return MConstant::New(alloc, v); } @@ -2878,11 +2904,14 @@ MDefinition * MTruncateToInt32::foldsTo(TempAllocator &alloc) { MDefinition *input = getOperand(0); + if (input->isBox()) + input = input->getOperand(0); + if (input->type() == MIRType_Int32) return input; if (input->type() == MIRType_Double && input->isConstant()) { - const Value &v = input->toConstant()->value(); + const Value &v = input->constantValue(); int32_t ret = ToInt32(v.toDouble()); return MConstant::New(alloc, Int32Value(ret)); } @@ -2893,12 +2922,15 @@ MTruncateToInt32::foldsTo(TempAllocator &alloc) MDefinition * MToDouble::foldsTo(TempAllocator &alloc) { - MDefinition *in = input(); - if (in->type() == MIRType_Double) - return in; + MDefinition *input = getOperand(0); + if (input->isBox()) + input = input->getOperand(0); - if (in->isConstant()) { - const Value &v = in->toConstant()->value(); + if (input->type() == MIRType_Double) + return input; + + if (input->isConstant()) { + const Value &v = input->toConstant()->value(); if (v.isNumber()) { double out = v.toNumber(); return MConstant::New(alloc, DoubleValue(out)); @@ -2911,15 +2943,19 @@ MToDouble::foldsTo(TempAllocator &alloc) MDefinition * MToFloat32::foldsTo(TempAllocator &alloc) { - if (input()->type() == MIRType_Float32) - return input(); + MDefinition *input = getOperand(0); + if (input->isBox()) + input = input->getOperand(0); + + if (input->type() == MIRType_Float32) + return input; // If x is a Float32, Float32(Double(x)) == x - if (input()->isToDouble() && input()->toToDouble()->input()->type() == MIRType_Float32) - return input()->toToDouble()->input(); + if (input->isToDouble() && input->toToDouble()->input()->type() == MIRType_Float32) + return input->toToDouble()->input(); - if (input()->isConstant()) { - const Value &v = input()->toConstant()->value(); + if (input->isConstant()) { + const Value &v = input->toConstant()->value(); if (v.isNumber()) { float out = v.toNumber(); MConstant *c = MConstant::New(alloc, DoubleValue(out)); @@ -2934,6 +2970,9 @@ MDefinition * MToString::foldsTo(TempAllocator &alloc) { MDefinition *in = input(); + if (in->isBox()) + in = in->getOperand(0); + if (in->type() == MIRType_String) return in; return this; @@ -2942,8 +2981,8 @@ MToString::foldsTo(TempAllocator &alloc) MDefinition * MClampToUint8::foldsTo(TempAllocator &alloc) { - if (input()->isConstant()) { - const Value &v = input()->toConstant()->value(); + if (input()->isConstantValue()) { + const Value &v = input()->constantValue(); if (v.isDouble()) { int32_t clamped = ClampDoubleToUint8(v.toDouble()); return MConstant::New(alloc, Int32Value(clamped)); @@ -3358,8 +3397,8 @@ MDefinition * MNot::foldsTo(TempAllocator &alloc) { // Fold if the input is constant - if (input()->isConstant()) { - bool result = input()->toConstant()->valueToBoolean(); + if (input()->isConstantValue() && !input()->constantValue().isMagic()) { + bool result = input()->constantToBoolean(); if (type() == MIRType_Int32) return MConstant::New(alloc, Int32Value(!result)); @@ -3925,8 +3964,8 @@ MGetPropertyCache::updateForReplacement(MDefinition *ins) { MDefinition * MAsmJSUnsignedToDouble::foldsTo(TempAllocator &alloc) { - if (input()->isConstant()) { - const Value &v = input()->toConstant()->value(); + if (input()->isConstantValue()) { + const Value &v = input()->constantValue(); if (v.isInt32()) return MConstant::New(alloc, DoubleValue(uint32_t(v.toInt32()))); } @@ -3937,8 +3976,8 @@ MAsmJSUnsignedToDouble::foldsTo(TempAllocator &alloc) MDefinition * MAsmJSUnsignedToFloat32::foldsTo(TempAllocator &alloc) { - if (input()->isConstant()) { - const Value &v = input()->toConstant()->value(); + if (input()->isConstantValue()) { + const Value &v = input()->constantValue(); if (v.isInt32()) { double dval = double(uint32_t(v.toInt32())); if (IsFloat32Representable(dval)) @@ -3987,8 +4026,8 @@ MSqrt::trySpecializeFloat32(TempAllocator &alloc) { MDefinition * MClz::foldsTo(TempAllocator &alloc) { - if (num()->isConstant()) { - int32_t n = num()->toConstant()->value().toInt32(); + if (num()->isConstantValue()) { + int32_t n = num()->constantValue().toInt32(); if (n == 0) return MConstant::New(alloc, Int32Value(32)); return MConstant::New(alloc, Int32Value(mozilla::CountLeadingZeroes32(n))); @@ -4000,9 +4039,9 @@ MClz::foldsTo(TempAllocator &alloc) MDefinition * MBoundsCheck::foldsTo(TempAllocator &alloc) { - if (index()->isConstant() && length()->isConstant()) { - uint32_t len = length()->toConstant()->value().toInt32(); - uint32_t idx = index()->toConstant()->value().toInt32(); + if (index()->isConstantValue() && length()->isConstantValue()) { + uint32_t len = length()->constantValue().toInt32(); + uint32_t idx = index()->constantValue().toInt32(); if (idx + uint32_t(minimum()) < len && idx + uint32_t(maximum()) < len) return index(); } diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index 909e114f04a..cdd30ce3f2d 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -752,6 +752,13 @@ class MDefinition : public MNode MIR_OPCODE_LIST(OPCODE_CASTS) # undef OPCODE_CASTS + bool isConstantValue() { + return isConstant() || (isBox() && getOperand(0)->isConstant()); + } + const Value &constantValue(); + const Value *constantVp(); + bool constantToBoolean(); + inline MInstruction *toInstruction(); inline const MInstruction *toInstruction() const; bool isInstruction() const { diff --git a/js/src/jit/RangeAnalysis.cpp b/js/src/jit/RangeAnalysis.cpp index 4f7bf6c108b..73956c67549 100644 --- a/js/src/jit/RangeAnalysis.cpp +++ b/js/src/jit/RangeAnalysis.cpp @@ -174,12 +174,12 @@ RangeAnalysis::addBetaNodes() conservativeUpper = GenericNaN(); } - if (left->isConstant() && left->toConstant()->value().isNumber()) { - bound = left->toConstant()->value().toNumber(); + if (left->isConstantValue() && left->constantValue().isNumber()) { + bound = left->constantValue().toNumber(); val = right; jsop = ReverseCompareOp(jsop); - } else if (right->isConstant() && right->toConstant()->value().isNumber()) { - bound = right->toConstant()->value().toNumber(); + } else if (right->isConstantValue() && right->constantValue().isNumber()) { + bound = right->constantValue().toNumber(); val = left; } else if (left->type() == MIRType_Int32 && right->type() == MIRType_Int32) { MDefinition *smaller = nullptr; @@ -1310,14 +1310,14 @@ MLsh::computeRange(TempAllocator &alloc) left.wrapAroundToInt32(); MDefinition *rhs = getOperand(1); - if (!rhs->isConstant()) { - right.wrapAroundToShiftCount(); - setRange(Range::lsh(alloc, &left, &right)); + if (rhs->isConstantValue() && rhs->constantValue().isInt32()) { + int32_t c = rhs->constantValue().toInt32(); + setRange(Range::lsh(alloc, &left, c)); return; } - int32_t c = rhs->toConstant()->value().toInt32(); - setRange(Range::lsh(alloc, &left, c)); + right.wrapAroundToShiftCount(); + setRange(Range::lsh(alloc, &left, &right)); } void @@ -1328,14 +1328,14 @@ MRsh::computeRange(TempAllocator &alloc) left.wrapAroundToInt32(); MDefinition *rhs = getOperand(1); - if (!rhs->isConstant()) { - right.wrapAroundToShiftCount(); - setRange(Range::rsh(alloc, &left, &right)); + if (rhs->isConstantValue() && rhs->constantValue().isInt32()) { + int32_t c = rhs->constantValue().toInt32(); + setRange(Range::rsh(alloc, &left, c)); return; } - int32_t c = rhs->toConstant()->value().toInt32(); - setRange(Range::rsh(alloc, &left, c)); + right.wrapAroundToShiftCount(); + setRange(Range::rsh(alloc, &left, &right)); } void @@ -1353,11 +1353,11 @@ MUrsh::computeRange(TempAllocator &alloc) right.wrapAroundToShiftCount(); MDefinition *rhs = getOperand(1); - if (!rhs->isConstant()) { - setRange(Range::ursh(alloc, &left, &right)); - } else { - int32_t c = rhs->toConstant()->value().toInt32(); + if (rhs->isConstantValue() && rhs->constantValue().isInt32()) { + int32_t c = rhs->constantValue().toInt32(); setRange(Range::ursh(alloc, &left, c)); + } else { + setRange(Range::ursh(alloc, &left, &right)); } MOZ_ASSERT(range()->lower() >= 0); @@ -2734,7 +2734,7 @@ CloneForDeadBranches(TempAllocator &alloc, MInstruction *candidate) candidate->block()->insertBefore(candidate, clone); - if (!candidate->isConstant()) { + if (!candidate->isConstantValue()) { MOZ_ASSERT(clone->canRecoverOnBailout()); clone->setRecoveredOnBailout(); } diff --git a/js/src/jit/ScalarReplacement.cpp b/js/src/jit/ScalarReplacement.cpp index 2900fc54f0d..c96ba425751 100644 --- a/js/src/jit/ScalarReplacement.cpp +++ b/js/src/jit/ScalarReplacement.cpp @@ -533,10 +533,10 @@ IndexOf(MDefinition *ins, int32_t *res) indexDef = indexDef->toBoundsCheck()->index(); if (indexDef->isToInt32()) indexDef = indexDef->toToInt32()->getOperand(0); - if (!indexDef->isConstant()) + if (!indexDef->isConstantValue()) return false; - Value index = indexDef->toConstant()->value(); + Value index = indexDef->constantValue(); if (!index.isInt32()) return false; *res = index.toInt32(); @@ -966,7 +966,7 @@ ArrayMemoryView::visitSetInitializedLength(MSetInitializedLength *ins) // To obtain the length, we need to add 1 to it, and thus we need to create // a new constant that we register in the ArrayState. state_ = BlockState::Copy(alloc_, state_); - int32_t initLengthValue = ins->index()->toConstant()->value().toInt32() + 1; + int32_t initLengthValue = ins->index()->constantValue().toInt32() + 1; MConstant *initLength = MConstant::New(alloc_, Int32Value(initLengthValue)); ins->block()->insertBefore(ins, initLength); ins->block()->insertBefore(ins, state_); diff --git a/js/src/jit/arm/Lowering-arm.cpp b/js/src/jit/arm/Lowering-arm.cpp index 04327f22987..b75169543a7 100644 --- a/js/src/jit/arm/Lowering-arm.cpp +++ b/js/src/jit/arm/Lowering-arm.cpp @@ -492,10 +492,10 @@ LIRGeneratorARM::visitAsmJSLoadHeap(MAsmJSLoadHeap *ins) LAllocation ptrAlloc; // For the ARM it is best to keep the 'ptr' in a register if a bounds check is needed. - if (ptr->isConstant() && !ins->needsBoundsCheck()) { + if (ptr->isConstantValue() && !ins->needsBoundsCheck()) { // A bounds check is only skipped for a positive index. - MOZ_ASSERT(ptr->toConstant()->value().toInt32() >= 0); - ptrAlloc = LAllocation(ptr->toConstant()->vp()); + MOZ_ASSERT(ptr->constantValue().toInt32() >= 0); + ptrAlloc = LAllocation(ptr->constantVp()); } else { ptrAlloc = useRegisterAtStart(ptr); } @@ -510,9 +510,9 @@ LIRGeneratorARM::visitAsmJSStoreHeap(MAsmJSStoreHeap *ins) MOZ_ASSERT(ptr->type() == MIRType_Int32); LAllocation ptrAlloc; - if (ptr->isConstant() && !ins->needsBoundsCheck()) { - MOZ_ASSERT(ptr->toConstant()->value().toInt32() >= 0); - ptrAlloc = LAllocation(ptr->toConstant()->vp()); + if (ptr->isConstantValue() && !ins->needsBoundsCheck()) { + MOZ_ASSERT(ptr->constantValue().toInt32() >= 0); + ptrAlloc = LAllocation(ptr->constantVp()); } else { ptrAlloc = useRegisterAtStart(ptr); } diff --git a/js/src/jit/mips/Lowering-mips.cpp b/js/src/jit/mips/Lowering-mips.cpp index 68c59be55f8..60364bad610 100644 --- a/js/src/jit/mips/Lowering-mips.cpp +++ b/js/src/jit/mips/Lowering-mips.cpp @@ -470,11 +470,11 @@ LIRGeneratorMIPS::visitAsmJSLoadHeap(MAsmJSLoadHeap *ins) // For MIPS it is best to keep the 'ptr' in a register if a bounds check // is needed. - if (ptr->isConstant() && !ins->needsBoundsCheck()) { - int32_t ptrValue = ptr->toConstant()->value().toInt32(); + if (ptr->isConstantValue() && !ins->needsBoundsCheck()) { + int32_t ptrValue = ptr->constantValue().toInt32(); // A bounds check is only skipped for a positive index. MOZ_ASSERT(ptrValue >= 0); - ptrAlloc = LAllocation(ptr->toConstant()->vp()); + ptrAlloc = LAllocation(ptr->constantVp()); } else ptrAlloc = useRegisterAtStart(ptr); @@ -488,9 +488,9 @@ LIRGeneratorMIPS::visitAsmJSStoreHeap(MAsmJSStoreHeap *ins) MOZ_ASSERT(ptr->type() == MIRType_Int32); LAllocation ptrAlloc; - if (ptr->isConstant() && !ins->needsBoundsCheck()) { - MOZ_ASSERT(ptr->toConstant()->value().toInt32() >= 0); - ptrAlloc = LAllocation(ptr->toConstant()->vp()); + if (ptr->isConstantValue() && !ins->needsBoundsCheck()) { + MOZ_ASSERT(ptr->constantValue().toInt32() >= 0); + ptrAlloc = LAllocation(ptr->constantVp()); } else ptrAlloc = useRegisterAtStart(ptr);