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