1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "ecmascript/builtins/builtins_number.h"
17
18 #include "ecmascript/base/number_helper.h"
19 #include "ecmascript/ecma_macros.h"
20 #include "ecmascript/global_env.h"
21 #include "ecmascript/js_handle.h"
22 #include "ecmascript/js_hclass.h"
23 #include "ecmascript/js_number_format.h"
24 #include "ecmascript/js_primitive_ref.h"
25 #include "ecmascript/js_tagged_number.h"
26 #include "ecmascript/js_tagged_value-inl.h"
27 #include "ecmascript/mem/c_containers.h"
28 #include "ecmascript/object_factory.h"
29 #include "ecmascript/tagged_hash_table.h"
30
31 namespace panda::ecmascript::builtins {
32 using NumberHelper = base::NumberHelper;
33
NumberConstructor(EcmaRuntimeCallInfo * argv)34 JSTaggedValue BuiltinsNumber::NumberConstructor(EcmaRuntimeCallInfo *argv)
35 {
36 ASSERT(argv);
37 BUILTINS_API_TRACE(argv->GetThread(), Number, Constructor);
38 JSThread *thread = argv->GetThread();
39 [[maybe_unused]] EcmaHandleScope handleScope(thread);
40 JSHandle<JSTaggedValue> newTarget = GetNewTarget(argv);
41 // 1. If no arguments were passed to this function invocation, let n be +0.
42 JSTaggedNumber numberValue(0);
43 if (argv->GetArgsNumber() > 0) {
44 JSHandle<JSTaggedValue> value = GetCallArg(argv, 0);
45 // a. Let prim be ? ToNumeric(value).
46 JSTaggedValue numeric = JSTaggedValue::ToNumeric(thread, value);
47 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
48 JSHandle<JSTaggedValue> numericVal(thread, numeric);
49 // b. If Type(prim) is BigInt, let n be (ℝ(prim)).
50 if (numericVal->IsBigInt()) {
51 JSHandle<BigInt> bigNumericVal(numericVal);
52 numberValue = BigInt::BigIntToNumber(thread, bigNumericVal);
53 } else {
54 // c. Otherwise, let n be prim.
55 numberValue = JSTaggedNumber(numeric);
56 }
57 }
58 // 3. If NewTarget is undefined, return n.
59 if (newTarget->IsUndefined()) {
60 return numberValue;
61 }
62 // 4. Let O be OrdinaryCreateFromConstructor(NewTarget, "%NumberPrototype%", «[[NumberData]]» ).
63 JSHandle<JSTaggedValue> constructor = GetConstructor(argv);
64 JSHandle<JSObject> result =
65 thread->GetEcmaVM()->GetFactory()->NewJSObjectByConstructor(JSHandle<JSFunction>::Cast(constructor), newTarget);
66 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
67 // 5. Set O.[[NumberData]] to n.
68 JSPrimitiveRef::Cast(*result)->SetValue(thread, numberValue);
69 // 6. Return O.
70 return result.GetTaggedValue();
71 }
72
73 // 20.1.2.2
IsFinite(EcmaRuntimeCallInfo * argv)74 JSTaggedValue BuiltinsNumber::IsFinite(EcmaRuntimeCallInfo *argv)
75 {
76 ASSERT(argv);
77 BUILTINS_API_TRACE(argv->GetThread(), Number, IsFinite);
78 JSTaggedValue msg = GetCallArg(argv, 0).GetTaggedValue();
79 // 1. If Type(number) is not Number, return false
80 // 2. If number is NaN, +infinite, or -infinite, return false
81 if (NumberHelper::IsFinite(msg)) {
82 return GetTaggedBoolean(true);
83 }
84 return GetTaggedBoolean(false);
85 }
86
87 // 20.1.2.3
IsInteger(EcmaRuntimeCallInfo * argv)88 JSTaggedValue BuiltinsNumber::IsInteger(EcmaRuntimeCallInfo *argv)
89 {
90 ASSERT(argv);
91 BUILTINS_API_TRACE(argv->GetThread(), Number, IsInteger);
92 JSThread *thread = argv->GetThread();
93 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
94 bool result = false;
95 // 1. If Type(number) is not Number, return false.
96 // 2. If number is NaN, +infinite, or -infinite, return false
97 if (NumberHelper::IsFinite(msg.GetTaggedValue())) {
98 [[maybe_unused]] EcmaHandleScope handleScope(thread);
99 double value = JSTaggedNumber(msg.GetTaggedValue()).GetNumber();
100 // 3. Let integer be ToInteger(number).
101 JSTaggedNumber number = JSTaggedValue::ToInteger(thread, msg);
102 // 4. If integer is not equal to number, return false.
103 // 5. Otherwise, return true.
104 result = (value == number.GetNumber());
105 }
106 return GetTaggedBoolean(result);
107 }
108
109 // 20.1.2.4
IsNaN(EcmaRuntimeCallInfo * argv)110 JSTaggedValue BuiltinsNumber::IsNaN(EcmaRuntimeCallInfo *argv)
111 {
112 ASSERT(argv);
113 BUILTINS_API_TRACE(argv->GetThread(), Number, IsNaN);
114 JSTaggedValue msg = GetCallArg(argv, 0).GetTaggedValue();
115 // 1. If Type(number) is not Number, return false.
116 // 2. If number is NaN, return true.
117 if (NumberHelper::IsNaN(msg)) {
118 return GetTaggedBoolean(true);
119 }
120 // 3. Otherwise, return false.
121 return GetTaggedBoolean(false);
122 }
123
124 // 20.1.2.5
IsSafeInteger(EcmaRuntimeCallInfo * argv)125 JSTaggedValue BuiltinsNumber::IsSafeInteger(EcmaRuntimeCallInfo *argv)
126 {
127 ASSERT(argv);
128 BUILTINS_API_TRACE(argv->GetThread(), Number, IsSafeInteger);
129 JSThread *thread = argv->GetThread();
130 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
131 bool result = false;
132 // 1. If Type(number) is not Number, return false.
133 // 2. If number is NaN, +infinite, or -infinite, return false
134 if (NumberHelper::IsFinite(msg.GetTaggedValue())) {
135 [[maybe_unused]] EcmaHandleScope handleScope(thread);
136 double value = JSTaggedNumber(msg.GetTaggedValue()).GetNumber();
137 // 3. Let integer be ToInteger(number).
138 JSTaggedNumber number = JSTaggedValue::ToInteger(thread, msg);
139 // 4. If integer is not equal to number, return false.
140 // 5. If abs(integer) ≤ 253−1, return true.
141 result = (value == number.GetNumber()) && std::abs(value) <= base::MAX_SAFE_INTEGER;
142 }
143 return GetTaggedBoolean(result);
144 }
145
146 // 18.2.4
147 // 20.1.2.12
ParseFloat(EcmaRuntimeCallInfo * argv)148 JSTaggedValue BuiltinsNumber::ParseFloat(EcmaRuntimeCallInfo *argv)
149 {
150 ASSERT(argv);
151 BUILTINS_API_TRACE(argv->GetThread(), Number, ParseFloat);
152 JSThread *thread = argv->GetThread();
153 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
154 if (msg->IsUndefined()) {
155 return GetTaggedDouble(base::NAN_VALUE);
156 }
157 [[maybe_unused]] EcmaHandleScope handleScope(thread);
158 // 1. Let inputString be ToString(string).
159 JSHandle<EcmaString> numberString = JSTaggedValue::ToString(thread, msg);
160 // 2. ReturnIfAbrupt(inputString).
161 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
162 Span<const uint8_t> str;
163 if (UNLIKELY(numberString->IsUtf16())) {
164 size_t len = base::utf_helper::Utf16ToUtf8Size(numberString->GetDataUtf16(), numberString->GetLength()) - 1;
165 CVector<uint8_t> buf(len);
166 len = base::utf_helper::ConvertRegionUtf16ToUtf8(numberString->GetDataUtf16(), buf.data(),
167 numberString->GetLength(), len, 0);
168 str = Span<const uint8_t>(buf.data(), len);
169 } else {
170 str = Span<const uint8_t>(numberString->GetDataUtf8(), numberString->GetUtf8Length() - 1);
171 }
172 // 4. If neither trimmedString nor any prefix of trimmedString satisfies the syntax of a StrDecimalLiteral
173 // (see 7.1.3.1), return NaN.
174 if (NumberHelper::IsEmptyString(str.begin(), str.end())) {
175 return BuiltinsBase::GetTaggedDouble(base::NAN_VALUE);
176 }
177 double result = NumberHelper::StringToDouble(str.begin(), str.end(), 0, base::IGNORE_TRAILING);
178 return GetTaggedDouble(result);
179 }
180
181 // 18.2.5
182 // 20.1.2.13
ParseInt(EcmaRuntimeCallInfo * argv)183 JSTaggedValue BuiltinsNumber::ParseInt(EcmaRuntimeCallInfo *argv)
184 {
185 ASSERT(argv);
186 BUILTINS_API_TRACE(argv->GetThread(), Number, ParseInt);
187 JSThread *thread = argv->GetThread();
188 [[maybe_unused]] EcmaHandleScope handleScope(thread);
189 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
190 JSHandle<JSTaggedValue> arg2 = GetCallArg(argv, 1);
191 int32_t radix = 0;
192
193 if (!arg2->IsUndefined()) {
194 // 7. Let R = ToInt32(radix).
195 radix = JSTaggedValue::ToInt32(thread, arg2);
196 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
197 }
198 // 1. Let inputString be ToString(string).
199 JSHandle<EcmaString> numberString = JSTaggedValue::ToString(thread, msg);
200 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
201 Span<const uint8_t> str;
202 if (UNLIKELY(numberString->IsUtf16())) {
203 size_t len = base::utf_helper::Utf16ToUtf8Size(numberString->GetDataUtf16(), numberString->GetLength()) - 1;
204 CVector<uint8_t> buf(len);
205 len = base::utf_helper::ConvertRegionUtf16ToUtf8(numberString->GetDataUtf16(), buf.data(),
206 numberString->GetLength(), len, 0);
207 str = Span<const uint8_t>(buf.data(), len);
208 } else {
209 str = Span<const uint8_t>(numberString->GetDataUtf8(), numberString->GetUtf8Length() - 1);
210 }
211
212 JSTaggedValue result = NumberHelper::StringToDoubleWithRadix(str.begin(), str.end(), radix);
213 return result;
214 }
215
216 // prototype
217 // 20.1.3.2
ToExponential(EcmaRuntimeCallInfo * argv)218 JSTaggedValue BuiltinsNumber::ToExponential(EcmaRuntimeCallInfo *argv)
219 {
220 ASSERT(argv);
221 BUILTINS_API_TRACE(argv->GetThread(), Number, ToExponential);
222 JSThread *thread = argv->GetThread();
223 [[maybe_unused]] EcmaHandleScope handleScope(thread);
224 // 1. Let x be ? thisNumberValue(this value).
225 JSTaggedNumber value = ThisNumberValue(argv);
226 // 2. ReturnIfAbrupt(x).
227 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
228
229 // 3. Let f be ToInteger(fractionDigits).
230 JSHandle<JSTaggedValue> digits = GetCallArg(argv, 0);
231 JSTaggedNumber digitInt = JSTaggedValue::ToInteger(thread, digits);
232 // 5. ReturnIfAbrupt(f).
233 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
234
235 double values = value.GetNumber();
236 // 6. If x is NaN, return the String "NaN".
237 if (std::isnan(values)) {
238 return GetTaggedString(thread, "NaN");
239 }
240 // 8. If x < 0, then
241 // a. Let s be "-".
242 // b. Let x = –x.
243 // 9. If x = +infinity, then
244 // a. Return the concatenation of the Strings s and "Infinity".
245 if (!std::isfinite(values)) {
246 if (values < 0) {
247 return GetTaggedString(thread, "-Infinity");
248 }
249 return GetTaggedString(thread, "Infinity");
250 }
251
252 // 4. Assert: f is 0, when fractionDigits is undefined.
253 // 10. If f < 0 or f > 20, throw a RangeError exception
254 double fraction = digitInt.GetNumber();
255 if (digits->IsUndefined()) {
256 fraction = -1;
257 } else {
258 if (fraction < base::MIN_FRACTION || fraction > base::MAX_FRACTION) {
259 THROW_RANGE_ERROR_AND_RETURN(thread, "fraction must be 0 to 100", JSTaggedValue::Exception());
260 }
261 }
262 return NumberHelper::DoubleToExponential(thread, values, static_cast<int>(fraction));
263 }
264
265 // 20.1.3.3
ToFixed(EcmaRuntimeCallInfo * argv)266 JSTaggedValue BuiltinsNumber::ToFixed(EcmaRuntimeCallInfo *argv)
267 {
268 ASSERT(argv);
269 BUILTINS_API_TRACE(argv->GetThread(), Number, ToFixed);
270 JSThread *thread = argv->GetThread();
271 [[maybe_unused]] EcmaHandleScope handleScope(thread);
272 // 1. Let x be ? thisNumberValue(this value).
273 JSTaggedNumber value = ThisNumberValue(argv);
274 // 2. ReturnIfAbrupt(x).
275 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
276 // 3. Let f be ToInteger(fractionDigits). (If fractionDigits is undefined, this step produces the value 0).
277 JSHandle<JSTaggedValue> digitArgv = GetCallArg(argv, 0);
278 JSTaggedNumber digitInt = JSTaggedValue::ToInteger(thread, digitArgv);
279 if (digitArgv->IsUndefined()) {
280 digitInt = JSTaggedNumber(0);
281 }
282 // 4. ReturnIfAbrupt(f).
283 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
284
285 double digit = digitInt.GetNumber();
286 if (digit < base::MIN_FRACTION || digit > base::MAX_FRACTION) {
287 THROW_RANGE_ERROR_AND_RETURN(thread, "fraction must be 0 to 100", JSTaggedValue::Exception());
288 }
289
290 // 6. If x is NaN, return the String "NaN".
291 double valueNumber = value.GetNumber();
292 if (std::isnan(valueNumber)) {
293 return GetTaggedString(thread, "NaN");
294 }
295 // 9. If x 1021, then
296 // a. Let m = ToString(x).
297 const double FIRST_NO_FIXED = 1e21;
298 if (valueNumber >= FIRST_NO_FIXED) {
299 return value.ToString(thread).GetTaggedValue();
300 }
301
302 return NumberHelper::DoubleToFixed(thread, valueNumber, static_cast<int>(digit));
303 }
304
305 // 20.1.3.4
ToLocaleString(EcmaRuntimeCallInfo * argv)306 JSTaggedValue BuiltinsNumber::ToLocaleString(EcmaRuntimeCallInfo *argv)
307 {
308 ASSERT(argv);
309 JSThread *thread = argv->GetThread();
310 BUILTINS_API_TRACE(thread, Number, ToLocaleString);
311 [[maybe_unused]] EcmaHandleScope handleScope(thread);
312 // 1. Let x be ? thisNumberValue(this value).
313 JSHandle<JSTaggedValue> x(thread, ThisNumberValue(argv));
314 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
315 // 2. Let numberFormat be ? Construct(%NumberFormat%, « locales, options »).
316 EcmaVM *ecmaVm = thread->GetEcmaVM();
317 JSHandle<JSTaggedValue> ctor = ecmaVm->GetGlobalEnv()->GetNumberFormatFunction();
318 ObjectFactory *factory = ecmaVm->GetFactory();
319 JSHandle<JSObject> obj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(ctor), ctor);
320 JSHandle<JSNumberFormat> numberFormat = JSHandle<JSNumberFormat>::Cast(obj);
321 JSHandle<JSTaggedValue> locales = GetCallArg(argv, 0);
322 JSHandle<JSTaggedValue> options = GetCallArg(argv, 1);
323 bool cacheable = (locales->IsUndefined() || locales->IsString()) && options->IsUndefined();
324 if (cacheable) {
325 auto numberFormatter = JSNumberFormat::GetCachedIcuNumberFormatter(thread, locales);
326 if (numberFormatter != nullptr) {
327 JSHandle<JSTaggedValue> result = JSNumberFormat::FormatNumeric(thread, numberFormatter, x.GetTaggedValue());
328 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
329 return result.GetTaggedValue();
330 }
331 }
332 JSNumberFormat::InitializeNumberFormat(thread, numberFormat, locales, options, cacheable);
333 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
334 if (cacheable) {
335 auto numberFormatter = JSNumberFormat::GetCachedIcuNumberFormatter(thread, locales);
336 ASSERT(numberFormatter != nullptr);
337 JSHandle<JSTaggedValue> result = JSNumberFormat::FormatNumeric(thread, numberFormatter, x.GetTaggedValue());
338 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
339 return result.GetTaggedValue();
340 }
341
342 // Return ? FormatNumeric(numberFormat, x).
343 JSHandle<JSTaggedValue> result = JSNumberFormat::FormatNumeric(thread, numberFormat, x.GetTaggedValue());
344 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
345 return result.GetTaggedValue();
346 }
347
348 // 20.1.3.5
ToPrecision(EcmaRuntimeCallInfo * argv)349 JSTaggedValue BuiltinsNumber::ToPrecision(EcmaRuntimeCallInfo *argv)
350 {
351 ASSERT(argv);
352 BUILTINS_API_TRACE(argv->GetThread(), Number, ToPrecision);
353 JSThread *thread = argv->GetThread();
354 [[maybe_unused]] EcmaHandleScope handleScope(thread);
355 // 1. Let x be ? thisNumberValue(this value).
356 JSTaggedNumber value = ThisNumberValue(argv);
357 // 2. ReturnIfAbrupt(x).
358 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
359
360 // 3. If precision is undefined, return ToString(x).
361 JSHandle<JSTaggedValue> digitArgv = GetCallArg(argv, 0);
362 if (digitArgv->IsUndefined()) {
363 return value.ToString(thread).GetTaggedValue();
364 }
365 // 4. Let p be ToInteger(precision).
366 JSTaggedNumber digitInt = JSTaggedValue::ToInteger(thread, digitArgv);
367 // 5. ReturnIfAbrupt(p).
368 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
369
370 // 6. If x is NaN, return the String "NaN".
371 double valueNumber = value.GetNumber();
372 if (std::isnan(valueNumber)) {
373 return GetTaggedString(thread, "NaN");
374 }
375 // 9. If x = +infinity, then
376 // a. Return the String that is the concatenation of s and "Infinity".
377 if (!std::isfinite(valueNumber)) {
378 if (valueNumber < 0) {
379 return GetTaggedString(thread, "-Infinity");
380 }
381 return GetTaggedString(thread, "Infinity");
382 }
383
384 // If p < 1 or p > 21, throw a RangeError exception
385 double digit = digitInt.GetNumber();
386 if (digit < base::MIN_FRACTION + 1 || digit > base::MAX_FRACTION) {
387 THROW_RANGE_ERROR_AND_RETURN(thread, "fraction must be 1 to 100", JSTaggedValue::Exception());
388 }
389 return NumberHelper::DoubleToPrecision(thread, valueNumber, static_cast<int>(digit));
390 }
391
392 // 20.1.3.6
ToString(EcmaRuntimeCallInfo * argv)393 JSTaggedValue BuiltinsNumber::ToString(EcmaRuntimeCallInfo *argv)
394 {
395 ASSERT(argv);
396 BUILTINS_API_TRACE(argv->GetThread(), Number, ToString);
397 JSThread *thread = argv->GetThread();
398 [[maybe_unused]] EcmaHandleScope handleScope(thread);
399 // 1. Let x be ? thisNumberValue(this value).
400 JSTaggedNumber value = ThisNumberValue(argv);
401 // 2. ReturnIfAbrupt(x).
402 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
403
404 // 3. If radix is not present, let radixNumber be 10.
405 // 4. Else if radix is undefined, let radixNumber be 10.
406 double radix = base::DECIMAL;
407 JSHandle<JSTaggedValue> radixValue = GetCallArg(argv, 0);
408 // 5. Else let radixNumber be ToInteger(radix).
409 if (!radixValue->IsUndefined()) {
410 JSTaggedNumber radixNumber = JSTaggedValue::ToInteger(thread, radixValue);
411 // 6. ReturnIfAbrupt(x).
412 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
413 radix = radixNumber.GetNumber();
414 }
415
416 // 7. If radixNumber < 2 or radixNumber > 36, throw a RangeError exception.
417 if (radix < base::MIN_RADIX || radix > base::MAX_RADIX) {
418 THROW_RANGE_ERROR_AND_RETURN(thread, "radix must be 2 to 36", JSTaggedValue::Exception());
419 }
420 // 8. If radixNumber = 10, return ToString(x).
421 if (radix == base::DECIMAL) {
422 return value.ToString(thread).GetTaggedValue();
423 }
424
425 double valueNumber = value.GetNumber();
426 // If x is NaN, return the String "NaN".
427 if (std::isnan(valueNumber)) {
428 return GetTaggedString(thread, "NaN");
429 }
430 // If x = +infinity, then
431 // Return the String that is the concatenation of s and "Infinity".
432 if (!std::isfinite(valueNumber)) {
433 if (valueNumber < 0) {
434 return GetTaggedString(thread, "-Infinity");
435 }
436 return GetTaggedString(thread, "Infinity");
437 }
438 return NumberHelper::DoubleToString(thread, valueNumber, static_cast<int>(radix));
439 }
440
441 // 20.1.3.7
ValueOf(EcmaRuntimeCallInfo * argv)442 JSTaggedValue BuiltinsNumber::ValueOf(EcmaRuntimeCallInfo *argv)
443 {
444 ASSERT(argv);
445 BUILTINS_API_TRACE(argv->GetThread(), Number, ValueOf);
446 // 1. Let x be ? thisNumberValue(this value).
447 JSTaggedValue x = ThisNumberValue(argv);
448 JSThread *thread = argv->GetThread();
449 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
450 return x;
451 }
452
ThisNumberValue(EcmaRuntimeCallInfo * argv)453 JSTaggedNumber BuiltinsNumber::ThisNumberValue(EcmaRuntimeCallInfo *argv)
454 {
455 BUILTINS_API_TRACE(argv->GetThread(), Number, ThisNumberValue);
456 JSHandle<JSTaggedValue> value = GetThis(argv);
457 if (value->IsNumber()) {
458 return JSTaggedNumber(value.GetTaggedValue());
459 }
460 if (value->IsJSPrimitiveRef()) {
461 JSTaggedValue primitive = JSPrimitiveRef::Cast(value->GetTaggedObject())->GetValue();
462 if (primitive.IsNumber()) {
463 return JSTaggedNumber(primitive);
464 }
465 }
466 JSThread *thread = argv->GetThread();
467 [[maybe_unused]] EcmaHandleScope handleScope(thread);
468 THROW_TYPE_ERROR_AND_RETURN(thread, "not number type", JSTaggedNumber::Exception());
469 }
470 } // namespace panda::ecmascript::builtins
471