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