• 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 "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