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