1// Copyright 2019 the V8 project authors. All rights reserved. Use of this 2// source code is governed by a BSD-style license that can be found in the 3// LICENSE file. 4 5namespace math { 6 7transitioning macro ReduceToSmiOrFloat64(implicit context: Context)(x: JSAny): 8 never 9 labels SmiResult(Smi), Float64Result(float64) { 10 let x1: JSAny = x; 11 while (true) { 12 typeswitch (x1) { 13 case (s: Smi): { 14 goto SmiResult(s); 15 } 16 case (h: HeapNumber): { 17 goto Float64Result(Convert<float64>(h)); 18 } 19 case (a: JSAnyNotNumber): { 20 x1 = conversion::NonNumberToNumber(a); 21 } 22 } 23 } 24 VerifiedUnreachable(); 25} 26 27// ES6 #sec-math.abs 28extern macro IsIntPtrAbsWithOverflowSupported(): constexpr bool; 29extern macro TrySmiAdd(Smi, Smi): Smi labels Overflow; 30extern macro TrySmiSub(Smi, Smi): Smi labels Overflow; 31extern macro TrySmiAbs(Smi): Smi labels Overflow; 32extern macro Float64Abs(float64): float64; 33const kSmiMaxValuePlusOne: 34 constexpr float64 generates '0.0 - kSmiMinValue'; 35 36transitioning javascript builtin 37MathAbs(js-implicit context: NativeContext)(x: JSAny): Number { 38 try { 39 ReduceToSmiOrFloat64(x) otherwise SmiResult, Float64Result; 40 } label SmiResult(s: Smi) { 41 try { 42 if constexpr (IsIntPtrAbsWithOverflowSupported()) { 43 const result: Smi = TrySmiAbs(s) 44 otherwise SmiOverflow; 45 return result; 46 } else { 47 if (0 <= s) { 48 return s; 49 } else { 50 const result: Smi = TrySmiSub(0, s) otherwise SmiOverflow; 51 return result; 52 } 53 } 54 } label SmiOverflow { 55 return NumberConstant(kSmiMaxValuePlusOne); 56 } 57 } label Float64Result(f: float64) { 58 return Convert<Number>(Float64Abs(f)); 59 } 60} 61 62// ES6 #sec-math.ceil 63extern macro Float64Ceil(float64): float64; 64transitioning javascript builtin 65MathCeil(js-implicit context: NativeContext)(x: JSAny): Number { 66 try { 67 ReduceToSmiOrFloat64(x) otherwise SmiResult, Float64Result; 68 } label SmiResult(s: Smi) { 69 return s; 70 } label Float64Result(f: float64) { 71 return Convert<Number>(Float64Ceil(f)); 72 } 73} 74 75// ES6 #sec-math.floor 76extern macro Float64Floor(float64): float64; 77transitioning javascript builtin 78MathFloor(js-implicit context: NativeContext)(x: JSAny): Number { 79 try { 80 ReduceToSmiOrFloat64(x) otherwise SmiResult, Float64Result; 81 } label SmiResult(s: Smi) { 82 return s; 83 } label Float64Result(f: float64) { 84 return Convert<Number>(Float64Floor(f)); 85 } 86} 87 88// ES6 #sec-math.round 89extern macro Float64Round(float64): float64; 90transitioning javascript builtin 91MathRound(js-implicit context: NativeContext)(x: JSAny): Number { 92 try { 93 ReduceToSmiOrFloat64(x) otherwise SmiResult, Float64Result; 94 } label SmiResult(s: Smi) { 95 return s; 96 } label Float64Result(f: float64) { 97 return Convert<Number>(Float64Round(f)); 98 } 99} 100 101// ES6 #sec-math.trunc 102extern macro Float64Trunc(float64): float64; 103transitioning javascript builtin 104MathTrunc(js-implicit context: NativeContext)(x: JSAny): Number { 105 try { 106 ReduceToSmiOrFloat64(x) otherwise SmiResult, Float64Result; 107 } label SmiResult(s: Smi) { 108 return s; 109 } label Float64Result(f: float64) { 110 return Convert<Number>(Float64Trunc(f)); 111 } 112} 113 114// ES6 #sec-math.pow 115extern macro Float64Pow(float64, float64): float64; 116extern macro TruncateTaggedToFloat64(implicit context: Context)(JSAny): float64; 117 118@export 119macro MathPowImpl(implicit context: Context)(base: JSAny, exponent: JSAny): 120 Number { 121 const baseValue: float64 = TruncateTaggedToFloat64(base); 122 const exponentValue: float64 = TruncateTaggedToFloat64(exponent); 123 const result: float64 = Float64Pow(baseValue, exponentValue); 124 return Convert<Number>(result); 125} 126 127transitioning javascript builtin 128MathPow(js-implicit context: NativeContext)( 129 base: JSAny, exponent: JSAny): Number { 130 return MathPowImpl(base, exponent); 131} 132 133// ES6 #sec-math.max 134extern macro Float64Max(float64, float64): float64; 135transitioning javascript builtin 136MathMax(js-implicit context: NativeContext)(...arguments): Number { 137 let result: float64 = MINUS_V8_INFINITY; 138 const argCount = arguments.length; 139 for (let i: intptr = 0; i < argCount; i++) { 140 const doubleValue = TruncateTaggedToFloat64(arguments[i]); 141 result = Float64Max(result, doubleValue); 142 } 143 return Convert<Number>(result); 144} 145 146// ES6 #sec-math.min 147extern macro Float64Min(float64, float64): float64; 148transitioning javascript builtin 149MathMin(js-implicit context: NativeContext)(...arguments): Number { 150 let result: float64 = V8_INFINITY; 151 const argCount = arguments.length; 152 for (let i: intptr = 0; i < argCount; i++) { 153 const doubleValue = TruncateTaggedToFloat64(arguments[i]); 154 result = Float64Min(result, doubleValue); 155 } 156 return Convert<Number>(result); 157} 158 159// ES6 #sec-math.acos 160extern macro Float64Acos(float64): float64; 161 162transitioning javascript builtin 163MathAcos(js-implicit context: NativeContext)(x: JSAny): Number { 164 const value = Convert<float64>(ToNumber_Inline(x)); 165 return Convert<Number>(Float64Acos(value)); 166} 167 168// ES6 #sec-math.acosh 169extern macro Float64Acosh(float64): float64; 170 171transitioning javascript builtin 172MathAcosh(js-implicit context: NativeContext)(x: JSAny): Number { 173 const value = Convert<float64>(ToNumber_Inline(x)); 174 return Convert<Number>(Float64Acosh(value)); 175} 176 177// ES6 #sec-math.asin 178extern macro Float64Asin(float64): float64; 179 180transitioning javascript builtin 181MathAsin(js-implicit context: NativeContext)(x: JSAny): Number { 182 const value = Convert<float64>(ToNumber_Inline(x)); 183 return Convert<Number>(Float64Asin(value)); 184} 185 186// ES6 #sec-math.asinh 187extern macro Float64Asinh(float64): float64; 188 189transitioning javascript builtin 190MathAsinh(js-implicit context: NativeContext)(x: JSAny): Number { 191 const value = Convert<float64>(ToNumber_Inline(x)); 192 return Convert<Number>(Float64Asinh(value)); 193} 194 195// ES6 #sec-math.atan 196extern macro Float64Atan(float64): float64; 197 198transitioning javascript builtin 199MathAtan(js-implicit context: NativeContext)(x: JSAny): Number { 200 const value = Convert<float64>(ToNumber_Inline(x)); 201 return Convert<Number>(Float64Atan(value)); 202} 203 204// ES6 #sec-math.atan2 205extern macro Float64Atan2(float64, float64): float64; 206 207transitioning javascript builtin 208MathAtan2(js-implicit context: NativeContext)(y: JSAny, x: JSAny): Number { 209 const yValue = Convert<float64>(ToNumber_Inline(y)); 210 const xValue = Convert<float64>(ToNumber_Inline(x)); 211 return Convert<Number>(Float64Atan2(yValue, xValue)); 212} 213 214// ES6 #sec-math.atanh 215extern macro Float64Atanh(float64): float64; 216 217transitioning javascript builtin 218MathAtanh(js-implicit context: NativeContext)(x: JSAny): Number { 219 const value = Convert<float64>(ToNumber_Inline(x)); 220 return Convert<Number>(Float64Atanh(value)); 221} 222 223// ES6 #sec-math.cbrt 224extern macro Float64Cbrt(float64): float64; 225 226transitioning javascript builtin 227MathCbrt(js-implicit context: NativeContext)(x: JSAny): Number { 228 const value = Convert<float64>(ToNumber_Inline(x)); 229 return Convert<Number>(Float64Cbrt(value)); 230} 231 232// ES6 #sec-math.clz32 233extern macro Word32Clz(int32): int32; 234 235transitioning javascript builtin 236MathClz32(js-implicit context: NativeContext)(x: JSAny): Number { 237 const value: int32 = Convert<int32>(ToNumber_Inline(x)); 238 return Convert<Number>(Word32Clz(value)); 239} 240 241// ES6 #sec-math.cos 242extern macro Float64Cos(float64): float64; 243 244transitioning javascript builtin 245MathCos(js-implicit context: NativeContext)(x: JSAny): Number { 246 const value = Convert<float64>(ToNumber_Inline(x)); 247 return Convert<Number>(Float64Cos(value)); 248} 249 250// ES6 #sec-math.cosh 251extern macro Float64Cosh(float64): float64; 252 253transitioning javascript builtin 254MathCosh(js-implicit context: NativeContext)(x: JSAny): Number { 255 const value = Convert<float64>(ToNumber_Inline(x)); 256 return Convert<Number>(Float64Cosh(value)); 257} 258 259// ES6 #sec-math.exp 260extern macro Float64Exp(float64): float64; 261 262transitioning javascript builtin 263MathExp(js-implicit context: NativeContext)(x: JSAny): Number { 264 const value = Convert<float64>(ToNumber_Inline(x)); 265 return Convert<Number>(Float64Exp(value)); 266} 267 268// ES6 #sec-math.expm1 269extern macro Float64Expm1(float64): float64; 270 271transitioning javascript builtin 272MathExpm1(js-implicit context: NativeContext)(x: JSAny): Number { 273 const value = Convert<float64>(ToNumber_Inline(x)); 274 return Convert<Number>(Float64Expm1(value)); 275} 276 277// ES6 #sec-math.fround 278transitioning javascript builtin 279MathFround(js-implicit context: NativeContext)(x: JSAny): Number { 280 const x32 = Convert<float32>(ToNumber_Inline(x)); 281 const x64 = Convert<float64>(x32); 282 return Convert<Number>(x64); 283} 284 285// ES6 #sec-math.imul 286transitioning javascript builtin 287MathImul(js-implicit context: NativeContext)(x: JSAny, y: JSAny): Number { 288 const x = Convert<int32>(ToNumber_Inline(x)); 289 const y = Convert<int32>(ToNumber_Inline(y)); 290 return Convert<Number>(x * y); 291} 292 293// ES6 #sec-math.log 294extern macro Float64Log(float64): float64; 295 296transitioning javascript builtin 297MathLog(js-implicit context: NativeContext)(x: JSAny): Number { 298 const value = Convert<float64>(ToNumber_Inline(x)); 299 return Convert<Number>(Float64Log(value)); 300} 301 302// ES6 #sec-math.log1p 303extern macro Float64Log1p(float64): float64; 304 305transitioning javascript builtin 306MathLog1p(js-implicit context: NativeContext)(x: JSAny): Number { 307 const value = Convert<float64>(ToNumber_Inline(x)); 308 return Convert<Number>(Float64Log1p(value)); 309} 310 311// ES6 #sec-math.log10 312extern macro Float64Log10(float64): float64; 313 314transitioning javascript builtin 315MathLog10(js-implicit context: NativeContext)(x: JSAny): Number { 316 const value = Convert<float64>(ToNumber_Inline(x)); 317 return Convert<Number>(Float64Log10(value)); 318} 319 320// ES6 #sec-math.log2 321extern macro Float64Log2(float64): float64; 322 323transitioning javascript builtin 324MathLog2(js-implicit context: NativeContext)(x: JSAny): Number { 325 const value = Convert<float64>(ToNumber_Inline(x)); 326 return Convert<Number>(Float64Log2(value)); 327} 328 329// ES6 #sec-math.sin 330extern macro Float64Sin(float64): float64; 331 332transitioning javascript builtin 333MathSin(js-implicit context: NativeContext)(x: JSAny): Number { 334 const value = Convert<float64>(ToNumber_Inline(x)); 335 return Convert<Number>(Float64Sin(value)); 336} 337 338// ES6 #sec-math.sign 339transitioning javascript builtin 340MathSign(js-implicit context: NativeContext)(x: JSAny): Number { 341 const num = ToNumber_Inline(x); 342 const value = Convert<float64>(num); 343 344 if (value < 0) { 345 return -1; 346 } else if (value > 0) { 347 return 1; 348 } else { 349 return num; 350 } 351} 352 353// ES6 #sec-math.sinh 354extern macro Float64Sinh(float64): float64; 355 356transitioning javascript builtin 357MathSinh(js-implicit context: NativeContext)(x: JSAny): Number { 358 const value = Convert<float64>(ToNumber_Inline(x)); 359 return Convert<Number>(Float64Sinh(value)); 360} 361 362// ES6 #sec-math.sqrt 363extern macro Float64Sqrt(float64): float64; 364 365transitioning javascript builtin 366MathSqrt(js-implicit context: NativeContext)(x: JSAny): Number { 367 const value = Convert<float64>(ToNumber_Inline(x)); 368 return Convert<Number>(Float64Sqrt(value)); 369} 370 371// ES6 #sec-math.tan 372extern macro Float64Tan(float64): float64; 373 374transitioning javascript builtin 375MathTan(js-implicit context: NativeContext)(x: JSAny): Number { 376 const value = Convert<float64>(ToNumber_Inline(x)); 377 return Convert<Number>(Float64Tan(value)); 378} 379 380// ES6 #sec-math.tanh 381extern macro Float64Tanh(float64): float64; 382 383transitioning javascript builtin 384MathTanh(js-implicit context: NativeContext)(x: JSAny): Number { 385 const value = Convert<float64>(ToNumber_Inline(x)); 386 return Convert<Number>(Float64Tanh(value)); 387} 388 389// ES6 #sec-math.hypot 390transitioning javascript builtin 391MathHypot( 392 js-implicit context: NativeContext, receiver: JSAny)(...arguments): Number { 393 const length = arguments.length; 394 if (length == 0) { 395 return 0; 396 } 397 const absValues = AllocateZeroedFixedDoubleArray(length); 398 let oneArgIsNaN: bool = false; 399 let max: float64 = 0; 400 for (let i: intptr = 0; i < length; ++i) { 401 const value = Convert<float64>(ToNumber_Inline(arguments[i])); 402 if (Float64IsNaN(value)) { 403 oneArgIsNaN = true; 404 } else { 405 const absValue = Float64Abs(value); 406 absValues.floats[i] = Convert<float64_or_hole>(absValue); 407 if (absValue > max) { 408 max = absValue; 409 } 410 } 411 } 412 if (max == V8_INFINITY) { 413 return V8_INFINITY; 414 } else if (oneArgIsNaN) { 415 return kNaN; 416 } else if (max == 0) { 417 return 0; 418 } 419 dcheck(max > 0); 420 421 // Kahan summation to avoid rounding errors. 422 // Normalize the numbers to the largest one to avoid overflow. 423 let sum: float64 = 0; 424 let compensation: float64 = 0; 425 for (let i: intptr = 0; i < length; ++i) { 426 const n = absValues.floats[i].ValueUnsafeAssumeNotHole() / max; 427 const summand = n * n - compensation; 428 const preliminary = sum + summand; 429 compensation = (preliminary - sum) - summand; 430 sum = preliminary; 431 } 432 return Convert<Number>(Float64Sqrt(sum) * max); 433} 434 435// ES6 #sec-math.random 436extern macro RefillMathRandom(NativeContext): Smi; 437 438transitioning javascript builtin 439MathRandom(js-implicit context: NativeContext, receiver: JSAny)(): Number { 440 let smiIndex: Smi = *NativeContextSlot(ContextSlot::MATH_RANDOM_INDEX_INDEX); 441 if (smiIndex == 0) { 442 // refill math random. 443 smiIndex = RefillMathRandom(context); 444 } 445 const newSmiIndex: Smi = smiIndex - 1; 446 *NativeContextSlot(ContextSlot::MATH_RANDOM_INDEX_INDEX) = newSmiIndex; 447 448 const array: FixedDoubleArray = 449 *NativeContextSlot(ContextSlot::MATH_RANDOM_CACHE_INDEX); 450 const random: float64 = 451 array.floats[Convert<intptr>(newSmiIndex)].ValueUnsafeAssumeNotHole(); 452 return AllocateHeapNumberWithValue(random); 453} 454} 455