• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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