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