Coverage Report

Created: 2025-06-24 06:43

/src/hermes/lib/VM/JSLib/Math.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) Meta Platforms, Inc. and affiliates.
3
 *
4
 * This source code is licensed under the MIT license found in the
5
 * LICENSE file in the root directory of this source tree.
6
 */
7
8
//===----------------------------------------------------------------------===//
9
/// \file
10
/// ES5.1 15.8 Populate the Math object.
11
//===----------------------------------------------------------------------===//
12
13
#include "JSLibInternal.h"
14
15
#include "hermes/VM/JSLib/JSLibStorage.h"
16
#include "hermes/VM/Operations.h"
17
#include "hermes/VM/SingleObject.h"
18
#include "hermes/VM/StringPrimitive.h"
19
20
#ifndef _USE_MATH_DEFINES
21
#define _USE_MATH_DEFINES
22
#endif
23
#include <float.h>
24
#include <math.h>
25
#include <random>
26
#include "hermes/Support/Math.h"
27
#include "hermes/Support/OSCompat.h"
28
29
#include "llvh/Support/MathExtras.h"
30
#pragma GCC diagnostic push
31
32
#ifdef HERMES_COMPILER_SUPPORTS_WSHORTEN_64_TO_32
33
#pragma GCC diagnostic ignored "-Wshorten-64-to-32"
34
#endif
35
namespace hermes {
36
namespace vm {
37
38
/// @name Math
39
/// @{
40
41
/// @}
42
43
//===----------------------------------------------------------------------===//
44
/// Math.
45
// Implementation of Math.round(), following ES 5.1 15.8.2.15
46
// This cannot be a simple call to std::round() because std::round() rounds
47
// halfways away from zero, while Math.round must round towards positive
48
// infinity.
49
// The essential algorithm is floor(x + 0.5). However this has three
50
// complications:
51
//  1. The range [-.5, -0] must round to -0, not +0
52
//  2. The largest value less than 0.5, when added to 0.5, becomes 1.0
53
//  (precision loss), causing us to round to 1 and not 0.
54
//  3. Above a certain threshold (shown below), x + 0.5 is the same as x + 1.0
55
//  (precision loss), causing us to round too high.
56
// We handle this by checking explicitly for the problematic ranges.
57
0
static double roundHalfwaysTowardsInfinity(double x) {
58
  // The first integer where all larger values are also integral
59
  // The -1 is to account for the implicit (hidden) bit in the mantissa
60
0
  static constexpr double integer_threshold = 1LLU << (DBL_MANT_DIG - 1);
61
0
  double absf = std::fabs(x);
62
0
  if (absf >= integer_threshold) {
63
    // x is necessarily already integral.
64
0
    return x;
65
0
  } else if (absf < 0.5) {
66
    // x may have too much precision to add 0.5. Just round to +/- 0.
67
0
    return std::copysign(0, x);
68
0
  } else {
69
    // Here we can apply the normal rounding algorithm, but we need to be
70
    // careful about -0.5, which must round to -0.
71
0
    return std::copysign(std::floor(x + 0.5), x);
72
0
  }
73
0
}
74
75
/// The Math object has functions like sin, cos, exp, etc. Most take one
76
/// argument, a few take two arguments, min() and max() may take any number
77
/// of arguments, and random() takes none. Use context as a index to switch to
78
/// the corresponding c function.
79
enum class MathKind {
80
#define MATHFUNC_1ARG(name, func) name,
81
#include "MathStdFunctions.def"
82
#undef MATHFUNC_1ARG
83
  Num1ArgKinds,
84
#define MATHFUNC_2ARG(name, func) name,
85
#include "MathStdFunctions.def"
86
#undef MATHFUNC_2ARG
87
  Num2ArgKinds
88
};
89
// Implementation of 1-arg Math functions like sin or exp
90
// Interprets the ctx pointer as an enum to invoke the
91
// corresponding function with the first argument
92
93
CallResult<HermesValue>
94
0
runContextFunc1Arg(void *ctx, Runtime &runtime, NativeArgs args) {
95
0
  typedef double (*Math1ArgFuncPtr)(double);
96
0
  static Math1ArgFuncPtr math1ArgFuncs[] = {
97
0
#define MATHFUNC_1ARG(name, func) func,
98
0
#include "MathStdFunctions.def"
99
0
#undef MATHFUNC_1ARG
100
0
  };
101
0
  assert(
102
0
      (uint64_t)ctx < (uint64_t)MathKind::Num1ArgKinds &&
103
0
      "runContextFunc1Arg with wrong kind");
104
0
  Math1ArgFuncPtr func = math1ArgFuncs[(uint64_t)ctx];
105
0
  auto res = toNumber_RJS(runtime, args.getArgHandle(0));
106
0
  if (LLVM_UNLIKELY(res == ExecutionStatus::EXCEPTION)) {
107
0
    return ExecutionStatus::EXCEPTION;
108
0
  }
109
0
  double arg = res->getNumber();
110
0
  return HermesValue::encodeUntrustedNumberValue(func(arg));
111
0
}
112
113
// Implementation of 2-arg Math functions like pow and atan2
114
// Interprets the ctx pointer as an enum and invoke corresponding
115
// function with the first two arguments
116
CallResult<HermesValue>
117
0
runContextFunc2Arg(void *ctx, Runtime &runtime, NativeArgs args) {
118
0
  typedef double (*Math2ArgFuncPtr)(double, double);
119
0
  static Math2ArgFuncPtr math2ArgFuncs[] = {
120
0
#define MATHFUNC_2ARG(name, func) func,
121
0
#include "MathStdFunctions.def"
122
0
#undef MATHFUNC_2ARG
123
0
  };
124
0
  assert(
125
0
      (uint64_t)ctx > (uint64_t)MathKind::Num1ArgKinds &&
126
0
      (uint64_t)ctx < (uint64_t)MathKind::Num2ArgKinds &&
127
0
      "runContextFunc1Arg with wrong kind");
128
0
  Math2ArgFuncPtr func =
129
0
      math2ArgFuncs[(uint64_t)ctx - (uint64_t)MathKind::Num1ArgKinds - 1];
130
0
  auto res = toNumber_RJS(runtime, args.getArgHandle(0));
131
0
  if (LLVM_UNLIKELY(res == ExecutionStatus::EXCEPTION)) {
132
0
    return ExecutionStatus::EXCEPTION;
133
0
  }
134
0
  double arg0 = res->getNumber();
135
136
0
  res = toNumber_RJS(runtime, args.getArgHandle(1));
137
0
  if (LLVM_UNLIKELY(res == ExecutionStatus::EXCEPTION)) {
138
0
    return ExecutionStatus::EXCEPTION;
139
0
  }
140
0
  double arg1 = res->getNumber();
141
142
0
  return HermesValue::encodeUntrustedNumberValue(func(arg0, arg1));
143
0
}
144
145
// ES5.1 15.8.2.11
146
0
CallResult<HermesValue> mathMax(void *, Runtime &runtime, NativeArgs args) {
147
0
  double result = -std::numeric_limits<double>::infinity();
148
0
  GCScopeMarkerRAII marker{runtime};
149
0
  for (const Handle<> sarg : args.handles()) {
150
0
    marker.flush();
151
0
    auto res = toNumber_RJS(runtime, sarg);
152
0
    if (LLVM_UNLIKELY(res == ExecutionStatus::EXCEPTION)) {
153
0
      return ExecutionStatus::EXCEPTION;
154
0
    }
155
0
    double arg = res->getNumber();
156
0
    if (std::isnan(result)) {
157
0
      continue;
158
0
    } else if (std::isnan(arg)) {
159
0
      result = std::numeric_limits<double>::quiet_NaN();
160
0
    } else if (arg > result || std::signbit(arg) < std::signbit(result)) {
161
      // signbit(arg) < signbit(result) => arg is at least +0, result at most -0
162
0
      result = arg;
163
0
    }
164
0
  }
165
0
  return HermesValue::encodeUntrustedNumberValue(result);
166
0
}
167
168
// ES5.1 15.8.2.12
169
0
CallResult<HermesValue> mathMin(void *, Runtime &runtime, NativeArgs args) {
170
0
  double result = std::numeric_limits<double>::infinity();
171
0
  GCScopeMarkerRAII marker{runtime};
172
0
  for (const Handle<> sarg : args.handles()) {
173
0
    marker.flush();
174
0
    auto res = toNumber_RJS(runtime, sarg);
175
0
    if (LLVM_UNLIKELY(res == ExecutionStatus::EXCEPTION)) {
176
0
      return ExecutionStatus::EXCEPTION;
177
0
    }
178
0
    double arg = res->getNumber();
179
0
    if (std::isnan(result)) {
180
0
      continue;
181
0
    } else if (std::isnan(arg)) {
182
0
      result = std::numeric_limits<double>::quiet_NaN();
183
0
    } else if (arg < result || std::signbit(arg) > std::signbit(result)) {
184
      // signbit(arg) > signbit(result) => arg is at most -0, result at least +0
185
0
      result = arg;
186
0
    }
187
0
  }
188
0
  return HermesValue::encodeUntrustedNumberValue(result);
189
0
}
190
191
// ES9.0 20.2.2.26
192
0
CallResult<HermesValue> mathPow(void *, Runtime &runtime, NativeArgs args) {
193
0
  auto res = toNumber_RJS(runtime, args.getArgHandle(0));
194
0
  if (LLVM_UNLIKELY(res == ExecutionStatus::EXCEPTION)) {
195
0
    return ExecutionStatus::EXCEPTION;
196
0
  }
197
0
  const double x = res->getNumber();
198
199
0
  res = toNumber_RJS(runtime, args.getArgHandle(1));
200
0
  if (LLVM_UNLIKELY(res == ExecutionStatus::EXCEPTION)) {
201
0
    return ExecutionStatus::EXCEPTION;
202
0
  }
203
0
  const double y = res->getNumber();
204
205
0
  return HermesValue::encodeUntrustedNumberValue(expOp(x, y));
206
0
}
207
208
// ES5.1 15.8.2.14
209
// Returns a Hermes-encoded pseudo-random number uniformly chosen from [0, 1)
210
0
CallResult<HermesValue> mathRandom(void *, Runtime &runtime, NativeArgs) {
211
0
  JSLibStorage *storage = runtime.getJSLibStorage();
212
0
  if (!storage->randomEngineSeeded_) {
213
0
    std::random_device randDevice;
214
215
0
    auto randValue = randDevice();
216
0
    static_assert(
217
0
        sizeof(randValue) == 4, "expecting 32 bits from std::random_device()");
218
219
    // Create a 64-bit seed using two 32-bit random numbers.
220
0
    uint64_t seed =
221
0
        (uint64_t(randValue) << (8 * sizeof(randValue))) | randDevice();
222
0
    static_assert(
223
0
        sizeof(decltype(storage->randomEngine_)::result_type) >= 8,
224
0
        "expecting at least 64-bit result_type for PRNG");
225
226
0
    storage->randomEngine_.seed(seed);
227
0
    storage->randomEngineSeeded_ = true;
228
0
  }
229
0
  std::uniform_real_distribution<> dist(0.0, 1.0);
230
0
  return HermesValue::encodeUntrustedNumberValue(dist(storage->randomEngine_));
231
0
}
232
233
CallResult<HermesValue> mathFround(void *, Runtime &runtime, NativeArgs args)
234
    LLVM_NO_SANITIZE("float-cast-overflow");
235
236
0
CallResult<HermesValue> mathFround(void *, Runtime &runtime, NativeArgs args) {
237
0
  auto res = toNumber_RJS(runtime, args.getArgHandle(0));
238
0
  if (LLVM_UNLIKELY(res == ExecutionStatus::EXCEPTION)) {
239
0
    return ExecutionStatus::EXCEPTION;
240
0
  }
241
0
  double x = res->getNumber();
242
243
  // Make the double x into a 32-bit float,
244
  // and then recast it back to a 64-bit float to return it.
245
  // This is UB for values outside of the range of a float, but this works on
246
  // our current compilers.
247
  // TODO(T43892577): Find an alternative that doesn't use UB (or validate that
248
  // the UB is ok).
249
0
  return HermesValue::encodeUntrustedNumberValue(
250
0
      static_cast<double>(static_cast<float>(x)));
251
0
}
252
253
// ES2022 21.3.2.18
254
0
CallResult<HermesValue> mathHypot(void *, Runtime &runtime, NativeArgs args) {
255
0
  GCScope gcScope{runtime};
256
  // 1. Let coerced be a new empty List.
257
0
  llvh::SmallVector<double, 4> coerced{};
258
0
  coerced.reserve(args.getArgCount());
259
260
  // Store the max abs(arg), since every argument will be squared anyway.
261
  // We scale down every argument by max while doing addition and sqrt,
262
  // and then multiply by max at the end.
263
0
  double max = 0;
264
265
0
  bool hasNaN = false, hasInf = false;
266
0
  auto marker = gcScope.createMarker();
267
  // 2. For each element arg of args, do
268
0
  for (const Handle<> arg : args.handles()) {
269
0
    gcScope.flushToMarker(marker);
270
    // a. Let n be ? ToNumber(arg).
271
0
    auto res = toNumber_RJS(runtime, arg);
272
0
    if (LLVM_UNLIKELY(res == ExecutionStatus::EXCEPTION)) {
273
0
      return ExecutionStatus::EXCEPTION;
274
0
    }
275
0
    double value = res->getNumber();
276
0
    hasInf = std::isinf(value) || hasInf;
277
0
    hasNaN = std::isnan(value) || hasNaN;
278
    // b. Append n to coerced.
279
0
    coerced.push_back(value);
280
0
    max = std::max(std::fabs(value), max);
281
0
  }
282
  // 3. For each element number of coerced, do
283
  //   a. If number is +∞𝔽 or number is -∞𝔽, return +∞𝔽.
284
0
  if (hasInf)
285
0
    return HermesValue::encodeUntrustedNumberValue(
286
0
        std::numeric_limits<double>::infinity());
287
  // 5. For each element number of coerced, do
288
  //   a. If number is NaN, return NaN.
289
0
  if (hasNaN)
290
0
    return HermesValue::encodeNaNValue();
291
292
0
  assert(!(max < 0) && "max must not be negative (max(abs(value))");
293
  // 6. If onlyZero is true, return +0𝔽.
294
0
  if (max == 0) {
295
0
    return HermesValue::encodeUntrustedNumberValue(+0);
296
0
  }
297
298
  // 7. Return an implementation-approximated Number value representing the
299
  // square root of the sum of squares of the mathematical values of the
300
  // elements of coerced.
301
302
  // We use the Kahan summation algorithm, since we are supposed to
303
  // "take care to avoid the loss of precision from overflows and underflows".
304
  // We add (value / max)**2 each iteration through the loop,
305
  // so that multiplying by max following the sqrt will negate
306
  // its effects. This normalizes the values to allow more accurate summation.
307
0
  double sum = 0;
308
0
  double c = 0;
309
0
  for (const double value : coerced) {
310
0
    double addend = (value / max) * (value / max);
311
    // Perform Kahan summation and put the result and compensation in sum and c.
312
0
    double y = addend - c;
313
0
    double t = sum + y;
314
0
    c = (t - sum) - y;
315
0
    sum = t;
316
0
  }
317
0
  double result = std::sqrt(sum) * max;
318
319
0
  return HermesValue::encodeUntrustedNumberValue(result);
320
0
}
321
322
// ES6.0 20.2.2.19
323
// Integer multiplication.
324
0
CallResult<HermesValue> mathImul(void *, Runtime &runtime, NativeArgs args) {
325
0
  auto res = toUInt32_RJS(runtime, args.getArgHandle(0));
326
0
  if (LLVM_UNLIKELY(res == ExecutionStatus::EXCEPTION)) {
327
0
    return ExecutionStatus::EXCEPTION;
328
0
  }
329
0
  uint32_t a = res->getNumber();
330
0
  res = toUInt32_RJS(runtime, args.getArgHandle(1));
331
0
  if (LLVM_UNLIKELY(res == ExecutionStatus::EXCEPTION)) {
332
0
    return ExecutionStatus::EXCEPTION;
333
0
  }
334
0
  uint32_t b = res->getNumber();
335
336
  // Compute a * b mod 2^32.
337
0
  uint32_t product = a * b;
338
339
  // If product >= 2^31, return product - 2^32, else return product.
340
0
  return HermesValue::encodeUntrustedNumberValue(static_cast<int32_t>(product));
341
0
}
342
343
// ES6.0 20.2.2.11
344
// Count leading zeros on the 32-bit number.
345
0
CallResult<HermesValue> mathClz32(void *, Runtime &runtime, NativeArgs args) {
346
0
  auto res = toUInt32_RJS(runtime, args.getArgHandle(0));
347
0
  if (LLVM_UNLIKELY(res == ExecutionStatus::EXCEPTION)) {
348
0
    return ExecutionStatus::EXCEPTION;
349
0
  }
350
0
  uint32_t n = res->getNumberAs<uint32_t>();
351
0
  uint32_t p = llvh::countLeadingZeros(n);
352
0
  return HermesValue::encodeUntrustedNumberValue(p);
353
0
}
354
355
// ES6.0 20.2.2.29
356
// Get the sign of the input.
357
0
CallResult<HermesValue> mathSign(void *, Runtime &runtime, NativeArgs args) {
358
0
  auto res = toNumber_RJS(runtime, args.getArgHandle(0));
359
0
  if (LLVM_UNLIKELY(res == ExecutionStatus::EXCEPTION)) {
360
0
    return ExecutionStatus::EXCEPTION;
361
0
  }
362
0
  double x = res->getNumber();
363
364
0
  if (std::isnan(x)) {
365
0
    return HermesValue::encodeNaNValue();
366
0
  }
367
0
  if (x == 0) {
368
    // Preserve sign bit: return -0 for x == -0 and +0 for x == +0.
369
0
    return HermesValue::encodeUntrustedNumberValue(x);
370
0
  }
371
372
0
  return HermesValue::encodeUntrustedNumberValue(std::signbit(x) ? -1 : +1);
373
0
}
374
375
53
Handle<JSObject> createMathObject(Runtime &runtime) {
376
53
  auto objRes = JSMath::create(
377
53
      runtime, Handle<JSObject>::vmcast(&runtime.objectPrototype));
378
53
  assert(objRes != ExecutionStatus::EXCEPTION && "unable to define Math");
379
53
  auto math = runtime.makeHandle<JSMath>(*objRes);
380
381
53
  DefinePropertyFlags constantDPF =
382
53
      DefinePropertyFlags::getDefaultNewPropertyFlags();
383
53
  constantDPF.enumerable = 0;
384
53
  constantDPF.writable = 0;
385
53
  constantDPF.configurable = 0;
386
387
53
  MutableHandle<> numberHandle{runtime};
388
389
  // ES5.1 15.8.1, Math value properties
390
424
  auto setMathValueProperty = [&](SymbolID name, double value) {
391
424
    numberHandle = HermesValue::encodeUntrustedNumberValue(value);
392
424
    auto result = JSObject::defineOwnProperty(
393
424
        math, runtime, name, constantDPF, numberHandle);
394
424
    assert(
395
424
        result != ExecutionStatus::EXCEPTION &&
396
424
        "defineOwnProperty() failed on a new object");
397
424
    (void)result;
398
424
  };
399
53
  setMathValueProperty(Predefined::getSymbolID(Predefined::E), M_E);
400
53
  setMathValueProperty(Predefined::getSymbolID(Predefined::LN10), M_LN10);
401
53
  setMathValueProperty(Predefined::getSymbolID(Predefined::LN2), M_LN2);
402
53
  setMathValueProperty(Predefined::getSymbolID(Predefined::LOG2E), M_LOG2E);
403
53
  setMathValueProperty(Predefined::getSymbolID(Predefined::LOG10E), M_LOG10E);
404
53
  setMathValueProperty(Predefined::getSymbolID(Predefined::PI), M_PI);
405
53
  setMathValueProperty(Predefined::getSymbolID(Predefined::SQRT1_2), M_SQRT1_2);
406
53
  setMathValueProperty(Predefined::getSymbolID(Predefined::SQRT2), M_SQRT2);
407
408
  // ES5.1 15.8.2, Math function properties
409
53
  auto setMathFunctionProperty1Arg = [&runtime, math](
410
1.32k
                                         SymbolID name, MathKind kind) {
411
1.32k
    defineMethod(runtime, math, name, (void *)kind, runContextFunc1Arg, 1);
412
1.32k
  };
413
414
53
  auto setMathFunctionProperty2Arg = [&runtime, math](
415
53
                                         SymbolID name, MathKind kind) {
416
53
    defineMethod(runtime, math, name, (void *)kind, runContextFunc2Arg, 2);
417
53
  };
418
419
  // We use the C versions of some of these functions from <math.h>
420
  // because on Android, the C++ <cmath> library doesn't have them.
421
53
  setMathFunctionProperty1Arg(
422
53
      Predefined::getSymbolID(Predefined::abs), MathKind::abs);
423
53
  setMathFunctionProperty1Arg(
424
53
      Predefined::getSymbolID(Predefined::acos), MathKind::acos);
425
53
  setMathFunctionProperty1Arg(
426
53
      Predefined::getSymbolID(Predefined::acosh), MathKind::acosh);
427
53
  setMathFunctionProperty1Arg(
428
53
      Predefined::getSymbolID(Predefined::asin), MathKind::asin);
429
53
  setMathFunctionProperty1Arg(
430
53
      Predefined::getSymbolID(Predefined::asinh), MathKind::asinh);
431
53
  setMathFunctionProperty1Arg(
432
53
      Predefined::getSymbolID(Predefined::atan), MathKind::atan);
433
53
  setMathFunctionProperty1Arg(
434
53
      Predefined::getSymbolID(Predefined::atanh), MathKind::atanh);
435
53
  setMathFunctionProperty2Arg(
436
53
      Predefined::getSymbolID(Predefined::atan2), MathKind::atan2);
437
53
  setMathFunctionProperty1Arg(
438
53
      Predefined::getSymbolID(Predefined::cbrt), MathKind::cbrt);
439
53
  setMathFunctionProperty1Arg(
440
53
      Predefined::getSymbolID(Predefined::ceil), MathKind::ceil);
441
53
  defineMethod(
442
53
      runtime,
443
53
      math,
444
53
      Predefined::getSymbolID(Predefined::clz32),
445
53
      nullptr,
446
53
      mathClz32,
447
53
      1);
448
53
  setMathFunctionProperty1Arg(
449
53
      Predefined::getSymbolID(Predefined::cos), MathKind::cos);
450
53
  setMathFunctionProperty1Arg(
451
53
      Predefined::getSymbolID(Predefined::cosh), MathKind::cosh);
452
53
  setMathFunctionProperty1Arg(
453
53
      Predefined::getSymbolID(Predefined::exp), MathKind::exp);
454
53
  setMathFunctionProperty1Arg(
455
53
      Predefined::getSymbolID(Predefined::expm1), MathKind::expm1);
456
53
  setMathFunctionProperty1Arg(
457
53
      Predefined::getSymbolID(Predefined::floor), MathKind::floor);
458
53
  defineMethod(
459
53
      runtime,
460
53
      math,
461
53
      Predefined::getSymbolID(Predefined::fround),
462
53
      nullptr,
463
53
      mathFround,
464
53
      1);
465
53
  defineMethod(
466
53
      runtime,
467
53
      math,
468
53
      Predefined::getSymbolID(Predefined::hypot),
469
53
      nullptr,
470
53
      mathHypot,
471
53
      2);
472
53
  setMathFunctionProperty1Arg(
473
53
      Predefined::getSymbolID(Predefined::log), MathKind::log);
474
53
  setMathFunctionProperty1Arg(
475
53
      Predefined::getSymbolID(Predefined::log10), MathKind::log10);
476
53
  setMathFunctionProperty1Arg(
477
53
      Predefined::getSymbolID(Predefined::log1p), MathKind::log1p);
478
53
  setMathFunctionProperty1Arg(
479
53
      Predefined::getSymbolID(Predefined::log2), MathKind::log2);
480
53
  setMathFunctionProperty1Arg(
481
53
      Predefined::getSymbolID(Predefined::trunc), MathKind::trunc);
482
53
  defineMethod(
483
53
      runtime,
484
53
      math,
485
53
      Predefined::getSymbolID(Predefined::max),
486
53
      nullptr,
487
53
      mathMax,
488
53
      2);
489
53
  defineMethod(
490
53
      runtime,
491
53
      math,
492
53
      Predefined::getSymbolID(Predefined::min),
493
53
      nullptr,
494
53
      mathMin,
495
53
      2);
496
53
  defineMethod(
497
53
      runtime,
498
53
      math,
499
53
      Predefined::getSymbolID(Predefined::imul),
500
53
      nullptr,
501
53
      mathImul,
502
53
      2);
503
53
  defineMethod(
504
53
      runtime,
505
53
      math,
506
53
      Predefined::getSymbolID(Predefined::pow),
507
53
      nullptr,
508
53
      mathPow,
509
53
      2);
510
53
  defineMethod(
511
53
      runtime,
512
53
      math,
513
53
      Predefined::getSymbolID(Predefined::random),
514
53
      nullptr,
515
53
      mathRandom,
516
53
      0);
517
53
  setMathFunctionProperty1Arg(
518
53
      Predefined::getSymbolID(Predefined::round), MathKind::round);
519
53
  defineMethod(
520
53
      runtime,
521
53
      math,
522
53
      Predefined::getSymbolID(Predefined::sign),
523
53
      nullptr,
524
53
      mathSign,
525
53
      1);
526
53
  setMathFunctionProperty1Arg(
527
53
      Predefined::getSymbolID(Predefined::sin), MathKind::sin);
528
53
  setMathFunctionProperty1Arg(
529
53
      Predefined::getSymbolID(Predefined::sinh), MathKind::sinh);
530
53
  setMathFunctionProperty1Arg(
531
53
      Predefined::getSymbolID(Predefined::sqrt), MathKind::sqrt);
532
53
  setMathFunctionProperty1Arg(
533
53
      Predefined::getSymbolID(Predefined::tan), MathKind::tan);
534
53
  setMathFunctionProperty1Arg(
535
53
      Predefined::getSymbolID(Predefined::tanh), MathKind::tanh);
536
537
53
  auto dpf = DefinePropertyFlags::getDefaultNewPropertyFlags();
538
53
  dpf.writable = 0;
539
53
  dpf.enumerable = 0;
540
53
  defineProperty(
541
53
      runtime,
542
53
      math,
543
53
      Predefined::getSymbolID(Predefined::SymbolToStringTag),
544
53
      runtime.getPredefinedStringHandle(Predefined::Math),
545
53
      dpf);
546
547
53
  return math;
548
53
}
549
550
} // namespace vm
551
} // namespace hermes