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