зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1101356 - MHypot Instruction supports up to four arguments. r=nbp
This commit is contained in:
Родитель
659f621d17
Коммит
cc6c44b80f
|
@ -21,5 +21,14 @@ assertNear(Math.hypot(1e3, 1e-3), 1000.0000000005);
|
|||
assertNear(Math.hypot(1e-300, 1e300), 1e300);
|
||||
assertNear(Math.hypot(1e3, 1e-3, 1e3, 1e-3), 1414.2135623738021555);
|
||||
|
||||
for (var i = 1, j = 1; i < 2; i += 0.05, j += 0.05)
|
||||
assertNear(Math.hypot(1e1, 1e2, 1e3), Math.sqrt(1e2 + 1e4 + 1e6));
|
||||
assertNear(Math.hypot(1e1, 1e2, 1e3, 1e4), Math.sqrt(1e2 + 1e4 + 1e6 + 1e8));
|
||||
|
||||
for (var i = 1, j = 2; i < 2; i += 0.05, j += 0.05)
|
||||
assertNear(Math.hypot(i, j), Math.sqrt(i * i + j * j));
|
||||
|
||||
for (var i = 1, j = 2, k = 3; i < 2; i += 0.05, j += 0.05, k += 0.05)
|
||||
assertNear(Math.hypot(i, j, k), Math.sqrt(i * i + j * j + k * k));
|
||||
|
||||
for (var i = 1, j = 2, k = 3, l = 4; i < 2; i += 0.05, j += 0.05, k += 0.05, l += 0.5)
|
||||
assertNear(Math.hypot(i, j, k, l), Math.sqrt(i * i + j * j + k * k + l * l));
|
||||
|
|
|
@ -28,6 +28,11 @@ for (var inf of [Infinity, -Infinity]) {
|
|||
assertEq(Math.hypot(inf, NaN, NaN), Infinity);
|
||||
assertEq(Math.hypot(NaN, inf, NaN), Infinity);
|
||||
assertEq(Math.hypot(NaN, NaN, inf), Infinity);
|
||||
|
||||
assertEq(Math.hypot(inf, NaN, NaN, NaN), Infinity);
|
||||
assertEq(Math.hypot(NaN, inf, NaN, NaN), Infinity);
|
||||
assertEq(Math.hypot(NaN, NaN, inf, NaN), Infinity);
|
||||
assertEq(Math.hypot(NaN, NaN, NaN, inf), Infinity);
|
||||
}
|
||||
|
||||
// If no argument is +∞ or −∞, and any argument is NaN, the result is NaN.
|
||||
|
@ -42,7 +47,13 @@ assertEq(Math.hypot(NaN, 0, 0), NaN);
|
|||
assertEq(Math.hypot(0, NaN, 0), NaN);
|
||||
assertEq(Math.hypot(0, 0, NaN), NaN);
|
||||
|
||||
assertEq(Math.hypot(NaN, 0, 0, 0), NaN);
|
||||
assertEq(Math.hypot(0, NaN, 0, 0), NaN);
|
||||
assertEq(Math.hypot(0, 0, NaN, 0), NaN);
|
||||
assertEq(Math.hypot(0, 0, 0, NaN), NaN);
|
||||
|
||||
assertEq(Math.hypot(Number.MAX_VALUE, Number.MIN_VALUE, NaN), NaN);
|
||||
assertEq(Math.hypot(Number.MAX_VALUE, Number.MIN_VALUE, Number.MIN_VALUE, NaN), NaN);
|
||||
|
||||
// If all arguments are either +0 or -0, the result is +0.
|
||||
assertEq(Math.hypot(-0, -0), +0);
|
||||
|
@ -53,5 +64,11 @@ assertEq(Math.hypot(+0, -0, -0), +0);
|
|||
assertEq(Math.hypot(-0, +0, -0), +0);
|
||||
assertEq(Math.hypot(+0, +0, -0), +0);
|
||||
|
||||
assertEq(Math.hypot(-0, -0, -0, -0), +0);
|
||||
assertEq(Math.hypot(+0, -0, -0, -0), +0);
|
||||
assertEq(Math.hypot(-0, -0, +0, -0), +0);
|
||||
assertEq(Math.hypot(+0, +0, +0, -0), +0);
|
||||
assertEq(Math.hypot(-0, -0, -0, +0), +0);
|
||||
|
||||
// The length property of the hypot function is 2.
|
||||
assertEq(Math.hypot.length, 2);
|
||||
|
|
|
@ -1062,16 +1062,32 @@ function rtrunc_to_int32_string(i) {
|
|||
return i;
|
||||
}
|
||||
|
||||
var uceFault_hypot_number = eval(uneval(uceFault).replace('uceFault', 'uceFault_hypot_number'));
|
||||
function rhypot_number(i) {
|
||||
var uceFault_hypot_number_2args = eval(uneval(uceFault).replace('uceFault', 'uceFault_hypot_number_2args'));
|
||||
function rhypot_number_2args(i) {
|
||||
var x = Math.hypot(i, i + 1);
|
||||
if (uceFault_hypot_number(i) || uceFault_hypot_number(i))
|
||||
if (uceFault_hypot_number_2args(i) || uceFault_hypot_number_2args(i))
|
||||
assertEq(x, Math.sqrt(i * i + (i + 1) * (i + 1)));
|
||||
return i;
|
||||
}
|
||||
|
||||
var uceFault_hypot_object = eval(uneval(uceFault).replace('uceFault', 'uceFault_hypot_object'));
|
||||
function rhypot_object(i) {
|
||||
var uceFault_hypot_number_3args = eval(uneval(uceFault).replace('uceFault', 'uceFault_hypot_number_3args'));
|
||||
function rhypot_number_3args(i) {
|
||||
var x = Math.hypot(i, i + 1, i + 2);
|
||||
if (uceFault_hypot_number_3args(i) || uceFault_hypot_number_3args(i))
|
||||
assertEq(x, Math.sqrt(i * i + (i + 1) * (i + 1) + (i + 2) * (i + 2)));
|
||||
return i;
|
||||
}
|
||||
|
||||
var uceFault_hypot_number_4args = eval(uneval(uceFault).replace('uceFault', 'uceFault_hypot_number_4args'));
|
||||
function rhypot_number_4args(i) {
|
||||
var x = Math.hypot(i, i + 1, i + 2, i + 3);
|
||||
if (uceFault_hypot_number_4args(i) || uceFault_hypot_number_4args(i))
|
||||
assertEq(x, Math.sqrt(i * i + (i + 1) * (i + 1) + (i + 2) * (i + 2) + (i + 3) * (i + 3)));
|
||||
return i;
|
||||
}
|
||||
|
||||
var uceFault_hypot_object_2args = eval(uneval(uceFault).replace('uceFault', 'uceFault_hypot_object_2args'));
|
||||
function rhypot_object_2args(i) {
|
||||
var t0 = i;
|
||||
var t1 = i + 1;
|
||||
var o0 = { valueOf: function () { return t0; } };
|
||||
|
@ -1079,11 +1095,48 @@ function rhypot_object(i) {
|
|||
var x = Math.hypot(o0, o1);
|
||||
t0 = 1000;
|
||||
t1 = 2000;
|
||||
if (uceFault_hypot_object(i) || uceFault_hypot_object(i) )
|
||||
if (uceFault_hypot_object_2args(i) || uceFault_hypot_object_2args(i) )
|
||||
assertEq(x, Math.sqrt(i * i + (i + 1) * (i + 1)));
|
||||
return i;
|
||||
}
|
||||
|
||||
var uceFault_hypot_object_3args = eval(uneval(uceFault).replace('uceFault', 'uceFault_hypot_object_3args'));
|
||||
function rhypot_object_3args(i) {
|
||||
var t0 = i;
|
||||
var t1 = i + 1;
|
||||
var t2 = i + 2;
|
||||
var o0 = { valueOf: function () { return t0; } };
|
||||
var o1 = { valueOf: function () { return t1; } };
|
||||
var o2 = { valueOf: function () { return t2; } };
|
||||
var x = Math.hypot(o0, o1, o2);
|
||||
t0 = 1000;
|
||||
t1 = 2000;
|
||||
t2 = 3000;
|
||||
if (uceFault_hypot_object_3args(i) || uceFault_hypot_object_3args(i) )
|
||||
assertEq(x, Math.sqrt(i * i + (i + 1) * (i + 1) + (i + 2) * (i + 2)));
|
||||
return i;
|
||||
}
|
||||
|
||||
var uceFault_hypot_object_4args = eval(uneval(uceFault).replace('uceFault', 'uceFault_hypot_object_4args'));
|
||||
function rhypot_object_4args(i) {
|
||||
var t0 = i;
|
||||
var t1 = i + 1;
|
||||
var t2 = i + 2;
|
||||
var t3 = i + 3;
|
||||
var o0 = { valueOf: function () { return t0; } };
|
||||
var o1 = { valueOf: function () { return t1; } };
|
||||
var o2 = { valueOf: function () { return t2; } };
|
||||
var o3 = { valueOf: function () { return t3; } };
|
||||
var x = Math.hypot(o0, o1, o2, o3);
|
||||
t0 = 1000;
|
||||
t1 = 2000;
|
||||
t2 = 3000;
|
||||
t3 = 4000;
|
||||
if (uceFault_hypot_object_4args(i) || uceFault_hypot_object_4args(i) )
|
||||
assertEq(x, Math.sqrt(i * i + (i + 1) * (i + 1) + (i + 2) * (i + 2) + (i + 3) * (i + 3)));
|
||||
return i;
|
||||
}
|
||||
|
||||
var uceFault_sin_number = eval(uneval(uceFault).replace('uceFault', 'uceFault_sin_number'));
|
||||
function rsin_number(i) {
|
||||
var x = Math.sin(i);
|
||||
|
@ -1224,8 +1277,12 @@ for (i = 0; i < 100; i++) {
|
|||
rtrunc_to_int32_number(i);
|
||||
rtrunc_to_int32_object(i);
|
||||
rtrunc_to_int32_string(i);
|
||||
rhypot_number(i);
|
||||
rhypot_object(i);
|
||||
rhypot_number_2args(i);
|
||||
rhypot_number_3args(i);
|
||||
rhypot_number_4args(i);
|
||||
rhypot_object_2args(i);
|
||||
rhypot_object_3args(i);
|
||||
rhypot_object_4args(i);
|
||||
rsin_number(i);
|
||||
rsin_object(i);
|
||||
rlog_number(i);
|
||||
|
|
|
@ -3908,14 +3908,25 @@ void
|
|||
CodeGenerator::visitHypot(LHypot *lir)
|
||||
{
|
||||
Register temp = ToRegister(lir->temp());
|
||||
FloatRegister x = ToFloatRegister(lir->x());
|
||||
FloatRegister y = ToFloatRegister(lir->y());
|
||||
uint32_t numArgs = lir->numArgs();
|
||||
masm.setupUnalignedABICall(numArgs, temp);
|
||||
|
||||
masm.setupUnalignedABICall(2, temp);
|
||||
masm.passABIArg(x, MoveOp::DOUBLE);
|
||||
masm.passABIArg(y, MoveOp::DOUBLE);
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, ecmaHypot), MoveOp::DOUBLE);
|
||||
for (uint32_t i = 0 ; i < numArgs; ++i)
|
||||
masm.passABIArg(ToFloatRegister(lir->getOperand(i)), MoveOp::DOUBLE);
|
||||
|
||||
switch(numArgs) {
|
||||
case 2:
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, ecmaHypot), MoveOp::DOUBLE);
|
||||
break;
|
||||
case 3:
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, hypot3), MoveOp::DOUBLE);
|
||||
break;
|
||||
case 4:
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, hypot4), MoveOp::DOUBLE);
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("Unexpected number of arguments to hypot function.");
|
||||
}
|
||||
MOZ_ASSERT(ToFloatRegister(lir->output()) == ReturnDoubleReg);
|
||||
}
|
||||
|
||||
|
|
|
@ -636,7 +636,14 @@ enum ABIFunctionType
|
|||
// int f(int, double)
|
||||
Args_Int_IntDouble = Args_General0 |
|
||||
(ArgType_Double << (ArgType_Shift * 1)) |
|
||||
(ArgType_General << (ArgType_Shift * 2))
|
||||
(ArgType_General << (ArgType_Shift * 2)),
|
||||
|
||||
// double f(double, double, double)
|
||||
Args_Double_DoubleDoubleDouble = Args_Double_DoubleDouble | (ArgType_Double << (ArgType_Shift * 3)),
|
||||
|
||||
// double f(double, double, double, double)
|
||||
Args_Double_DoubleDoubleDoubleDouble = Args_Double_DoubleDoubleDouble | (ArgType_Double << (ArgType_Shift * 4))
|
||||
|
||||
};
|
||||
|
||||
enum class BarrierKind : uint32_t {
|
||||
|
|
|
@ -2965,16 +2965,40 @@ class LAtan2D : public LCallInstructionHelper<1, 2, 1>
|
|||
}
|
||||
};
|
||||
|
||||
class LHypot : public LCallInstructionHelper<1, 2, 1>
|
||||
class LHypot : public LCallInstructionHelper<1, 4, 1>
|
||||
{
|
||||
uint32_t numOperands_;
|
||||
public:
|
||||
LIR_HEADER(Hypot)
|
||||
LHypot(const LAllocation &x, const LAllocation &y, const LDefinition &temp) {
|
||||
LHypot(const LAllocation &x, const LAllocation &y, const LDefinition &temp)
|
||||
: numOperands_(2)
|
||||
{
|
||||
setOperand(0, x);
|
||||
setOperand(1, y);
|
||||
setTemp(0, temp);
|
||||
}
|
||||
|
||||
LHypot(const LAllocation &x, const LAllocation &y, const LAllocation &z, const LDefinition &temp)
|
||||
: numOperands_(3)
|
||||
{
|
||||
setOperand(0, x);
|
||||
setOperand(1, y);
|
||||
setOperand(2, z);
|
||||
setTemp(0, temp);
|
||||
}
|
||||
|
||||
LHypot(const LAllocation &x, const LAllocation &y, const LAllocation &z, const LAllocation &w, const LDefinition &temp)
|
||||
: numOperands_(4)
|
||||
{
|
||||
setOperand(0, x);
|
||||
setOperand(1, y);
|
||||
setOperand(2, z);
|
||||
setOperand(3, w);
|
||||
setTemp(0, temp);
|
||||
}
|
||||
|
||||
uint32_t numArgs() const { return numOperands_; }
|
||||
|
||||
const LAllocation *x() {
|
||||
return getOperand(0);
|
||||
}
|
||||
|
|
|
@ -1306,13 +1306,34 @@ LIRGenerator::visitAtan2(MAtan2 *ins)
|
|||
void
|
||||
LIRGenerator::visitHypot(MHypot *ins)
|
||||
{
|
||||
MDefinition *x = ins->x();
|
||||
MOZ_ASSERT(x->type() == MIRType_Double);
|
||||
LHypot *lir = nullptr;
|
||||
uint32_t length = ins->numOperands();
|
||||
for (uint32_t i = 0; i < length; ++i)
|
||||
MOZ_ASSERT(ins->getOperand(i)->type() == MIRType_Double);
|
||||
|
||||
MDefinition *y = ins->y();
|
||||
MOZ_ASSERT(y->type() == MIRType_Double);
|
||||
switch(length) {
|
||||
case 2:
|
||||
lir = new(alloc()) LHypot(useRegisterAtStart(ins->getOperand(0)),
|
||||
useRegisterAtStart(ins->getOperand(1)),
|
||||
tempFixed(CallTempReg0));
|
||||
break;
|
||||
case 3:
|
||||
lir = new(alloc()) LHypot(useRegisterAtStart(ins->getOperand(0)),
|
||||
useRegisterAtStart(ins->getOperand(1)),
|
||||
useRegisterAtStart(ins->getOperand(2)),
|
||||
tempFixed(CallTempReg0));
|
||||
break;
|
||||
case 4:
|
||||
lir = new(alloc()) LHypot(useRegisterAtStart(ins->getOperand(0)),
|
||||
useRegisterAtStart(ins->getOperand(1)),
|
||||
useRegisterAtStart(ins->getOperand(2)),
|
||||
useRegisterAtStart(ins->getOperand(3)),
|
||||
tempFixed(CallTempReg0));
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("Unexpected number of arguments to LHypot.");
|
||||
}
|
||||
|
||||
LHypot *lir = new(alloc()) LHypot(useRegisterAtStart(x), useRegisterAtStart(y), tempFixed(CallTempReg0));
|
||||
defineReturn(lir, ins);
|
||||
}
|
||||
|
||||
|
|
|
@ -1002,21 +1002,30 @@ IonBuilder::inlineMathHypot(CallInfo &callInfo)
|
|||
if (callInfo.constructing())
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
if (callInfo.argc() != 2)
|
||||
uint32_t argc = callInfo.argc();
|
||||
if (argc < 2 || argc > 4)
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
if (getInlineReturnType() != MIRType_Double)
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
MIRType argType0 = callInfo.getArg(0)->type();
|
||||
MIRType argType1 = callInfo.getArg(1)->type();
|
||||
|
||||
if (!IsNumberType(argType0) || !IsNumberType(argType1))
|
||||
MDefinitionVector vector(alloc());
|
||||
if (!vector.reserve(argc))
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
callInfo.setImplicitlyUsedUnchecked();
|
||||
for (uint32_t i = 0; i < argc; ++i) {
|
||||
MDefinition * arg = callInfo.getArg(i);
|
||||
if (!IsNumberType(arg->type()))
|
||||
return InliningStatus_NotInlined;
|
||||
vector.infallibleAppend(arg);
|
||||
}
|
||||
|
||||
callInfo.setImplicitlyUsedUnchecked();
|
||||
MHypot *hypot = MHypot::New(alloc(), vector);
|
||||
|
||||
if (!hypot)
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
MHypot *hypot = MHypot::New(alloc(), callInfo.getArg(0), callInfo.getArg(1));
|
||||
current->add(hypot);
|
||||
current->push(hypot);
|
||||
return InliningStatus_Inlined;
|
||||
|
|
|
@ -2231,6 +2231,18 @@ MMathFunction::trySpecializeFloat32(TempAllocator &alloc)
|
|||
setPolicyType(MIRType_Float32);
|
||||
}
|
||||
|
||||
MHypot *MHypot::New(TempAllocator &alloc, const MDefinitionVector & vector)
|
||||
{
|
||||
uint32_t length = vector.length();
|
||||
MHypot * hypot = new(alloc) MHypot;
|
||||
if (!hypot->init(alloc, length))
|
||||
return nullptr;
|
||||
|
||||
for (uint32_t i = 0; i < length; ++i)
|
||||
hypot->initOperand(i, vector[i]);
|
||||
return hypot;
|
||||
}
|
||||
|
||||
bool
|
||||
MAdd::fallible() const
|
||||
{
|
||||
|
|
|
@ -5507,11 +5507,10 @@ class MAtan2
|
|||
|
||||
// Inline implementation of Math.hypot().
|
||||
class MHypot
|
||||
: public MBinaryInstruction,
|
||||
public MixPolicy<DoublePolicy<0>, DoublePolicy<1> >::Data
|
||||
: public MVariadicInstruction,
|
||||
public AllDoublePolicy::Data
|
||||
{
|
||||
MHypot(MDefinition *y, MDefinition *x)
|
||||
: MBinaryInstruction(x, y)
|
||||
MHypot()
|
||||
{
|
||||
setResultType(MIRType_Double);
|
||||
setMovable();
|
||||
|
@ -5519,17 +5518,7 @@ class MHypot
|
|||
|
||||
public:
|
||||
INSTRUCTION_HEADER(Hypot)
|
||||
static MHypot *New(TempAllocator &alloc, MDefinition *x, MDefinition *y) {
|
||||
return new(alloc) MHypot(y, x);
|
||||
}
|
||||
|
||||
MDefinition *x() const {
|
||||
return getOperand(0);
|
||||
}
|
||||
|
||||
MDefinition *y() const {
|
||||
return getOperand(1);
|
||||
}
|
||||
static MHypot *New(TempAllocator &alloc, const MDefinitionVector &vector);
|
||||
|
||||
bool congruentTo(const MDefinition *ins) const MOZ_OVERRIDE {
|
||||
return congruentIfOperandsEqual(ins);
|
||||
|
@ -5548,7 +5537,13 @@ class MHypot
|
|||
return true;
|
||||
}
|
||||
|
||||
ALLOW_CLONE(MHypot)
|
||||
bool canClone() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
MInstruction *clone(TempAllocator &alloc, const MDefinitionVector &inputs) const {
|
||||
return MHypot::New(alloc, inputs);
|
||||
}
|
||||
};
|
||||
|
||||
// Inline implementation of Math.pow().
|
||||
|
|
|
@ -874,10 +874,12 @@ MHypot::writeRecoverData(CompactBufferWriter &writer) const
|
|||
{
|
||||
MOZ_ASSERT(canRecoverOnBailout());
|
||||
writer.writeUnsigned(uint32_t(RInstruction::Recover_Hypot));
|
||||
writer.writeUnsigned(uint32_t(numOperands()));
|
||||
return true;
|
||||
}
|
||||
|
||||
RHypot::RHypot(CompactBufferReader &reader)
|
||||
: numOperands_(reader.readUnsigned())
|
||||
{ }
|
||||
|
||||
bool
|
||||
|
@ -885,12 +887,11 @@ RHypot::recover(JSContext *cx, SnapshotIterator &iter) const
|
|||
{
|
||||
JS::AutoValueVector vec(cx);
|
||||
|
||||
// currently, only 2 args can be saved in MIR
|
||||
if (!vec.reserve(2))
|
||||
if (!vec.reserve(numOperands_))
|
||||
return false;
|
||||
|
||||
vec.infallibleAppend(iter.read());
|
||||
vec.infallibleAppend(iter.read());
|
||||
for (uint32_t i = 0 ; i < numOperands_ ; ++i)
|
||||
vec.infallibleAppend(iter.read());
|
||||
|
||||
RootedValue result(cx);
|
||||
|
||||
|
|
|
@ -477,11 +477,14 @@ class RAtan2 MOZ_FINAL : public RInstruction
|
|||
|
||||
class RHypot MOZ_FINAL : public RInstruction
|
||||
{
|
||||
private:
|
||||
uint32_t numOperands_;
|
||||
|
||||
public:
|
||||
RINSTRUCTION_HEADER_(Hypot)
|
||||
|
||||
virtual uint32_t numOperands() const {
|
||||
return 2;
|
||||
return numOperands_;
|
||||
}
|
||||
|
||||
bool recover(JSContext *cx, SnapshotIterator &iter) const;
|
||||
|
|
|
@ -94,6 +94,26 @@ ArithPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins)
|
|||
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)
|
||||
{
|
||||
|
@ -1025,6 +1045,7 @@ FilterTypeSetPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins)
|
|||
_(StoreTypedArrayPolicy) \
|
||||
_(StoreUnboxedObjectOrNullPolicy) \
|
||||
_(TestPolicy) \
|
||||
_(AllDoublePolicy) \
|
||||
_(ToDoublePolicy) \
|
||||
_(ToInt32Policy) \
|
||||
_(ToStringPolicy) \
|
||||
|
|
|
@ -93,6 +93,13 @@ class ArithPolicy MOZ_FINAL : public TypePolicy
|
|||
virtual bool adjustInputs(TempAllocator &alloc, MInstruction *def) MOZ_OVERRIDE;
|
||||
};
|
||||
|
||||
class AllDoublePolicy MOZ_FINAL : public TypePolicy
|
||||
{
|
||||
public:
|
||||
EMPTY_DATA_;
|
||||
bool adjustInputs(TempAllocator &alloc, MInstruction *def);
|
||||
};
|
||||
|
||||
class BitwisePolicy MOZ_FINAL : public TypePolicy
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -1378,6 +1378,50 @@ js::ecmaHypot(double x, double y)
|
|||
return hypot(x, y);
|
||||
}
|
||||
|
||||
static inline
|
||||
void
|
||||
hypot_step(double &scale, double &sumsq, double x)
|
||||
{
|
||||
double xabs = mozilla::Abs(x);
|
||||
if (scale < xabs) {
|
||||
sumsq = 1 + sumsq * (scale / xabs) * (scale / xabs);
|
||||
scale = xabs;
|
||||
} else if (scale != 0) {
|
||||
sumsq += (xabs / scale) * (xabs / scale);
|
||||
}
|
||||
}
|
||||
|
||||
double
|
||||
js::hypot4(double x, double y, double z, double w)
|
||||
{
|
||||
/* Check for infinity or NaNs so that we can return immediatelly.
|
||||
* Does not need to be WIN_XP specific as ecmaHypot
|
||||
*/
|
||||
if (mozilla::IsInfinite(x) || mozilla::IsInfinite(y) ||
|
||||
mozilla::IsInfinite(z) || mozilla::IsInfinite(w))
|
||||
return mozilla::PositiveInfinity<double>();
|
||||
|
||||
if (mozilla::IsNaN(x) || mozilla::IsNaN(y) || mozilla::IsNaN(z) ||
|
||||
mozilla::IsNaN(w))
|
||||
return GenericNaN();
|
||||
|
||||
double scale = 0;
|
||||
double sumsq = 1;
|
||||
|
||||
hypot_step(scale, sumsq, x);
|
||||
hypot_step(scale, sumsq, y);
|
||||
hypot_step(scale, sumsq, z);
|
||||
hypot_step(scale, sumsq, w);
|
||||
|
||||
return scale * sqrt(sumsq);
|
||||
}
|
||||
|
||||
double
|
||||
js::hypot3(double x, double y, double z)
|
||||
{
|
||||
return hypot4(x, y, z, 0.0);
|
||||
}
|
||||
|
||||
bool
|
||||
js::math_hypot(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
|
@ -1418,14 +1462,7 @@ js::math_hypot_handle(JSContext *cx, HandleValueArray args, MutableHandleValue r
|
|||
if (isInfinite || isNaN)
|
||||
continue;
|
||||
|
||||
double xabs = mozilla::Abs(x);
|
||||
|
||||
if (scale < xabs) {
|
||||
sumsq = 1 + sumsq * (scale / xabs) * (scale / xabs);
|
||||
scale = xabs;
|
||||
} else if (scale != 0) {
|
||||
sumsq += (xabs / scale) * (xabs / scale);
|
||||
}
|
||||
hypot_step(scale, sumsq, x);
|
||||
}
|
||||
|
||||
double result = isInfinite ? PositiveInfinity<double>() :
|
||||
|
|
|
@ -245,6 +245,12 @@ math_atanh(JSContext *cx, unsigned argc, js::Value *vp);
|
|||
extern double
|
||||
ecmaHypot(double x, double y);
|
||||
|
||||
extern double
|
||||
hypot3(double x, double y, double z);
|
||||
|
||||
extern double
|
||||
hypot4(double x, double y, double z, double w);
|
||||
|
||||
extern bool
|
||||
math_hypot(JSContext *cx, unsigned argc, Value *vp);
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче