/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 |