Coverage Report

Created: 2025-12-12 07:27

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hermes/lib/VM/JSLib/BigInt.cpp
Line
Count
Source
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
/// The BigInt constructor (https://tc39.es/ecma262/#sec-bigint-constructor).
11
//===----------------------------------------------------------------------===//
12
#include "JSLibInternal.h"
13
14
#include "hermes/VM/BigIntPrimitive.h"
15
#include "hermes/VM/Operations.h"
16
#include "hermes/VM/PrimitiveBox.h"
17
18
namespace hermes {
19
namespace vm {
20
21
113
Handle<JSObject> createBigIntConstructor(Runtime &runtime) {
22
113
  auto bigintPrototype = Handle<JSObject>::vmcast(&runtime.bigintPrototype);
23
24
113
  auto cons = defineSystemConstructor<JSBigInt>(
25
113
      runtime,
26
113
      Predefined::getSymbolID(Predefined::BigInt),
27
113
      bigintConstructor,
28
113
      bigintPrototype,
29
113
      1,
30
113
      CellKind::JSBigIntKind);
31
32
  // BigInt.prototype.xxx methods.
33
  // https://tc39.es/ecma262/#sec-properties-of-the-bigint-prototype-object
34
113
  void *ctx = nullptr;
35
113
  defineMethod(
36
113
      runtime,
37
113
      bigintPrototype,
38
113
      Predefined::getSymbolID(Predefined::toString),
39
113
      ctx,
40
113
      bigintPrototypeToString,
41
113
      0);
42
113
  defineMethod(
43
113
      runtime,
44
113
      bigintPrototype,
45
113
      Predefined::getSymbolID(Predefined::valueOf),
46
113
      ctx,
47
113
      bigintPrototypeValueOf,
48
113
      0);
49
113
  defineMethod(
50
113
      runtime,
51
113
      bigintPrototype,
52
113
      Predefined::getSymbolID(Predefined::toLocaleString),
53
113
      ctx,
54
113
      bigintPrototypeToLocaleString,
55
113
      1);
56
57
  // BigInt.xxx() methods.
58
  // https://tc39.es/ecma262/#sec-properties-of-the-bigint-constructor
59
113
  defineMethod(
60
113
      runtime,
61
113
      cons,
62
113
      Predefined::getSymbolID(Predefined::asIntN),
63
113
      reinterpret_cast<void *>(&BigIntPrimitive::asIntN),
64
113
      bigintTruncate,
65
113
      2);
66
113
  defineMethod(
67
113
      runtime,
68
113
      cons,
69
113
      Predefined::getSymbolID(Predefined::asUintN),
70
113
      reinterpret_cast<void *>(&BigIntPrimitive::asUintN),
71
113
      bigintTruncate,
72
113
      2);
73
74
  // BigInt.xxx properties
75
113
  auto dpf = DefinePropertyFlags::getDefaultNewPropertyFlags();
76
113
  dpf.writable = 0;
77
113
  dpf.enumerable = 0;
78
113
  defineProperty(
79
113
      runtime,
80
113
      bigintPrototype,
81
113
      Predefined::getSymbolID(Predefined::SymbolToStringTag),
82
113
      runtime.getPredefinedStringHandle(Predefined::BigInt),
83
113
      dpf);
84
85
113
  return cons;
86
113
}
87
88
CallResult<HermesValue>
89
0
bigintConstructor(void *, Runtime &runtime, NativeArgs args) {
90
  // The bigint constructor is not a constructor according to
91
  // https://262.ecma-international.org/#sec-bigint-constructor
92
0
  if (args.isConstructorCall()) {
93
0
    return runtime.raiseTypeError("BigInt is not a constructor");
94
0
  }
95
96
0
  auto hArg0 = runtime.makeHandle(args.getArg(0));
97
0
  auto prim = toPrimitive_RJS(runtime, hArg0, PreferredType::NUMBER);
98
0
  if (LLVM_UNLIKELY(prim == ExecutionStatus::EXCEPTION)) {
99
0
    return ExecutionStatus::EXCEPTION;
100
0
  }
101
102
0
  if (prim->isNumber()) {
103
0
    return numberToBigInt(runtime, prim->getNumber());
104
0
  }
105
106
0
  return toBigInt_RJS(runtime, hArg0);
107
0
}
108
109
CallResult<HermesValue>
110
0
bigintPrototypeToLocaleString(void *ctx, Runtime &runtime, NativeArgs args) {
111
0
  auto bigint = thisBigIntValue(runtime, args.getThisHandle());
112
0
  if (LLVM_UNLIKELY(bigint == ExecutionStatus::EXCEPTION)) {
113
0
    return ExecutionStatus::EXCEPTION;
114
0
  }
115
116
  // Call toString, as JSC does.
117
  // TODO(T120187933): Format string according to locale.
118
0
  auto res = toString_RJS(runtime, runtime.makeHandle(*bigint));
119
0
  if (LLVM_UNLIKELY(res == ExecutionStatus::EXCEPTION)) {
120
0
    return ExecutionStatus::EXCEPTION;
121
0
  }
122
123
0
  return res->getHermesValue();
124
0
}
125
126
CallResult<HermesValue>
127
0
bigintPrototypeToString(void *, Runtime &runtime, NativeArgs args) {
128
  // 1. Let x be ? thisBigIntValue(this value).
129
0
  auto x = thisBigIntValue(runtime, args.getThisHandle());
130
131
0
  if (LLVM_UNLIKELY(x == ExecutionStatus::EXCEPTION)) {
132
0
    return ExecutionStatus::EXCEPTION;
133
0
  }
134
135
0
  Handle<BigIntPrimitive> xHandle = runtime.makeHandle(x->getBigInt());
136
137
  // 2. If radix is undefined, let radixMV be 10.
138
0
  uint32_t radixMV = 10;
139
140
  // 3. Else, let radixMV be ? ToIntegerOrInfinity(radix).
141
0
  auto radixArg = args.getArgHandle(0);
142
0
  if (!radixArg->isUndefined()) {
143
0
    auto r = toIntegerOrInfinity(runtime, radixArg);
144
0
    if (LLVM_UNLIKELY(r == ExecutionStatus::EXCEPTION)) {
145
0
      return ExecutionStatus::EXCEPTION;
146
0
    }
147
0
    assert(r->isNumber());
148
    // 4. If radixMV < 2 or radixMV > 36, throw a RangeError exception.
149
0
    if (r->getNumber() < 2 || r->getNumber() > 36) {
150
0
      return runtime.raiseRangeError(
151
0
          "radix out-of-range in BigInt.prototype.toString");
152
0
    }
153
154
0
    radixMV = r->getNumber();
155
0
  }
156
157
  // 5. If radixMV = 10, return ! ToString(x).
158
  // 6. Return the String representation of x.
159
0
  return BigIntPrimitive::toString(runtime, xHandle, radixMV);
160
0
}
161
162
CallResult<HermesValue>
163
0
bigintPrototypeValueOf(void *, Runtime &runtime, NativeArgs args) {
164
0
  return thisBigIntValue(runtime, args.getThisHandle());
165
0
}
166
167
using TruncateOp =
168
    CallResult<HermesValue> (*)(Runtime &, uint64_t, Handle<BigIntPrimitive>);
169
170
CallResult<HermesValue>
171
0
bigintTruncate(void *ctx, Runtime &runtime, NativeArgs args) {
172
0
  auto bitsRes = toIndex(runtime, args.getArgHandle(0));
173
0
  if (LLVM_UNLIKELY(bitsRes == ExecutionStatus::EXCEPTION)) {
174
0
    return ExecutionStatus::EXCEPTION;
175
0
  }
176
0
  uint64_t bits = bitsRes->getNumberAs<uint64_t>();
177
178
0
  auto bigint = toBigInt_RJS(runtime, args.getArgHandle(1));
179
0
  if (LLVM_UNLIKELY(bigint == ExecutionStatus::EXCEPTION)) {
180
0
    return ExecutionStatus::EXCEPTION;
181
0
  }
182
183
0
  auto op = reinterpret_cast<TruncateOp>(ctx);
184
0
  return (*op)(runtime, bits, runtime.makeHandle(bigint->getBigInt()));
185
0
}
186
187
} // namespace vm
188
} // namespace hermes