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