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_math.h"
17 #include <random>
18 #include <sys/time.h>
19 #include "ecmascript/js_tagged_value-inl.h"
20
21 namespace panda::ecmascript::builtins {
22 using NumberHelper = base::NumberHelper;
23 using RandomGenerator = base::RandomGenerator;
24
25 // 20.2.2.1
Abs(EcmaRuntimeCallInfo *argv)26 JSTaggedValue BuiltinsMath::Abs(EcmaRuntimeCallInfo *argv)
27 {
28 ASSERT(argv);
29 BUILTINS_API_TRACE(argv->GetThread(), Math, Abs);
30 JSThread *thread = argv->GetThread();
31 [[maybe_unused]] EcmaHandleScope handleScope(thread);
32 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
33 JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg);
34 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
35 if (numberValue.IsDouble()) {
36 // if number_value is double,NaN,Undefine, deal in this case
37 // if number_value is a String ,which can change to double. e.g."100",deal in this case
38 return GetTaggedDouble(std::fabs(numberValue.GetDouble()));
39 }
40 // if number_value is int,boolean,null, deal in this case
41 int value = numberValue.GetInt();
42 if (value == INT_MIN) {
43 return GetTaggedDouble(-static_cast<int64_t>(INT_MIN));
44 }
45 return GetTaggedInt(std::abs(value));
46 }
47
48 // 20.2.2.2
Acos(EcmaRuntimeCallInfo *argv)49 JSTaggedValue BuiltinsMath::Acos(EcmaRuntimeCallInfo *argv)
50 {
51 ASSERT(argv);
52 BUILTINS_API_TRACE(argv->GetThread(), Math, Acos);
53 JSThread *thread = argv->GetThread();
54 [[maybe_unused]] EcmaHandleScope handleScope(thread);
55 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
56 JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg);
57 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
58 double value = numberValue.GetNumber();
59 double result = base::NAN_VALUE;
60 // value == -NaN , <-1 or > 1,result is NaN
61 if (!std::isnan(std::abs(value)) && value <= 1 && value >= -1) {
62 result = std::acos(value);
63 }
64 return GetTaggedDouble(result);
65 }
66
67 // 20.2.2.3
Acosh(EcmaRuntimeCallInfo *argv)68 JSTaggedValue BuiltinsMath::Acosh(EcmaRuntimeCallInfo *argv)
69 {
70 ASSERT(argv);
71 BUILTINS_API_TRACE(argv->GetThread(), Math, Acosh);
72 JSThread *thread = argv->GetThread();
73 [[maybe_unused]] EcmaHandleScope handleScope(thread);
74 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
75 JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg);
76 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
77 double value = numberValue.GetNumber();
78 double result = base::NAN_VALUE;
79 if (value >= 1) {
80 result = std::acosh(value);
81 }
82 return GetTaggedDouble(result);
83 }
84
85 // 20.2.2.4
Asin(EcmaRuntimeCallInfo *argv)86 JSTaggedValue BuiltinsMath::Asin(EcmaRuntimeCallInfo *argv)
87 {
88 ASSERT(argv);
89 BUILTINS_API_TRACE(argv->GetThread(), Math, Asin);
90 JSThread *thread = argv->GetThread();
91 [[maybe_unused]] EcmaHandleScope handleScope(thread);
92 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
93 JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg);
94 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
95 double value = numberValue.GetNumber();
96 double result = base::NAN_VALUE;
97 if (value >= -1 && value <= 1) {
98 result = std::asin(value);
99 }
100 return GetTaggedDouble(result);
101 }
102
103 // 20.2.2.5
Asinh(EcmaRuntimeCallInfo *argv)104 JSTaggedValue BuiltinsMath::Asinh(EcmaRuntimeCallInfo *argv)
105 {
106 ASSERT(argv);
107 BUILTINS_API_TRACE(argv->GetThread(), Math, Asinh);
108 JSThread *thread = argv->GetThread();
109 [[maybe_unused]] EcmaHandleScope handleScope(thread);
110 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
111 JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg);
112 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
113 double value = numberValue.GetNumber();
114 double result = base::NAN_VALUE;
115 // value == -NaN, NaN, result is NaN
116 if (!std::isnan(std::abs(value))) {
117 result = base::MathHelper::Asinh(value);
118 }
119 return GetTaggedDouble(result);
120 }
121
122 // 20.2.2.6
Atan(EcmaRuntimeCallInfo *argv)123 JSTaggedValue BuiltinsMath::Atan(EcmaRuntimeCallInfo *argv)
124 {
125 ASSERT(argv);
126 BUILTINS_API_TRACE(argv->GetThread(), Math, Atan);
127 JSThread *thread = argv->GetThread();
128 [[maybe_unused]] EcmaHandleScope handleScope(thread);
129 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
130 JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg);
131 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
132 double value = numberValue.GetNumber();
133 double result = base::NAN_VALUE;
134 // value == -NaN, NaN, result is NaN
135 if (!std::isnan(std::abs(value))) {
136 result = std::atan(value);
137 }
138 return GetTaggedDouble(result);
139 }
140
141 // 20.2.2.7
Atanh(EcmaRuntimeCallInfo *argv)142 JSTaggedValue BuiltinsMath::Atanh(EcmaRuntimeCallInfo *argv)
143 {
144 ASSERT(argv);
145 BUILTINS_API_TRACE(argv->GetThread(), Math, Atanh);
146 JSThread *thread = argv->GetThread();
147 [[maybe_unused]] EcmaHandleScope handleScope(thread);
148 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
149 JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg);
150 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
151 double value = numberValue.GetNumber();
152 double result = base::NAN_VALUE;
153 if (value >= -1 && value <= 1) {
154 result = base::MathHelper::Atanh(value);
155 }
156 return GetTaggedDouble(result);
157 }
158
159 // 20.2.2.8
Atan2(EcmaRuntimeCallInfo *argv)160 JSTaggedValue BuiltinsMath::Atan2(EcmaRuntimeCallInfo *argv)
161 {
162 ASSERT(argv);
163 BUILTINS_API_TRACE(argv->GetThread(), Math, Atan2);
164 JSThread *thread = argv->GetThread();
165 [[maybe_unused]] EcmaHandleScope handleScope(thread);
166 JSHandle<JSTaggedValue> msgY = GetCallArg(argv, 0);
167 JSHandle<JSTaggedValue> msgX = GetCallArg(argv, 1);
168 double result = base::NAN_VALUE;
169 JSTaggedNumber numberValueY = JSTaggedValue::ToNumber(thread, msgY);
170 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
171 JSTaggedNumber numberValueX = JSTaggedValue::ToNumber(thread, msgX);
172 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
173 double valueY = numberValueY.GetNumber();
174 double valueX = numberValueX.GetNumber();
175 // y = +0 and x > +0, return +0
176 // y = -0 and x > +0, return -0
177 if (valueY == 0 && valueX > 0) {
178 result = valueY;
179 } else if (std::isfinite(valueY) && valueX == std::numeric_limits<double>::infinity()) {
180 // y < 0 and y is finite and x is POSITIVE_INFINITY,return -0
181 // y >= 0 and y is finite and x is POSITIVE_INFINITY,return +0
182 result = valueY >= 0 ? 0 : -0.0;
183 } else if (!std::isnan(std::abs(valueY)) && !std::isnan(std::abs(valueX))) {
184 // If either x or y is NaN, the result is NaN
185 result = std::atan2(valueY, valueX);
186 }
187 return GetTaggedDouble(result);
188 }
189
190 // 20.2.2.9
Cbrt(EcmaRuntimeCallInfo *argv)191 JSTaggedValue BuiltinsMath::Cbrt(EcmaRuntimeCallInfo *argv)
192 {
193 ASSERT(argv);
194 BUILTINS_API_TRACE(argv->GetThread(), Math, Cbrt);
195 JSThread *thread = argv->GetThread();
196 [[maybe_unused]] EcmaHandleScope handleScope(thread);
197 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
198 JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg);
199 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
200 double value = numberValue.GetNumber();
201 double result = base::NAN_VALUE;
202 // if value == -NaN, NaN, result is NaN
203 if (!std::isnan(std::abs(value))) {
204 result = std::cbrt(value);
205 }
206 return GetTaggedDouble(result);
207 }
208
209 // 20.2.2.10
Ceil(EcmaRuntimeCallInfo *argv)210 JSTaggedValue BuiltinsMath::Ceil(EcmaRuntimeCallInfo *argv)
211 {
212 ASSERT(argv);
213 BUILTINS_API_TRACE(argv->GetThread(), Math, Ceil);
214 JSThread *thread = argv->GetThread();
215 [[maybe_unused]] EcmaHandleScope handleScope(thread);
216 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
217 JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg);
218 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
219 double value = numberValue.GetNumber();
220 double result = base::NAN_VALUE;
221 // If value is NaN or -NaN, +infinite, -infinite,return value
222 if (!std::isfinite(value)) {
223 // if value is -NaN , return NaN, else return value
224 if (!std::isnan(std::abs(value))) {
225 result = value;
226 }
227 } else {
228 result = std::ceil(value);
229 }
230 return GetTaggedDouble(result);
231 }
232
233 // 20.2.2.11
Clz32(EcmaRuntimeCallInfo *argv)234 JSTaggedValue BuiltinsMath::Clz32(EcmaRuntimeCallInfo *argv)
235 {
236 ASSERT(argv);
237 BUILTINS_API_TRACE(argv->GetThread(), Math, Clz32);
238 JSThread *thread = argv->GetThread();
239 [[maybe_unused]] EcmaHandleScope handleScope(thread);
240 constexpr int defaultValue = 32;
241 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
242 JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg);
243 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
244 double value = numberValue.GetNumber();
245 auto tmpValue = std::abs(value);
246 auto result = numberValue.ToUint32();
247 if (!std::isfinite(tmpValue) || tmpValue == 0 || result == 0) {
248 // If value is NaN or -NaN, +infinite, -infinite, 0,return 32
249 return GetTaggedInt(defaultValue);
250 }
251 return GetTaggedInt(__builtin_clz(result));
252 }
253
254 // 20.2.2.12
Cos(EcmaRuntimeCallInfo *argv)255 JSTaggedValue BuiltinsMath::Cos(EcmaRuntimeCallInfo *argv)
256 {
257 ASSERT(argv);
258 BUILTINS_API_TRACE(argv->GetThread(), Math, Cos);
259 JSThread *thread = argv->GetThread();
260 [[maybe_unused]] EcmaHandleScope handleScope(thread);
261 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
262 JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg);
263 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
264 double value = numberValue.GetNumber();
265 double result = base::NAN_VALUE;
266 // If value is NaN or -NaN, +infinite, -infinite, result is NaN
267 if (std::isfinite(std::abs(value))) {
268 result = std::cos(value);
269 }
270 return GetTaggedDouble(result);
271 }
272
273 // 20.2.2.13
Cosh(EcmaRuntimeCallInfo *argv)274 JSTaggedValue BuiltinsMath::Cosh(EcmaRuntimeCallInfo *argv)
275 {
276 ASSERT(argv);
277 BUILTINS_API_TRACE(argv->GetThread(), Math, Cosh);
278 JSThread *thread = argv->GetThread();
279 [[maybe_unused]] EcmaHandleScope handleScope(thread);
280 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
281 JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg);
282 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
283 double value = numberValue.GetNumber();
284 double result = base::NAN_VALUE;
285 // if value is NaN or -NaN, result is NaN
286 if (!std::isnan(std::abs(value))) {
287 result = std::cosh(value);
288 }
289 return GetTaggedDouble(result);
290 }
291
292 // 20.2.2.14
Exp(EcmaRuntimeCallInfo *argv)293 JSTaggedValue BuiltinsMath::Exp(EcmaRuntimeCallInfo *argv)
294 {
295 ASSERT(argv);
296 BUILTINS_API_TRACE(argv->GetThread(), Math, Exp);
297 JSThread *thread = argv->GetThread();
298 [[maybe_unused]] EcmaHandleScope handleScope(thread);
299 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
300 JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg);
301 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
302 double value = numberValue.GetNumber();
303 double result = base::NAN_VALUE;
304 // if value is NaN or -NaN, result is NaN
305 if (!std::isnan(std::abs(value))) {
306 result = std::exp(value);
307 }
308 return GetTaggedDouble(result);
309 }
310
311 // 20.2.2.15
Expm1(EcmaRuntimeCallInfo *argv)312 JSTaggedValue BuiltinsMath::Expm1(EcmaRuntimeCallInfo *argv)
313 {
314 ASSERT(argv);
315 BUILTINS_API_TRACE(argv->GetThread(), Math, Expm1);
316 JSThread *thread = argv->GetThread();
317 [[maybe_unused]] EcmaHandleScope handleScope(thread);
318 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
319 JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg);
320 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
321 double value = numberValue.GetNumber();
322 double result = base::NAN_VALUE;
323 // if value is NaN or -NaN, result is NaN
324 if (!std::isnan(std::abs(value))) {
325 result = std::expm1(value);
326 }
327 return GetTaggedDouble(result);
328 }
329
330 // 20.2.2.16
Floor(EcmaRuntimeCallInfo *argv)331 JSTaggedValue BuiltinsMath::Floor(EcmaRuntimeCallInfo *argv)
332 {
333 ASSERT(argv);
334 BUILTINS_API_TRACE(argv->GetThread(), Math, Floor);
335 JSThread *thread = argv->GetThread();
336 [[maybe_unused]] EcmaHandleScope handleScope(thread);
337 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
338 JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg);
339 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
340 double value = numberValue.GetNumber();
341 double result = base::NAN_VALUE;
342 // If value is NaN or -NaN, +infinite, -infinite, +0, -0, return value
343 if (!std::isfinite(value) || value == 0) {
344 // If value is -NaN, return NaN, else return value
345 if (!std::isnan(std::abs(value))) {
346 result = value;
347 }
348 } else if (value > 0 && value < 1) {
349 // If x is greater than 0 but less than 1, the result is +0
350 result = 0;
351 } else {
352 result = std::floor(value);
353 }
354 return GetTaggedDouble(result);
355 }
356
357 // 20.2.2.17
Fround(EcmaRuntimeCallInfo *argv)358 JSTaggedValue BuiltinsMath::Fround(EcmaRuntimeCallInfo *argv)
359 {
360 ASSERT(argv);
361 BUILTINS_API_TRACE(argv->GetThread(), Math, Fround);
362 JSThread *thread = argv->GetThread();
363 [[maybe_unused]] EcmaHandleScope handleScope(thread);
364 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
365 JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg);
366 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
367 double value = numberValue.GetNumber();
368 double result;
369 if (std::isnan(std::abs(value))) {
370 // If result is NaN or -NaN, the result is NaN
371 result = base::NAN_VALUE;
372 } else {
373 result = static_cast<float>(value);
374 }
375 return GetTaggedDouble(result);
376 }
377
378 // 20.2.2.18
Hypot(EcmaRuntimeCallInfo *argv)379 JSTaggedValue BuiltinsMath::Hypot(EcmaRuntimeCallInfo *argv)
380 {
381 ASSERT(argv);
382 BUILTINS_API_TRACE(argv->GetThread(), Math, Hypot);
383 JSThread *thread = argv->GetThread();
384 [[maybe_unused]] EcmaHandleScope handleScope(thread);
385 double result = 0;
386 double value = 0;
387 uint32_t argLen = argv->GetArgsNumber();
388 auto numberValue = JSTaggedNumber(0);
389 for (uint32_t i = 0; i < argLen; i++) {
390 JSHandle<JSTaggedValue> msg = GetCallArg(argv, i);
391 numberValue = JSTaggedValue::ToNumber(thread, msg);
392 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
393 value = numberValue.GetNumber();
394 result = std::hypot(result, value);
395 }
396 return GetTaggedDouble(result);
397 }
398
399 // 20.2.2.19
Imul(EcmaRuntimeCallInfo *argv)400 JSTaggedValue BuiltinsMath::Imul(EcmaRuntimeCallInfo *argv)
401 {
402 ASSERT(argv);
403 BUILTINS_API_TRACE(argv->GetThread(), Math, Imul);
404 JSThread *thread = argv->GetThread();
405 [[maybe_unused]] EcmaHandleScope handleScope(thread);
406 JSHandle<JSTaggedValue> msg1 = GetCallArg(argv, 0);
407 JSHandle<JSTaggedValue> msg2 = GetCallArg(argv, 1);
408 JSTaggedNumber numberValue1 = JSTaggedValue::ToNumber(thread, msg1);
409 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
410 JSTaggedNumber numberValue2 = JSTaggedValue::ToNumber(thread, msg2);
411 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
412 auto value1 = numberValue1.GetNumber();
413 auto value2 = numberValue2.GetNumber();
414 if (!std::isfinite(value1) || !std::isfinite(value2)) {
415 // If value is NaN or -NaN, +infinite, -infinite
416 return GetTaggedInt(0);
417 }
418 value1 = numberValue1.ToInt32();
419 value2 = numberValue2.ToInt32();
420 // purposely ignoring overflow
421 auto result = static_cast<int32_t>(static_cast<int64_t>(value1) * static_cast<int64_t>(value2));
422 return GetTaggedInt(result);
423 }
424
425 // 20.2.2.20
Log(EcmaRuntimeCallInfo *argv)426 JSTaggedValue BuiltinsMath::Log(EcmaRuntimeCallInfo *argv)
427 {
428 ASSERT(argv);
429 BUILTINS_API_TRACE(argv->GetThread(), Math, Log);
430 JSThread *thread = argv->GetThread();
431 [[maybe_unused]] EcmaHandleScope handleScope(thread);
432 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
433 JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg);
434 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
435 double value = numberValue.GetNumber();
436 double result = base::NAN_VALUE;
437 // If value is NaN , -NaN , or < 0,result is NaN
438 if (!std::isnan(std::abs(value)) && value >= 0) {
439 result = std::log(value);
440 }
441 return GetTaggedDouble(result);
442 }
443
444 // 20.2.2.21
Log1p(EcmaRuntimeCallInfo *argv)445 JSTaggedValue BuiltinsMath::Log1p(EcmaRuntimeCallInfo *argv)
446 {
447 ASSERT(argv);
448 BUILTINS_API_TRACE(argv->GetThread(), Math, Log1p);
449 JSThread *thread = argv->GetThread();
450 [[maybe_unused]] EcmaHandleScope handleScope(thread);
451 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
452 JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg);
453 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
454 double value = numberValue.GetNumber();
455 double result = base::NAN_VALUE;
456 // If value is NaN , -NaN , or < -1,result is NaN
457 if (!std::isnan(std::abs(value)) && value >= -1) {
458 result = std::log1p(value);
459 }
460 return GetTaggedDouble(result);
461 }
462
463 // 20.2.2.22
Log10(EcmaRuntimeCallInfo *argv)464 JSTaggedValue BuiltinsMath::Log10(EcmaRuntimeCallInfo *argv)
465 {
466 ASSERT(argv);
467 BUILTINS_API_TRACE(argv->GetThread(), Math, Log10);
468 JSThread *thread = argv->GetThread();
469 [[maybe_unused]] EcmaHandleScope handleScope(thread);
470 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
471 JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg);
472 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
473 double value = numberValue.GetNumber();
474 double result = base::NAN_VALUE;
475 // If value is NaN , -NaN , or < 0,result is NaN
476 if (!std::isnan(std::abs(value)) && value >= 0) {
477 result = std::log10(value);
478 }
479 return GetTaggedDouble(result);
480 }
481
482 // 20.2.2.23
Log2(EcmaRuntimeCallInfo *argv)483 JSTaggedValue BuiltinsMath::Log2(EcmaRuntimeCallInfo *argv)
484 {
485 ASSERT(argv);
486 BUILTINS_API_TRACE(argv->GetThread(), Math, Log2);
487 JSThread *thread = argv->GetThread();
488 [[maybe_unused]] EcmaHandleScope handleScope(thread);
489 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
490 JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg);
491 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
492 double value = numberValue.GetNumber();
493 double result = base::NAN_VALUE;
494 // If value is NaN , -NaN , or < 0,result is NaN
495 if (!std::isnan(std::abs(value)) && value >= 0) {
496 result = std::log2(value);
497 }
498 return GetTaggedDouble(result);
499 }
500
IsNegZero(double value)501 inline bool IsNegZero(double value)
502 {
503 return (value == 0.0 && (base::bit_cast<uint64_t>(value) & base::DOUBLE_SIGN_MASK) == base::DOUBLE_SIGN_MASK);
504 }
505
506 // 20.2.2.24
Max(EcmaRuntimeCallInfo *argv)507 JSTaggedValue BuiltinsMath::Max(EcmaRuntimeCallInfo *argv)
508 {
509 ASSERT(argv);
510 BUILTINS_API_TRACE(argv->GetThread(), Math, Max);
511 JSThread *thread = argv->GetThread();
512 [[maybe_unused]] EcmaHandleScope handleScope(thread);
513 uint32_t argLen = argv->GetArgsNumber();
514 auto numberValue = JSTaggedNumber(-base::POSITIVE_INFINITY);
515 // If no arguments are given, the result is -inf
516 auto result = JSTaggedNumber(-base::POSITIVE_INFINITY);
517 auto tmpMax = -base::POSITIVE_INFINITY;
518 auto value = -base::POSITIVE_INFINITY;
519 bool flag = false;
520 uint32_t i = 0;
521 for (; i < argLen; i++) {
522 JSHandle<JSTaggedValue> msg = GetCallArg(argv, i);
523 numberValue = JSTaggedValue::ToNumber(thread, msg);
524 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
525 value = numberValue.GetNumber();
526 if (std::isnan(std::abs(value))) {
527 // If any value is NaN, or -NaN, the max result is NaN
528 result = numberValue;
529 flag = true;
530 i++;
531 break;
532 }
533 if (value > tmpMax) {
534 result = numberValue;
535 tmpMax = value;
536 } else if (value == 0 && tmpMax == 0 && IsNegZero(tmpMax) && !IsNegZero(value)) {
537 // if tmp_max is -0, value is 0, max is 0
538 result = numberValue;
539 tmpMax = value;
540 }
541 }
542 if (flag) {
543 for (; i < argLen; i++) {
544 JSHandle<JSTaggedValue> msg = GetCallArg(argv, i);
545 numberValue = JSTaggedValue::ToNumber(thread, msg);
546 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
547 }
548 }
549 return result;
550 }
551
552 // 20.2.2.25
Min(EcmaRuntimeCallInfo *argv)553 JSTaggedValue BuiltinsMath::Min(EcmaRuntimeCallInfo *argv)
554 {
555 ASSERT(argv);
556 BUILTINS_API_TRACE(argv->GetThread(), Math, Min);
557 JSThread *thread = argv->GetThread();
558 [[maybe_unused]] EcmaHandleScope handleScope(thread);
559 uint32_t argLen = argv->GetArgsNumber();
560 auto numberValue = JSTaggedNumber(base::POSITIVE_INFINITY);
561 // If no arguments are given, the result is inf
562 auto result = JSTaggedNumber(base::POSITIVE_INFINITY);
563 auto tmpMin = base::POSITIVE_INFINITY;
564 auto value = base::POSITIVE_INFINITY;
565 bool flag = false;
566 uint32_t i = 0;
567 for (; i < argLen; i++) {
568 JSHandle<JSTaggedValue> msg = GetCallArg(argv, i);
569 numberValue = JSTaggedValue::ToNumber(thread, msg);
570 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
571 value = numberValue.GetNumber();
572 if (std::isnan(std::abs(value))) {
573 // If any value is NaN or -NaN, the min result is NaN
574 result = numberValue;
575 flag = true;
576 i++;
577 break;
578 }
579 if (value < tmpMin) {
580 result = numberValue;
581 tmpMin = value;
582 } else if (value == 0 && tmpMin == 0 && !IsNegZero(tmpMin) && IsNegZero(value)) {
583 // if tmp_min is 0, value is -0, min is -0
584 result = numberValue;
585 tmpMin = value;
586 }
587 }
588 if (flag) {
589 for (; i < argLen; i++) {
590 JSHandle<JSTaggedValue> msg = GetCallArg(argv, i);
591 numberValue = JSTaggedValue::ToNumber(thread, msg);
592 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
593 }
594 }
595 return result;
596 }
597
598 // 20.2.2.26
Pow(EcmaRuntimeCallInfo *argv)599 JSTaggedValue BuiltinsMath::Pow(EcmaRuntimeCallInfo *argv)
600 {
601 ASSERT(argv);
602 BUILTINS_API_TRACE(argv->GetThread(), Math, Pow);
603 JSThread *thread = argv->GetThread();
604 [[maybe_unused]] EcmaHandleScope handleScope(thread);
605 JSHandle<JSTaggedValue> msgX = GetCallArg(argv, 0);
606 JSHandle<JSTaggedValue> msgY = GetCallArg(argv, 1);
607 JSHandle<JSTaggedValue> baseVale = JSTaggedValue::ToNumeric(thread, msgX);
608 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
609 JSHandle<JSTaggedValue> exponentValue = JSTaggedValue::ToNumeric(thread, msgY);
610 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
611 if (baseVale->IsBigInt() || exponentValue->IsBigInt()) {
612 if (baseVale->IsBigInt() && exponentValue->IsBigInt()) {
613 JSHandle<BigInt> bigBaseVale(baseVale);
614 JSHandle<BigInt> bigExponentValue(exponentValue);
615 return BigInt::Exponentiate(thread, bigBaseVale, bigExponentValue).GetTaggedValue();
616 }
617 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot mix BigInt and other types, use explicit conversions",
618 JSTaggedValue::Exception());
619 }
620 double valueX = baseVale->GetNumber();
621 double valueY = exponentValue->GetNumber();
622 // If abs(x) is 1 and y is inf or -inf, the result is NaN
623 if (std::abs(valueX) == 1 && !std::isfinite(valueY)) {
624 return GetTaggedDouble(base::NAN_VALUE);
625 }
626 double result = std::pow(valueX, valueY);
627 if (std::isnan(std::abs(result))) {
628 // If result is NaN or -NaN, the result is NaN
629 result = base::NAN_VALUE;
630 }
631 return GetTaggedDouble(result);
632 }
633
634 // 20.2.2.27
Random(EcmaRuntimeCallInfo *argv)635 JSTaggedValue BuiltinsMath::Random(EcmaRuntimeCallInfo *argv)
636 {
637 ASSERT(argv);
638 JSThread *thread = argv->GetThread();
639 BUILTINS_API_TRACE(thread, Math, Random);
640 [[maybe_unused]] EcmaHandleScope handleScope(thread);
641 return GetTaggedDouble(RandomGenerator::NextDouble());
642 }
643
644 // 20.2.2.28
Round(EcmaRuntimeCallInfo *argv)645 JSTaggedValue BuiltinsMath::Round(EcmaRuntimeCallInfo *argv)
646 {
647 ASSERT(argv);
648 BUILTINS_API_TRACE(argv->GetThread(), Math, Round);
649 JSThread *thread = argv->GetThread();
650 [[maybe_unused]] EcmaHandleScope handleScope(thread);
651 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
652 JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg);
653 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
654 double value = numberValue.GetNumber();
655 auto result = base::NAN_VALUE;
656 const double diff = 0.5;
657 double absValue = std::abs(value);
658 if (!std::isfinite(absValue) || absValue == 0) {
659 // If value is NaN, +infinite, or -infinite, VRegisterTag is DOUBLE
660 if (!std::isnan(absValue)) {
661 // If value is NaN or -NaN, the result is default NaN, else is value
662 result = value;
663 }
664 return GetTaggedDouble(result);
665 }
666 // If x is less than 0 but greater than or equal to -0.5, the result is -0
667 if (value < 0 && value >= -diff) {
668 return GetTaggedDouble(-0.0);
669 }
670 // If x is greater than 0 but less than 0.5, the result is +0
671 if (value > 0 && value < diff) {
672 return GetTaggedInt(0);
673 }
674 // For huge integers
675 result = std::ceil(value);
676 if (result - value > diff) {
677 result -= 1;
678 }
679 return GetTaggedDouble(result);
680 }
681
682 // 20.2.2.29
Sign(EcmaRuntimeCallInfo *argv)683 JSTaggedValue BuiltinsMath::Sign(EcmaRuntimeCallInfo *argv)
684 {
685 ASSERT(argv);
686 BUILTINS_API_TRACE(argv->GetThread(), Math, Sign);
687 JSThread *thread = argv->GetThread();
688 [[maybe_unused]] EcmaHandleScope handleScope(thread);
689 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
690 JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg);
691 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
692 double value = numberValue.GetNumber();
693 if (std::isnan(std::abs(value))) {
694 return GetTaggedDouble(std::abs(value));
695 }
696 if (value == 0.0) {
697 return GetTaggedDouble(value);
698 }
699 if (value < 0) {
700 return GetTaggedInt(-1);
701 }
702 return GetTaggedInt(1);
703 }
704
705 // 20.2.2.30
Sin(EcmaRuntimeCallInfo *argv)706 JSTaggedValue BuiltinsMath::Sin(EcmaRuntimeCallInfo *argv)
707 {
708 ASSERT(argv);
709 BUILTINS_API_TRACE(argv->GetThread(), Math, Sin);
710 JSThread *thread = argv->GetThread();
711 [[maybe_unused]] EcmaHandleScope handleScope(thread);
712 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
713 JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg);
714 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
715 double value = numberValue.GetNumber();
716 double result = base::NAN_VALUE;
717 // If value is NaN or -NaN, the result is NaN
718 if (std::isfinite(std::abs(value))) {
719 result = std::sin(value);
720 }
721 return GetTaggedDouble(result);
722 }
723
724 // 20.2.2.31
Sinh(EcmaRuntimeCallInfo *argv)725 JSTaggedValue BuiltinsMath::Sinh(EcmaRuntimeCallInfo *argv)
726 {
727 ASSERT(argv);
728 BUILTINS_API_TRACE(argv->GetThread(), Math, Sinh);
729 JSThread *thread = argv->GetThread();
730 [[maybe_unused]] EcmaHandleScope handleScope(thread);
731 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
732 JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg);
733 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
734 double value = numberValue.GetNumber();
735 double result = base::NAN_VALUE;
736 // If value is NaN or -NaN, the result is NaN
737 if (!std::isnan(std::abs(value))) {
738 result = std::sinh(value);
739 }
740 return GetTaggedDouble(result);
741 }
742
743 // 20.2.2.32
Sqrt(EcmaRuntimeCallInfo *argv)744 JSTaggedValue BuiltinsMath::Sqrt(EcmaRuntimeCallInfo *argv)
745 {
746 ASSERT(argv);
747 BUILTINS_API_TRACE(argv->GetThread(), Math, Sqrt);
748 JSThread *thread = argv->GetThread();
749 [[maybe_unused]] EcmaHandleScope handleScope(thread);
750 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
751 JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg);
752 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
753 double value = numberValue.GetNumber();
754 double result = base::NAN_VALUE;
755 // If value is negative, include -NaN and -Infinity but not -0.0, the result is NaN
756 if (std::signbit(value) && value != 0) {
757 return GetTaggedDouble(result);
758 }
759 // If value is NaN, the result is NaN
760 if (!std::isnan(value)) {
761 result = std::sqrt(value);
762 }
763 return GetTaggedDouble(result);
764 }
765
766 // 20.2.2.33
Tan(EcmaRuntimeCallInfo *argv)767 JSTaggedValue BuiltinsMath::Tan(EcmaRuntimeCallInfo *argv)
768 {
769 ASSERT(argv);
770 BUILTINS_API_TRACE(argv->GetThread(), Math, Tan);
771 JSThread *thread = argv->GetThread();
772 [[maybe_unused]] EcmaHandleScope handleScope(thread);
773 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
774 JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg);
775 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
776 double value = numberValue.GetNumber();
777 double result = base::NAN_VALUE;
778 // If value is NaN or -NaN, +infinite, -infinite, result is NaN
779 if (std::isfinite(value)) {
780 result = std::tan(value);
781 }
782 return GetTaggedDouble(result);
783 }
784
785 // 20.2.2.34
Tanh(EcmaRuntimeCallInfo *argv)786 JSTaggedValue BuiltinsMath::Tanh(EcmaRuntimeCallInfo *argv)
787 {
788 ASSERT(argv);
789 BUILTINS_API_TRACE(argv->GetThread(), Math, Tanh);
790 JSThread *thread = argv->GetThread();
791 [[maybe_unused]] EcmaHandleScope handleScope(thread);
792 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
793 JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg);
794 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
795 double value = numberValue.GetNumber();
796 double result = base::NAN_VALUE;
797 if (!std::isnan(std::abs(value))) {
798 result = std::tanh(value);
799 }
800 return GetTaggedDouble(result);
801 }
802
803 // 20.2.2.35
Trunc(EcmaRuntimeCallInfo *argv)804 JSTaggedValue BuiltinsMath::Trunc(EcmaRuntimeCallInfo *argv)
805 {
806 ASSERT(argv);
807 BUILTINS_API_TRACE(argv->GetThread(), Math, Trunc);
808 JSThread *thread = argv->GetThread();
809 [[maybe_unused]] EcmaHandleScope handleScope(thread);
810 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
811 JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg);
812 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
813 double value = numberValue.GetNumber();
814 double result = base::NAN_VALUE;
815 if (!std::isfinite(value)) {
816 // if value is +infinite, -infinite, NaN, -NaN, VRegisterTag is double
817 if (!std::isnan(std::abs(value))) {
818 // if value is +infinite, -infinite, result is value
819 result = value;
820 }
821 } else {
822 result = std::trunc(value);
823 }
824 return GetTaggedDouble(result);
825 }
826 } // namespace panda::ecmascript::builtins
827