• 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         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
109         // 4. If integer is not equal to number, return false.
110         // 5. Otherwise, return true.
111         result = (value == number.GetNumber());
112     }
113     return GetTaggedBoolean(result);
114 }
115 
116 // 20.1.2.4
IsNaN(EcmaRuntimeCallInfo * argv)117 JSTaggedValue BuiltinsNumber::IsNaN(EcmaRuntimeCallInfo *argv)
118 {
119     ASSERT(argv);
120     BUILTINS_API_TRACE(argv->GetThread(), Number, IsNaN);
121     JSTaggedValue msg = GetCallArg(argv, 0).GetTaggedValue();
122     // 1. If Type(number) is not Number, return false.
123     // 2. If number is NaN, return true.
124     if (NumberHelper::IsNaN(msg)) {
125         return GetTaggedBoolean(true);
126     }
127     // 3. Otherwise, return false.
128     return GetTaggedBoolean(false);
129 }
130 
131 // 20.1.2.5
IsSafeInteger(EcmaRuntimeCallInfo * argv)132 JSTaggedValue BuiltinsNumber::IsSafeInteger(EcmaRuntimeCallInfo *argv)
133 {
134     ASSERT(argv);
135     BUILTINS_API_TRACE(argv->GetThread(), Number, IsSafeInteger);
136     JSThread *thread = argv->GetThread();
137     JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
138     bool result = false;
139     // 1. If Type(number) is not Number, return false.
140     // 2. If number is NaN, +infinite, or -infinite, return false
141     if (NumberHelper::IsFinite(msg.GetTaggedValue())) {
142         [[maybe_unused]] EcmaHandleScope handleScope(thread);
143         double value = JSTaggedNumber(msg.GetTaggedValue()).GetNumber();
144         // 3. Let integer be ToInteger(number).
145         JSTaggedNumber number = JSTaggedValue::ToInteger(thread, msg);
146         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
147         // 4. If integer is not equal to number, return false.
148         // 5. If abs(integer) ≤ 253−1, return true.
149         result = (value == number.GetNumber()) && std::abs(value) <= base::MAX_SAFE_INTEGER;
150     }
151     return GetTaggedBoolean(result);
152 }
153 
154 // 18.2.4
155 // 20.1.2.12
ParseFloat(EcmaRuntimeCallInfo * argv)156 JSTaggedValue BuiltinsNumber::ParseFloat(EcmaRuntimeCallInfo *argv)
157 {
158     ASSERT(argv);
159     BUILTINS_API_TRACE(argv->GetThread(), Number, ParseFloat);
160     JSThread *thread = argv->GetThread();
161     JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
162     if (msg->IsUndefined()) {
163         return GetTaggedDouble(base::NAN_VALUE);
164     }
165     [[maybe_unused]] EcmaHandleScope handleScope(thread);
166     // 1. Let inputString be ToString(string).
167     JSHandle<EcmaString> numberString = JSTaggedValue::ToString(thread, msg);
168     // 2. ReturnIfAbrupt(inputString).
169     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
170     CVector<uint8_t> buf;
171     Span<const uint8_t> str = EcmaStringAccessor(numberString).ToUtf8Span(buf);
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     CVector<uint8_t> buf;
202     Span<const uint8_t> str = EcmaStringAccessor(numberString).ToUtf8Span(buf);
203 
204     JSTaggedValue result = NumberHelper::StringToDoubleWithRadix(str.begin(), str.end(), radix);
205     return JSTaggedValue::TryCastDoubleToInt32(result.GetNumber());
206 }
207 
208 // prototype
209 // 20.1.3.2
ToExponential(EcmaRuntimeCallInfo * argv)210 JSTaggedValue BuiltinsNumber::ToExponential(EcmaRuntimeCallInfo *argv)
211 {
212     ASSERT(argv);
213     JSThread *thread = argv->GetThread();
214     BUILTINS_API_TRACE(thread, Number, ToExponential);
215     [[maybe_unused]] EcmaHandleScope handleScope(thread);
216     // 1. Let x be ? thisNumberValue(this value).
217     JSTaggedNumber value = ThisNumberValue(thread, argv);
218     // 2. ReturnIfAbrupt(x).
219     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
220 
221     // 3. Let f be ToInteger(fractionDigits).
222     JSHandle<JSTaggedValue> digits = GetCallArg(argv, 0);
223     JSTaggedNumber digitInt = JSTaggedValue::ToInteger(thread, digits);
224     // 5. ReturnIfAbrupt(f).
225     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
226 
227     double values = value.GetNumber();
228     // 6. If x is NaN, return the String "NaN".
229     if (std::isnan(values)) {
230         return GetTaggedString(thread, "NaN");
231     }
232     // 8. If x < 0, then
233     //    a. Let s be "-".
234     //    b. Let x = –x.
235     // 9. If x = +infinity, then
236     //    a. Return the concatenation of the Strings s and "Infinity".
237     if (!std::isfinite(values)) {
238         if (values < 0) {
239             return GetTaggedString(thread, "-Infinity");
240         }
241         return GetTaggedString(thread, "Infinity");
242     }
243 
244     // 4. Assert: f is 0, when fractionDigits is undefined.
245     // 10. If f < 0 or f > 20, throw a RangeError exception
246     double fraction = digitInt.GetNumber();
247     if (digits->IsUndefined()) {
248         fraction = -1;
249     } else {
250         if (fraction < base::MIN_FRACTION || fraction > base::MAX_FRACTION) {
251             THROW_RANGE_ERROR_AND_RETURN(thread, "fraction must be 0 to 100", JSTaggedValue::Exception());
252         }
253     }
254     return NumberHelper::DoubleToExponential(thread, values, static_cast<int>(fraction));
255 }
256 
257 // 20.1.3.3
ToFixed(EcmaRuntimeCallInfo * argv)258 JSTaggedValue BuiltinsNumber::ToFixed(EcmaRuntimeCallInfo *argv)
259 {
260     ASSERT(argv);
261     JSThread *thread = argv->GetThread();
262     BUILTINS_API_TRACE(thread, Number, ToFixed);
263     [[maybe_unused]] EcmaHandleScope handleScope(thread);
264     // 1. Let x be ? thisNumberValue(this value).
265     JSTaggedNumber value = ThisNumberValue(thread, argv);
266     // 2. ReturnIfAbrupt(x).
267     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
268     // 3. Let f be ToInteger(fractionDigits). (If fractionDigits is undefined, this step produces the value 0).
269     JSHandle<JSTaggedValue> digitArgv = GetCallArg(argv, 0);
270     JSTaggedNumber digitInt = JSTaggedValue::ToInteger(thread, digitArgv);
271     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
272     if (digitArgv->IsUndefined()) {
273         digitInt = JSTaggedNumber(0);
274     }
275     // 4. ReturnIfAbrupt(f).
276     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
277 
278     double digit = digitInt.GetNumber();
279     if (digit < base::MIN_FRACTION || digit > base::MAX_FRACTION) {
280         THROW_RANGE_ERROR_AND_RETURN(thread, "fraction must be 0 to 100", JSTaggedValue::Exception());
281     }
282 
283     // 6. If x is NaN, return the String "NaN".
284     double valueNumber = value.GetNumber();
285     if (std::isnan(valueNumber)) {
286         const GlobalEnvConstants *globalConst = thread->GlobalConstants();
287         return globalConst->GetNanCapitalString();
288     }
289     // 9. If x  1021, then
290     //    a. Let m = ToString(x).
291     const double FIRST_NO_FIXED = 1e21;
292     if (valueNumber >= FIRST_NO_FIXED) {
293         return value.ToString(thread).GetTaggedValue();
294     }
295 
296     return NumberHelper::DoubleToFixed(thread, valueNumber, static_cast<int>(digit));
297 }
298 
299 // 20.1.3.4
ToLocaleString(EcmaRuntimeCallInfo * argv)300 JSTaggedValue BuiltinsNumber::ToLocaleString(EcmaRuntimeCallInfo *argv)
301 {
302     ASSERT(argv);
303     JSThread *thread = argv->GetThread();
304     BUILTINS_API_TRACE(thread, Number, ToLocaleString);
305     [[maybe_unused]] EcmaHandleScope handleScope(thread);
306     // 1. Let x be ? thisNumberValue(this value).
307     [[maybe_unused]] JSHandle<JSTaggedValue> x(thread, ThisNumberValue(thread, argv));
308     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
309 
310     JSHandle<JSTaggedValue> locales = GetCallArg(argv, 0);
311     JSHandle<JSTaggedValue> options = GetCallArg(argv, 1);
312     [[maybe_unused]] bool cacheable = (locales->IsUndefined() || locales->IsString()) && options->IsUndefined();
313 #ifdef ARK_SUPPORT_INTL
314     if (cacheable) {
315         auto numberFormatter = JSNumberFormat::GetCachedIcuNumberFormatter(thread, locales);
316         if (numberFormatter != nullptr) {
317             JSHandle<JSTaggedValue> result = JSNumberFormat::FormatNumeric(thread, numberFormatter, x.GetTaggedValue());
318             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
319             return result.GetTaggedValue();
320         }
321     }
322     // 2. Let numberFormat be ? Construct(%NumberFormat%, « locales, options »).
323     EcmaVM *ecmaVm = thread->GetEcmaVM();
324     JSHandle<JSFunction> ctor(ecmaVm->GetGlobalEnv()->GetNumberFormatFunction());
325     ObjectFactory *factory = ecmaVm->GetFactory();
326     JSHandle<JSObject> obj = factory->NewJSObjectByConstructor(ctor);
327     JSHandle<JSNumberFormat> numberFormat = JSHandle<JSNumberFormat>::Cast(obj);
328     JSNumberFormat::InitializeNumberFormat(thread, numberFormat, locales, options, cacheable);
329     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
330     if (cacheable) {
331         auto numberFormatter = JSNumberFormat::GetCachedIcuNumberFormatter(thread, locales);
332         ASSERT(numberFormatter != nullptr);
333         JSHandle<JSTaggedValue> result = JSNumberFormat::FormatNumeric(thread, numberFormatter, x.GetTaggedValue());
334         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
335         return result.GetTaggedValue();
336     }
337 
338     // Return ? FormatNumeric(numberFormat, x).
339     JSHandle<JSTaggedValue> result = JSNumberFormat::FormatNumeric(thread, numberFormat, x.GetTaggedValue());
340     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
341     return result.GetTaggedValue();
342 #else
343 #ifdef ARK_NOT_SUPPORT_INTL_GLOBAL
344     ARK_SUPPORT_INTL_RETURN_JSVALUE(thread, "LocaleCompare");
345 #else
346     intl::GlobalIntlHelper gh(thread, intl::GlobalFormatterType::NumberFormatter);
347     auto numberFormatter = gh.GetGlobalObject<intl::GlobalNumberFormat>(thread,
348         locales, options, intl::GlobalFormatterType::NumberFormatter, cacheable);
349     if (numberFormatter == nullptr) {
350         LOG_ECMA(ERROR) << "BuiltinsNumber:numberFormatter is nullptr";
351     }
352     ASSERT(numberFormatter != nullptr);
353     std::string result = numberFormatter->Format(x->GetDouble());
354     EcmaVM *ecmaVm = thread->GetEcmaVM();
355     ObjectFactory *factory = ecmaVm->GetFactory();
356     JSHandle returnValue = factory->NewFromStdString(result);
357     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
358     return returnValue.GetTaggedValue();
359 #endif
360 #endif
361 }
362 
363 // 20.1.3.5
ToPrecision(EcmaRuntimeCallInfo * argv)364 JSTaggedValue BuiltinsNumber::ToPrecision(EcmaRuntimeCallInfo *argv)
365 {
366     ASSERT(argv);
367     JSThread *thread = argv->GetThread();
368     BUILTINS_API_TRACE(thread, Number, ToPrecision);
369     [[maybe_unused]] EcmaHandleScope handleScope(thread);
370     // 1. Let x be ? thisNumberValue(this value).
371     JSTaggedNumber value = ThisNumberValue(thread, argv);
372     // 2. ReturnIfAbrupt(x).
373     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
374 
375     // 3. If precision is undefined, return ToString(x).
376     JSHandle<JSTaggedValue> digitArgv = GetCallArg(argv, 0);
377     if (digitArgv->IsUndefined()) {
378         return value.ToString(thread).GetTaggedValue();
379     }
380     // 4. Let p be ToInteger(precision).
381     JSTaggedNumber digitInt = JSTaggedValue::ToInteger(thread, digitArgv);
382     // 5. ReturnIfAbrupt(p).
383     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
384 
385     // 6. If x is NaN, return the String "NaN".
386     double valueNumber = value.GetNumber();
387     if (std::isnan(valueNumber)) {
388         return GetTaggedString(thread, "NaN");
389     }
390     // 9. If x = +infinity, then
391     //    a. Return the String that is the concatenation of s and "Infinity".
392     if (!std::isfinite(valueNumber)) {
393         if (valueNumber < 0) {
394             return GetTaggedString(thread, "-Infinity");
395         }
396         return GetTaggedString(thread, "Infinity");
397     }
398 
399     // If p < 1 or p > 21, throw a RangeError exception
400     double digit = digitInt.GetNumber();
401     if (digit < base::MIN_FRACTION + 1 || digit > base::MAX_FRACTION) {
402         THROW_RANGE_ERROR_AND_RETURN(thread, "fraction must be 1 to 100", JSTaggedValue::Exception());
403     }
404     return NumberHelper::DoubleToPrecision(thread, valueNumber, static_cast<int>(digit));
405 }
406 
407 // 20.1.3.6
ToString(EcmaRuntimeCallInfo * argv)408 JSTaggedValue BuiltinsNumber::ToString(EcmaRuntimeCallInfo *argv)
409 {
410     ASSERT(argv);
411     JSThread *thread = argv->GetThread();
412     BUILTINS_API_TRACE(thread, Number, ToString);
413     [[maybe_unused]] EcmaHandleScope handleScope(thread);
414     // 1. Let x be ? thisNumberValue(this value).
415     JSTaggedNumber value = ThisNumberValue(thread, argv);
416     // 2. ReturnIfAbrupt(x).
417     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
418 
419     // 3. If radix is not present, let radixNumber be 10.
420     // 4. Else if radix is undefined, let radixNumber be 10.
421     double radix = base::DECIMAL;
422     JSHandle<JSTaggedValue> radixValue = GetCallArg(argv, 0);
423     // 5. Else let radixNumber be ToInteger(radix).
424     if (!radixValue->IsUndefined()) {
425         JSTaggedNumber radixNumber = JSTaggedValue::ToInteger(thread, radixValue);
426         // 6. ReturnIfAbrupt(x).
427         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
428         radix = radixNumber.GetNumber();
429     }
430 
431     // 7. If radixNumber < 2 or radixNumber > 36, throw a RangeError exception.
432     if (radix < base::MIN_RADIX || radix > base::MAX_RADIX) {
433         THROW_RANGE_ERROR_AND_RETURN(thread, "radix must be 2 to 36", JSTaggedValue::Exception());
434     }
435     // 8. If radixNumber = 10, return ToString(x).
436     if (radix == base::DECIMAL) {
437         return value.ToString(thread).GetTaggedValue();
438     }
439 
440     double valueNumber = value.GetNumber();
441     // If x is NaN, return the String "NaN".
442     if (std::isnan(valueNumber)) {
443         return GetTaggedString(thread, "NaN");
444     }
445     //  If x = +infinity, then
446     //     Return the String that is the concatenation of s and "Infinity".
447     if (!std::isfinite(valueNumber)) {
448         if (valueNumber < 0) {
449             return GetTaggedString(thread, "-Infinity");
450         }
451         return GetTaggedString(thread, "Infinity");
452     }
453     return NumberHelper::DoubleToString(thread, valueNumber, static_cast<int>(radix));
454 }
455 
456 // 20.1.3.7
ValueOf(EcmaRuntimeCallInfo * argv)457 JSTaggedValue BuiltinsNumber::ValueOf(EcmaRuntimeCallInfo *argv)
458 {
459     ASSERT(argv);
460     JSThread *thread = argv->GetThread();
461     BUILTINS_API_TRACE(thread, Number, ValueOf);
462     // 1. Let x be ? thisNumberValue(this value).
463     JSTaggedValue x = ThisNumberValue(thread, argv);
464 
465     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
466     return x;
467 }
468 
ThisNumberValue(JSThread * thread,EcmaRuntimeCallInfo * argv)469 JSTaggedNumber BuiltinsNumber::ThisNumberValue(JSThread *thread, EcmaRuntimeCallInfo *argv)
470 {
471     BUILTINS_API_TRACE(thread, Number, ThisNumberValue);
472     JSHandle<JSTaggedValue> value = GetThis(argv);
473     if (value->IsNumber()) {
474         return JSTaggedNumber(value.GetTaggedValue());
475     }
476     if (value->IsJSPrimitiveRef()) {
477         JSTaggedValue primitive = JSPrimitiveRef::Cast(value->GetTaggedObject())->GetValue();
478         if (primitive.IsNumber()) {
479             return JSTaggedNumber(primitive);
480         }
481     }
482     [[maybe_unused]] EcmaHandleScope handleScope(thread);
483     THROW_TYPE_ERROR_AND_RETURN(thread, "not number type", JSTaggedNumber::Exception());
484 }
485 }  // namespace panda::ecmascript::builtins
486