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