math.tq 14.1 KB
Newer Older
1 2 3 4 5
// 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 {
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32

  extern transitioning builtin
  NonNumberToNumber(implicit context: Context)(HeapObject): Number;

  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 = NonNumberToNumber(a);
        }
      }
    }
    VerifiedUnreachable();
  }

  // ES6 #sec-math.abs
  extern macro IsIntPtrAbsWithOverflowSupported(): constexpr bool;
  extern macro TrySmiSub(Smi, Smi): Smi labels Overflow;
33
  extern macro TrySmiAbs(Smi): Smi labels Overflow;
34 35 36 37 38
  extern macro Float64Abs(float64): float64;
  const kSmiMaxValuePlusOne:
      constexpr float64 generates '0.0 - kSmiMinValue';

  transitioning javascript builtin
39
  MathAbs(js-implicit context: NativeContext)(x: JSAny): Number {
40 41 42 43 44 45
    try {
      ReduceToSmiOrFloat64(x) otherwise SmiResult, Float64Result;
    }
    label SmiResult(s: Smi) {
      try {
        if constexpr (IsIntPtrAbsWithOverflowSupported()) {
46
          const result: Smi = TrySmiAbs(s)
47
              otherwise SmiOverflow;
48
          return result;
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
        } 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));
    }
  }

67 68 69
  // ES6 #sec-math.ceil
  extern macro Float64Ceil(float64): float64;
  transitioning javascript builtin
