blob: fbcf35fedc29ff1023cf0a09f9e0a76d678d6145 [file] [log] [blame]
// Copyright 2019 the V8 project authors. All rights reserved. Use of this
// source code is governed by a BSD-style license that can be found in the
// LICENSE file.
namespace math {
transitioning macro ReduceToSmiOrFloat64(implicit context: Context)(x: JSAny):
never
labels SmiResult(Smi), Float64Result(float64) {
let x1: JSAny = x;
while (true) {
typeswitch (x1) {
case (s: Smi): {
goto SmiResult(s);
}
case (h: HeapNumber): {
goto Float64Result(Convert<float64>(h));
}
case (a: JSAnyNotNumber): {
x1 = conversion::NonNumberToNumber(a);
}
}
}
VerifiedUnreachable();
}
// ES6 #sec-math.abs
extern macro IsIntPtrAbsWithOverflowSupported(): constexpr bool;
extern macro TrySmiAdd(Smi, Smi): Smi labels Overflow;
extern macro TrySmiSub(Smi, Smi): Smi labels Overflow;
extern macro TrySmiAbs(Smi): Smi labels Overflow;
extern macro Float64Abs(float64): float64;
const kSmiMaxValuePlusOne:
constexpr float64 generates '0.0 - kSmiMinValue';
transitioning javascript builtin
MathAbs(js-implicit context: NativeContext)(x: JSAny): Number {
try {
ReduceToSmiOrFloat64(x) otherwise SmiResult, Float64Result;
} label SmiResult(s: Smi) {
try {
if constexpr (IsIntPtrAbsWithOverflowSupported()) {
const result: Smi = TrySmiAbs(s)
otherwise SmiOverflow;
return result;
} else {
if (0 <= s) {
return s;
} else {
const result: Smi = TrySmiSub(0, s) otherwise SmiOverflow;
return result;
}
}
} label SmiOverflow {
return NumberConstant(kSmiMaxValuePlusOne);
}
} label Float64Result(f: float64) {
return Convert<Number>(Float64Abs(f));
}
}
// ES6 #sec-math.ceil
extern macro Float64Ceil(float64): float64;
transitioning javascript builtin
MathCeil(js-implicit context: NativeContext)(x: JSAny): Number {
try {
ReduceToSmiOrFloat64(x) otherwise SmiResult, Float64Result;
} label SmiResult(s: Smi) {
return s;
} label Float64Result(f: float64) {
return Convert<Number>(Float64Ceil(f));
}
}
// ES6 #sec-math.floor
extern macro Float64Floor(float64): float64;
transitioning javascript builtin
MathFloor(js-implicit context: NativeContext)(x: JSAny): Number {
try {
ReduceToSmiOrFloat64(x) otherwise SmiResult, Float64Result;
} label SmiResult(s: Smi) {
return s;
} label Float64Result(f: float64) {
return Convert<Number>(Float64Floor(f));
}
}
// ES6 #sec-math.round
extern macro Float64Round(float64): float64;
transitioning javascript builtin
MathRound(js-implicit context: NativeContext)(x: JSAny): Number {
try {
ReduceToSmiOrFloat64(x) otherwise SmiResult, Float64Result;
} label SmiResult(s: Smi) {
return s;
} label Float64Result(f: float64) {
return Convert<Number>(Float64Round(f));
}
}
// ES6 #sec-math.trunc
extern macro Float64Trunc(float64): float64;
transitioning javascript builtin
MathTrunc(js-implicit context: NativeContext)(x: JSAny): Number {
try {
ReduceToSmiOrFloat64(x) otherwise SmiResult, Float64Result;
} label SmiResult(s: Smi) {
return s;
} label Float64Result(f: float64) {
return Convert<Number>(Float64Trunc(f));
}
}
// ES6 #sec-math.pow
extern macro Float64Pow(float64, float64): float64;
extern macro TruncateTaggedToFloat64(implicit context: Context)(JSAny): float64;
@export
macro MathPowImpl(implicit context: Context)(base: JSAny, exponent: JSAny):
Number {
const baseValue: float64 = TruncateTaggedToFloat64(base);
const exponentValue: float64 = TruncateTaggedToFloat64(exponent);
const result: float64 = Float64Pow(baseValue, exponentValue);
return Convert<Number>(result);
}
transitioning javascript builtin
MathPow(js-implicit context: NativeContext)(
base: JSAny, exponent: JSAny): Number {
return MathPowImpl(base, exponent);
}
// ES6 #sec-math.max
extern macro Float64Max(float64, float64): float64;
transitioning javascript builtin
MathMax(js-implicit context: NativeContext)(...arguments): Number {
let result: float64 = MINUS_V8_INFINITY;
const argCount = arguments.length;
for (let i: intptr = 0; i < argCount; i++) {
const doubleValue = TruncateTaggedToFloat64(arguments[i]);
result = Float64Max(result, doubleValue);
}
return Convert<Number>(result);
}
// ES6 #sec-math.min
extern macro Float64Min(float64, float64): float64;
transitioning javascript builtin
MathMin(js-implicit context: NativeContext)(...arguments): Number {
let result: float64 = V8_INFINITY;
const argCount = arguments.length;
for (let i: intptr = 0; i < argCount; i++) {
const doubleValue = TruncateTaggedToFloat64(arguments[i]);
result = Float64Min(result, doubleValue);
}
return Convert<Number>(result);
}
// ES6 #sec-math.acos
extern macro Float64Acos(float64): float64;
transitioning javascript builtin
MathAcos(js-implicit context: NativeContext)(x: JSAny): Number {
const value = Convert<float64>(ToNumber_Inline(x));
return Convert<Number>(Float64Acos(value));
}
// ES6 #sec-math.acosh
extern macro Float64Acosh(float64): float64;
transitioning javascript builtin
MathAcosh(js-implicit context: NativeContext)(x: JSAny): Number {
const value = Convert<float64>(ToNumber_Inline(x));
return Convert<Number>(Float64Acosh(value));
}
// ES6 #sec-math.asin
extern macro Float64Asin(float64): float64;
transitioning javascript builtin
MathAsin(js-implicit context: NativeContext)(x: JSAny): Number {
const value = Convert<float64>(ToNumber_Inline(x));
return Convert<Number>(Float64Asin(value));
}
// ES6 #sec-math.asinh
extern macro Float64Asinh(float64): float64;
transitioning javascript builtin
MathAsinh(js-implicit context: NativeContext)(x: JSAny): Number {
const value = Convert<float64>(ToNumber_Inline(x));
return Convert<Number>(Float64Asinh(value));
}
// ES6 #sec-math.atan
extern macro Float64Atan(float64): float64;
transitioning javascript builtin
MathAtan(js-implicit context: NativeContext)(x: JSAny): Number {
const value = Convert<float64>(ToNumber_Inline(x));
return Convert<Number>(Float64Atan(value));
}
// ES6 #sec-math.atan2
extern macro Float64Atan2(float64, float64): float64;
transitioning javascript builtin
MathAtan2(js-implicit context: NativeContext)(y: JSAny, x: JSAny): Number {
const yValue = Convert<float64>(ToNumber_Inline(y));
const xValue = Convert<float64>(ToNumber_Inline(x));
return Convert<Number>(Float64Atan2(yValue, xValue));
}
// ES6 #sec-math.atanh
extern macro Float64Atanh(float64): float64;
transitioning javascript builtin
MathAtanh(js-implicit context: NativeContext)(x: JSAny): Number {
const value = Convert<float64>(ToNumber_Inline(x));
return Convert<Number>(Float64Atanh(value));
}
// ES6 #sec-math.cbrt
extern macro Float64Cbrt(float64): float64;
transitioning javascript builtin
MathCbrt(js-implicit context: NativeContext)(x: JSAny): Number {
const value = Convert<float64>(ToNumber_Inline(x));
return Convert<Number>(Float64Cbrt(value));
}
// ES6 #sec-math.clz32
extern macro Word32Clz(int32): int32;
transitioning javascript builtin
MathClz32(js-implicit context: NativeContext)(x: JSAny): Number {
const value: int32 = Convert<int32>(ToNumber_Inline(x));
return Convert<Number>(Word32Clz(value));
}
// ES6 #sec-math.cos
extern macro Float64Cos(float64): float64;
transitioning javascript builtin
MathCos(js-implicit context: NativeContext)(x: JSAny): Number {
const value = Convert<float64>(ToNumber_Inline(x));
return Convert<Number>(Float64Cos(value));
}
// ES6 #sec-math.cosh
extern macro Float64Cosh(float64): float64;
transitioning javascript builtin
MathCosh(js-implicit context: NativeContext)(x: JSAny): Number {
const value = Convert<float64>(ToNumber_Inline(x));
return Convert<Number>(Float64Cosh(value));
}
// ES6 #sec-math.exp
extern macro Float64Exp(float64): float64;
transitioning javascript builtin
MathExp(js-implicit context: NativeContext)(x: JSAny): Number {
const value = Convert<float64>(ToNumber_Inline(x));
return Convert<Number>(Float64Exp(value));
}
// ES6 #sec-math.expm1
extern macro Float64Expm1(float64): float64;
transitioning javascript builtin
MathExpm1(js-implicit context: NativeContext)(x: JSAny): Number {
const value = Convert<float64>(ToNumber_Inline(x));
return Convert<Number>(Float64Expm1(value));
}
// ES6 #sec-math.fround
transitioning javascript builtin
MathFround(js-implicit context: NativeContext)(x: JSAny): Number {
const x32 = Convert<float32>(ToNumber_Inline(x));
const x64 = Convert<float64>(x32);
return Convert<Number>(x64);
}
// ES6 #sec-math.imul
transitioning javascript builtin
MathImul(js-implicit context: NativeContext)(x: JSAny, y: JSAny): Number {
const x = Convert<int32>(ToNumber_Inline(x));
const y = Convert<int32>(ToNumber_Inline(y));
return Convert<Number>(x * y);
}
// ES6 #sec-math.log
extern macro Float64Log(float64): float64;
transitioning javascript builtin
MathLog(js-implicit context: NativeContext)(x: JSAny): Number {
const value = Convert<float64>(ToNumber_Inline(x));
return Convert<Number>(Float64Log(value));
}
// ES6 #sec-math.log1p
extern macro Float64Log1p(float64): float64;
transitioning javascript builtin
MathLog1p(js-implicit context: NativeContext)(x: JSAny): Number {
const value = Convert<float64>(ToNumber_Inline(x));
return Convert<Number>(Float64Log1p(value));
}
// ES6 #sec-math.log10
extern macro Float64Log10(float64): float64;
transitioning javascript builtin
MathLog10(js-implicit context: NativeContext)(x: JSAny): Number {
const value = Convert<float64>(ToNumber_Inline(x));
return Convert<Number>(Float64Log10(value));
}
// ES6 #sec-math.log2
extern macro Float64Log2(float64): float64;
transitioning javascript builtin
MathLog2(js-implicit context: NativeContext)(x: JSAny): Number {
const value = Convert<float64>(ToNumber_Inline(x));
return Convert<Number>(Float64Log2(value));
}
// ES6 #sec-math.sin
extern macro Float64Sin(float64): float64;
transitioning javascript builtin
MathSin(js-implicit context: NativeContext)(x: JSAny): Number {
const value = Convert<float64>(ToNumber_Inline(x));
return Convert<Number>(Float64Sin(value));
}
// ES6 #sec-math.sign
transitioning javascript builtin
MathSign(js-implicit context: NativeContext)(x: JSAny): Number {
const num = ToNumber_Inline(x);
const value = Convert<float64>(num);
if (value < 0) {
return -1;
} else if (value > 0) {
return 1;
} else {
return num;
}
}
// ES6 #sec-math.sinh
extern macro Float64Sinh(float64): float64;
transitioning javascript builtin
MathSinh(js-implicit context: NativeContext)(x: JSAny): Number {
const value = Convert<float64>(ToNumber_Inline(x));
return Convert<Number>(Float64Sinh(value));
}
// ES6 #sec-math.sqrt
extern macro Float64Sqrt(float64): float64;
transitioning javascript builtin
MathSqrt(js-implicit context: NativeContext)(x: JSAny): Number {
const value = Convert<float64>(ToNumber_Inline(x));
return Convert<Number>(Float64Sqrt(value));
}
// ES6 #sec-math.tan
extern macro Float64Tan(float64): float64;
transitioning javascript builtin
MathTan(js-implicit context: NativeContext)(x: JSAny): Number {
const value = Convert<float64>(ToNumber_Inline(x));
return Convert<Number>(Float64Tan(value));
}
// ES6 #sec-math.tanh
extern macro Float64Tanh(float64): float64;
transitioning javascript builtin
MathTanh(js-implicit context: NativeContext)(x: JSAny): Number {
const value = Convert<float64>(ToNumber_Inline(x));
return Convert<Number>(Float64Tanh(value));
}
// ES6 #sec-math.hypot
transitioning javascript builtin
MathHypot(
js-implicit context: NativeContext, receiver: JSAny)(...arguments): Number {
const length = arguments.length;
if (length == 0) {
return 0;
}
const absValues = AllocateZeroedFixedDoubleArray(length);
let oneArgIsNaN: bool = false;
let max: float64 = 0;
for (let i: intptr = 0; i < length; ++i) {
const value = Convert<float64>(ToNumber_Inline(arguments[i]));
if (Float64IsNaN(value)) {
oneArgIsNaN = true;
} else {
const absValue = Float64Abs(value);
absValues.floats[i] = Convert<float64_or_hole>(absValue);
if (absValue > max) {
max = absValue;
}
}
}
if (max == V8_INFINITY) {
return V8_INFINITY;
} else if (oneArgIsNaN) {
return kNaN;
} else if (max == 0) {
return 0;
}
assert(max > 0);
// Kahan summation to avoid rounding errors.
// Normalize the numbers to the largest one to avoid overflow.
let sum: float64 = 0;
let compensation: float64 = 0;
for (let i: intptr = 0; i < length; ++i) {
const n = absValues.floats[i].ValueUnsafeAssumeNotHole() / max;
const summand = n * n - compensation;
const preliminary = sum + summand;
compensation = (preliminary - sum) - summand;
sum = preliminary;
}
return Convert<Number>(Float64Sqrt(sum) * max);
}
// ES6 #sec-math.random
extern macro RefillMathRandom(NativeContext): Smi;
transitioning javascript builtin
MathRandom(js-implicit context: NativeContext, receiver: JSAny)(): Number {
let smiIndex: Smi = *NativeContextSlot(ContextSlot::MATH_RANDOM_INDEX_INDEX);
if (smiIndex == 0) {
// refill math random.
smiIndex = RefillMathRandom(context);
}
const newSmiIndex: Smi = smiIndex - 1;
*NativeContextSlot(ContextSlot::MATH_RANDOM_INDEX_INDEX) = newSmiIndex;
const array: FixedDoubleArray =
*NativeContextSlot(ContextSlot::MATH_RANDOM_CACHE_INDEX);
const random: float64 =
array.floats[Convert<intptr>(newSmiIndex)].ValueUnsafeAssumeNotHole();
return AllocateHeapNumberWithValue(random);
}
}