• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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