70
  MathCeil(js-implicit context: NativeContext)(x: JSAny): Number {
71 72 73 74 75 76 77 78 79 80 81 82 83 84
    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
85
  MathFloor(js-implicit context: NativeContext)(x: JSAny): Number {
86 87 88 89 90 91 92 93 94 95 96 97 98 99
    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
100
  MathRound(js-implicit context: NativeContext)(x: JSAny): Number {
101 102 103 104 105 106 107 108 109 110 111 112 113 114
    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
115
  MathTrunc(js-implicit context: NativeContext)(x: JSAny): Number {
116 117 118 119 120 121 122 123 124 125 126 127
    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
128
  extern macro Float64Pow(float64, float64): float64;
129 130
  extern macro TruncateTaggedToFloat64(implicit context: Context)(JSAny):
      float64;
131 132 133 134

  @export
  macro MathPowImpl(implicit context: Context)(base: JSAny, exponent: JSAny):
      Number {
135 136 137 138 139 140
    const baseValue: float64 = TruncateTaggedToFloat64(base);
    const exponentValue: float64 = TruncateTaggedToFloat64(exponent);
    const result: float64 = Float64Pow(baseValue, exponentValue);
    return Convert<Number>(result);
  }

141
  transitioning javascript builtin
142 143
  MathPow(js-implicit context: NativeContext)(base: JSAny, exponent: JSAny):
      Number {
144 145 146
    return MathPowImpl(base, exponent);
  }

147 148 149
  // ES6 #sec-math.max
  extern macro Float64Max(float64, float64): float64;
  transitioning javascript builtin
150
  MathMax(js-implicit context: NativeContext)(...arguments): Number {
151 152 153 154 155 156 157 158 159 160 161 162
    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
163
  MathMin(js-implicit context: NativeContext)(...arguments): Number {
164 165 166 167 168 169 170 171 172
    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);
  }

173 174 175 176
  // ES6 #sec-math.acos
  extern macro Float64Acos(float64): float64;

  transitioning javascript builtin
177
  MathAcos(js-implicit context: NativeContext)(x: JSAny): Number {
178
    const value = Convert<float64>(ToNumber_Inline(x));
179 180 181 182 183 184 185
    return Convert<Number>(Float64Acos(value));
  }

  // ES6 #sec-math.acosh
  extern macro Float64Acosh(float64): float64;

  transitioning javascript builtin
186
  MathAcosh(js-implicit context: NativeContext)(x: JSAny): Number {
187
    const value = Convert<float64>(ToNumber_Inline(x));
188 189 190 191 192 193 194
    return Convert<Number>(Float64Acosh(value));
  }

  // ES6 #sec-math.asin
  extern macro Float64Asin(float64): float64;

  transitioning javascript builtin
195
  MathAsin(js-implicit context: NativeContext)(x: JSAny): Number {
196
    const value = Convert<float64>(ToNumber_Inline(x));
197 198 199 200 201 202 203
    return Convert<Number>(Float64Asin(value));
  }

  // ES6 #sec-math.asinh
  extern macro Float64Asinh(float64): float64;

  transitioning javascript builtin
204
  MathAsinh(js-implicit context: NativeContext)(x: JSAny): Number {
205
    const value = Convert<float64>(ToNumber_Inline(x));
206 207 208 209 210 211 212
    return Convert<Number>(Float64Asinh(value));
  }

  // ES6 #sec-math.atan
  extern macro Float64Atan(float64): float64;

  transitioning javascript builtin
213
  MathAtan(js-implicit context: NativeContext)(x: JSAny): Number {
214
    const value = Convert<float64>(ToNumber_Inline(x));
215 216 217 218 219 220 221
    return Convert<Number>(Float64Atan(value));
  }

  // ES6 #sec-math.atan2
  extern macro Float64Atan2(float64, float64): float64;

  transitioning javascript builtin
222
  MathAtan2(js-implicit context: NativeContext)(y: JSAny, x: JSAny): Number {
223 224
    const yValue = Convert<float64>(ToNumber_Inline(y));
    const xValue = Convert<float64>(ToNumber_Inline(x));
225 226 227 228 229 230 231
    return Convert<Number>(Float64Atan2(yValue, xValue));
  }

  // ES6 #sec-math.atanh
  extern macro Float64Atanh(float64): float64;

  transitioning javascript builtin
232
  MathAtanh(js-implicit context: NativeContext)(x: JSAny): Number {
233
    const value = Convert<float64>(ToNumber_Inline(x));
234 235 236 237 238 239 240
    return Convert<Number>(Float64Atanh(value));
  }

  // ES6 #sec-math.cbrt
  extern macro Float64Cbrt(float64): float64;

  transitioning javascript builtin
241
  MathCbrt(js-implicit context: NativeContext)(x: JSAny): Number {
242
    const value = Convert<float64>(ToNumber_Inline(x));
243 244 245
    return Convert<Number>(Float64Cbrt(value));
  }

246 247 248 249
  // ES6 #sec-math.clz32
  extern macro Word32Clz(int32): int32;

  transitioning javascript builtin
250
  MathClz32(js-implicit context: NativeContext)(x: JSAny): Number {
251
    const value: int32 = Convert<int32>(ToNumber_Inline(x));
252 253 254
    return Convert<Number>(Word32Clz(value));
  }

255 256 257 258
  // ES6 #sec-math.cos
  extern macro Float64Cos(float64): float64;

  transitioning javascript builtin
259
  MathCos(js-implicit context: NativeContext)(x: JSAny): Number {
260
    const value = Convert<float64>(ToNumber_Inline(x));
261 262 263 264 265 266 267
    return Convert<Number>(Float64Cos(value));
  }

  // ES6 #sec-math.cosh
  extern macro Float64Cosh(float64): float64;

  transitioning javascript builtin
268
  MathCosh(js-implicit context: NativeContext)(x: JSAny): Number {
269
    const value = Convert<float64>(ToNumber_Inline(x));
270 271 272 273 274 275 276
    return Convert<Number>(Float64Cosh(value));
  }

  // ES6 #sec-math.exp
  extern macro Float64Exp(float64): float64;

  transitioning javascript builtin
277
  MathExp(js-implicit context: NativeContext)(x: JSAny): Number {
278
    const value = Convert<float64>(ToNumber_Inline(x));
279 280 281 282 283 284 285
    return Convert<Number>(Float64Exp(value));
  }

  // ES6 #sec-math.expm1
  extern macro Float64Expm1(float64): float64;

  transitioning javascript builtin
286
  MathExpm1(js-implicit context: NativeContext)(x: JSAny): Number {
287
    const value = Convert<float64>(ToNumber_Inline(x));
288 289 290 291 292
    return Convert<Number>(Float64Expm1(value));
  }

  // ES6 #sec-math.fround
  transitioning javascript builtin
293
  MathFround(js-implicit context: NativeContext)(x: JSAny): Number {
294
    const x32 = Convert<float32>(ToNumber_Inline(x));
295 296 297 298
    const x64 = Convert<float64>(x32);
    return Convert<Number>(x64);
  }

299 300
  // ES6 #sec-math.imul
  transitioning javascript builtin
301
  MathImul(js-implicit context: NativeContext)(x: JSAny, y: JSAny): Number {
302 303 304 305 306
    const x = Convert<int32>(ToNumber_Inline(x));
    const y = Convert<int32>(ToNumber_Inline(y));
    return Convert<Number>(x * y);
  }

307 308 309 310
  // ES6 #sec-math.log
  extern macro Float64Log(float64): float64;

  transitioning javascript builtin
311
  MathLog(js-implicit context: NativeContext)(x: JSAny): Number {
312
    const value = Convert<float64>(ToNumber_Inline(x));
313 314 315 316 317 318 319
    return Convert<Number>(Float64Log(value));
  }

  // ES6 #sec-math.log1p
  extern macro Float64Log1p(float64): float64;

  transitioning javascript builtin
320
  MathLog1p(js-implicit context: NativeContext)(x: JSAny): Number {
321
    const value = Convert<float64>(ToNumber_Inline(x));
322 323 324 325 326 327 328
    return Convert<Number>(Float64Log1p(value));
  }

  // ES6 #sec-math.log10
  extern macro Float64Log10(float64): float64;

  transitioning javascript builtin
329
  MathLog10(js-implicit context: NativeContext)(x: JSAny): Number {
330
    const value = Convert<float64>(ToNumber_Inline(x));
331 332 333 334 335 336 337
    return Convert<Number>(Float64Log10(value));
  }

  // ES6 #sec-math.log2
  extern macro Float64Log2(float64): float64;

  transitioning javascript builtin
338
  MathLog2(js-implicit context: NativeContext)(x: JSAny): Number {
339
    const value = Convert<float64>(ToNumber_Inline(x));
340 341 342 343 344 345 346
    return Convert<Number>(Float64Log2(value));
  }

  // ES6 #sec-math.sin
  extern macro Float64Sin(float64): float64;

  transitioning javascript builtin
347
  MathSin(js-implicit context: NativeContext)(x: JSAny): Number {
348
    const value = Convert<float64>(ToNumber_Inline(x));
349 350 351
    return Convert<Number>(Float64Sin(value));
  }

352 353
  // ES6 #sec-math.sign
  transitioning javascript builtin
354
  MathSign(js-implicit context: NativeContext)(x: JSAny): Number {
355
    const num = ToNumber_Inline(x);
356 357 358 359 360 361 362 363 364 365 366
    const value = Convert<float64>(num);

    if (value < 0) {
      return -1;
    } else if (value > 0) {
      return 1;
    } else {
      return num;
    }
  }

367 368 369 370
  // ES6 #sec-math.sinh
  extern macro Float64Sinh(float64): float64;

  transitioning javascript builtin
371
  MathSinh(js-implicit context: NativeContext)(x: JSAny): Number {
372
    const value = Convert<float64>(ToNumber_Inline(x));
373 374 375 376 377 378 379
    return Convert<Number>(Float64Sinh(value));
  }

  // ES6 #sec-math.sqrt
  extern macro Float64Sqrt(float64): float64;

  transitioning javascript builtin
380
  MathSqrt(js-implicit context: NativeContext)(x: JSAny): Number {
381
    const value = Convert<float64>(ToNumber_Inline(x));
382 383 384 385 386 387 388
    return Convert<Number>(Float64Sqrt(value));
  }

  // ES6 #sec-math.tan
  extern macro Float64Tan(float64): float64;

  transitioning javascript builtin
389
  MathTan(js-implicit context: NativeContext)(x: JSAny): Number {
390
    const value = Convert<float64>(ToNumber_Inline(x));
391 392 393 394 395 396 397
    return Convert<Number>(Float64Tan(value));
  }

  // ES6 #sec-math.tanh
  extern macro Float64Tanh(float64): float64;

  transitioning javascript builtin
398
  MathTanh(js-implicit context: NativeContext)(x: JSAny): Number {
399
    const value = Convert<float64>(ToNumber_Inline(x));
400 401
    return Convert<Number>(Float64Tanh(value));
  }
402 403 404

  // ES6 #sec-math.hypot
  transitioning javascript builtin
405
  MathHypot(js-implicit context: NativeContext, receiver: JSAny)(...arguments):
406 407 408 409 410 411 412 413 414
      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) {
415
      const value = Convert<float64>(ToNumber_Inline(arguments[i]));
416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447
      if (Float64IsNaN(value)) {
        oneArgIsNaN = true;
      } else {
        const absValue = Float64Abs(value);
        absValues.floats[i] = 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] / max;
      const summand = n * n - compensation;
      const preliminary = sum + summand;
      compensation = (preliminary - sum) - summand;
      sum = preliminary;
    }
    return Convert<Number>(Float64Sqrt(sum) * max);
  }
448 449 450 451 452

  // ES6 #sec-math.random
  extern macro RefillMathRandom(NativeContext): Smi;

  transitioning javascript builtin
453 454
  MathRandom(js-implicit context: NativeContext, receiver: JSAny)(): Number {
    let smiIndex: Smi = Cast<Smi>(context[MATH_RANDOM_INDEX_INDEX])
455 456 457
        otherwise unreachable;
    if (smiIndex == 0) {
      // refill math random.
458
      smiIndex = RefillMathRandom(context);
459 460
    }
    const newSmiIndex: Smi = smiIndex - 1;
461
    context[MATH_RANDOM_INDEX_INDEX] = newSmiIndex;
462 463

    const array: FixedDoubleArray =
464
        Cast<FixedDoubleArray>(context[MATH_RANDOM_CACHE_INDEX])
465 466 467 468
        otherwise unreachable;
    const random: float64 = array.floats[Convert<intptr>(newSmiIndex)];
    return AllocateHeapNumberWithValue(random);
  }
469
}