// 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(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(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(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(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(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(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(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(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(result); } // ES6 #sec-math.acos extern macro Float64Acos(float64): float64; transitioning javascript builtin MathAcos(js-implicit context: NativeContext)(x: JSAny): Number { const value = Convert(ToNumber_Inline(x)); return Convert(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(ToNumber_Inline(x)); return Convert(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(ToNumber_Inline(x)); return Convert(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(ToNumber_Inline(x)); return Convert(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(ToNumber_Inline(x)); return Convert(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(ToNumber_Inline(y)); const xValue = Convert(ToNumber_Inline(x)); return Convert(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(ToNumber_Inline(x)); return Convert(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(ToNumber_Inline(x)); return Convert(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(ToNumber_Inline(x)); return Convert(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(ToNumber_Inline(x)); return Convert(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(ToNumber_Inline(x)); return Convert(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(ToNumber_Inline(x)); return Convert(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(ToNumber_Inline(x)); return Convert(Float64Expm1(value)); } // ES6 #sec-math.fround transitioning javascript builtin MathFround(js-implicit context: NativeContext)(x: JSAny): Number { const x32 = Convert(ToNumber_Inline(x)); const x64 = Convert(x32); return Convert(x64); } // ES6 #sec-math.imul transitioning javascript builtin MathImul(js-implicit context: NativeContext)(x: JSAny, y: JSAny): Number { const x = Convert(ToNumber_Inline(x)); const y = Convert(ToNumber_Inline(y)); return Convert(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(ToNumber_Inline(x)); return Convert(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(ToNumber_Inline(x)); return Convert(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(ToNumber_Inline(x)); return Convert(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(ToNumber_Inline(x)); return Convert(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(ToNumber_Inline(x)); return Convert(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(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(ToNumber_Inline(x)); return Convert(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(ToNumber_Inline(x)); return Convert(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(ToNumber_Inline(x)); return Convert(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(ToNumber_Inline(x)); return Convert(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(ToNumber_Inline(arguments[i])); if (Float64IsNaN(value)) { oneArgIsNaN = true; } else { const absValue = Float64Abs(value); absValues.floats[i] = Convert(absValue); if (absValue > max) { max = absValue; } } } if (max == V8_INFINITY) { return V8_INFINITY; } else if (oneArgIsNaN) { return kNaN; } else if (max == 0) { return 0; } dcheck(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(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(newSmiIndex)].ValueUnsafeAssumeNotHole(); return AllocateHeapNumberWithValue(random); } }