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