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