1/*
2 * Copyright (c) 2024 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
16declare function print(arg:any):string;
17declare interface ArkTools {
18    isAOTCompiled(args: any): boolean;
19}
20function replace(a : number, b : number)
21{
22    return a;
23}
24
25function doImul(x: any, y: any): number {
26    return Math.imul(x, y);
27}
28
29function printImul(x: any, y: any) {
30    try {
31        print(doImul(x, y));
32    } finally {
33    }
34}
35
36let len:number = 1;
37
38len = Math.imul(2, 3)
39//aot: [trace] aot inline builtin: Math.imul, caller function name:func_main_0@builtinMathImul
40print(len) //: 6
41
42// Check without params
43len = Math.imul();
44//aot: [trace] aot inline builtin: Math.imul, caller function name:func_main_0@builtinMathImul
45print(len); //: 0
46
47// Check with single param
48len = Math.imul(0);
49//aot: [trace] aot inline builtin: Math.imul, caller function name:func_main_0@builtinMathImul
50print(len); //: 0
51
52// Check with three param
53len = Math.imul(2, 4, 6);
54//aot: [trace] aot inline builtin: Math.imul, caller function name:func_main_0@builtinMathImul
55print(len); //: 8
56
57// If an input is NaN, return 0
58len = Math.imul(2, NaN)
59//aot: [trace] aot inline builtin: Math.imul, caller function name:func_main_0@builtinMathImul
60print(len) //: 0
61
62// Check with 0
63len = Math.imul(3, +0.0);
64//aot: [trace] aot inline builtin: Math.imul, caller function name:func_main_0@builtinMathImul
65print(len); //: 0
66
67len = Math.imul(3, -0.0);
68//aot: [trace] aot inline builtin: Math.imul, caller function name:func_main_0@builtinMathImul
69print(len); //: 0
70
71// If an input is Infinity or -Infinity, return 0
72len = Math.imul(-Infinity, 5);
73//aot: [trace] aot inline builtin: Math.imul, caller function name:func_main_0@builtinMathImul
74print(len); //: 0
75len = Math.imul(Infinity, 6);
76//aot: [trace] aot inline builtin: Math.imul, caller function name:func_main_0@builtinMathImul
77print(len); //: 0
78len = Math.imul(3, -Infinity);
79//aot: [trace] aot inline builtin: Math.imul, caller function name:func_main_0@builtinMathImul
80print(len); //: 0
81len = Math.imul(5, Infinity);
82//aot: [trace] aot inline builtin: Math.imul, caller function name:func_main_0@builtinMathImul
83print(len); //: 0
84
85// Check int
86len = Math.imul(-2, -10);
87//aot: [trace] aot inline builtin: Math.imul, caller function name:func_main_0@builtinMathImul
88print(len); //: 20
89len = Math.imul(5, 10000);
90//aot: [trace] aot inline builtin: Math.imul, caller function name:func_main_0@builtinMathImul
91print(len); //: 50000
92len = Math.imul(-600, -20);
93//aot: [trace] aot inline builtin: Math.imul, caller function name:func_main_0@builtinMathImul
94print(len); //: 12000
95
96// Check double
97len = Math.imul(5.3, 2.7);
98//aot: [trace] aot inline builtin: Math.imul, caller function name:func_main_0@builtinMathImul
99print(len); //: 10
100len = Math.imul(-2.4, -4.7);
101//aot: [trace] aot inline builtin: Math.imul, caller function name:func_main_0@builtinMathImul
102print(len); //: 8
103
104len = Math.imul(-7.3, 6.2);
105//aot: [trace] aot inline builtin: Math.imul, caller function name:func_main_0@builtinMathImul
106print(len); //: -42
107
108//big double
109len = Math.imul(2, 1.9e80);
110//aot: [trace] aot inline builtin: Math.imul, caller function name:func_main_0@builtinMathImul
111print(len); //: 0
112
113//small double
114len = Math.imul(2, 1.9e-80);
115//aot: [trace] aot inline builtin: Math.imul, caller function name:func_main_0@builtinMathImul
116print(len); //: 0
117
118
119// Check edge cases
120const INT_MAX: number = 2147483647;
121const INT_MIN: number = -INT_MAX - 1;
122//aot: [trace] aot inline builtin: Math.imul, caller function name:func_main_0@builtinMathImul
123print(Math.imul(INT_MAX, 1)); //: 2147483647
124//aot: [trace] aot inline builtin: Math.imul, caller function name:func_main_0@builtinMathImul
125print(Math.imul(2147483648 , 2)); //: 0
126//aot: [trace] aot inline builtin: Math.imul, caller function name:func_main_0@builtinMathImul
127print(Math.imul(-INT_MAX, 2)); //: 2
128//aot: [trace] aot inline builtin: Math.imul, caller function name:func_main_0@builtinMathImul
129print(Math.imul(INT_MIN, 2)); //: 0
130//aot: [trace] aot inline builtin: Math.imul, caller function name:func_main_0@builtinMathImul
131print(Math.imul(INT_MIN - 1, 2)); //: -2
132
133len = Math.imul(2, "three");
134//aot: [trace] aot inline builtin: Math.imul, caller function name:func_main_0@builtinMathImul
135//aot: [trace] Check Type: NotNumber1
136print(len); //: 0
137
138// Replace standard builtin
139let true_imul = Math.imul
140Math.imul= replace
141print(Math.imul(2, 40)); //: 2
142Math.imul = true_imul
143
144len = Math.imul(3, 3)
145print(len) //: 9
146//aot: [trace] aot inline builtin: Math.imul, caller function name:#*#doImul@builtinMathImul
147printImul(-12, 2); //: -24
148// Call standard builtin with non-number param
149//aot: [trace] aot inline builtin: Math.imul, caller function name:#*#doImul@builtinMathImul
150//aot: [trace] Check Type: NotNumber1
151printImul("abc", 2); //: 0
152//aot: [trace] aot inline builtin: Math.imul, caller function name:#*#doImul@builtinMathImul
153//aot: [trace] Check Type: NotNumber1
154printImul("-12", 2); //: -24
155
156if (ArkTools.isAOTCompiled(printImul)) {
157    // Replace standard builtin after call to standard builtin was profiled
158    Math.imul= replace
159}
160printImul(-12, 2); //pgo: -24
161//aot: [trace] Check Type: NotCallTarget1
162//aot: -12
163printImul("abc", 2); //pgo: 0
164//aot: [trace] Check Type: NotCallTarget1
165//aot: abc
166
167Math.imul = true_imul
168
169// Check IR correctness inside try-block
170try {
171    //aot: [trace] aot inline builtin: Math.imul, caller function name:#*#doImul@builtinMathImul
172    printImul(-12, 2); //: -24
173    //aot: [trace] aot inline builtin: Math.imul, caller function name:#*#doImul@builtinMathImul
174    //aot: [trace] Check Type: NotNumber1
175    printImul("abc", 2); //: 0
176} catch (e) {
177}
178
179let obj = {};
180obj.valueOf = (() => { return -23; })
181//aot: [trace] aot inline builtin: Math.imul, caller function name:#*#doImul@builtinMathImul
182//aot: [trace] Check Type: NotNumber1
183printImul(obj, -2); //: 46
184
185function Throwing() {
186    this.value = -14;
187}
188Throwing.prototype.valueOf = function() {
189    if (this.value > 0) {
190        throw new Error("already positive");
191    }
192    return this.value;
193}
194let throwingObj = new Throwing();
195
196try {
197    print(Math.imul(throwingObj, 2)); //: -28
198    throwingObj.value = 10;
199    print(Math.imul(throwingObj), 2); //: Error: already positive
200} catch(e) {
201    print(e);
202} finally {
203    print(Math.imul(obj, 2)); //: -46
204}
205