1 /*
2  * Copyright (c) 2022 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/compiler/operations_stub_builder.h"
17 #include "ecmascript/compiler/interpreter_stub-inl.h"
18 #include "ecmascript/compiler/rt_call_signature.h"
19 #include "ecmascript/compiler/stub_builder-inl.h"
20 
21 namespace panda::ecmascript::kungfu {
Equal(GateRef glue, GateRef left, GateRef right, ProfileOperation callback)22 GateRef OperationsStubBuilder::Equal(GateRef glue, GateRef left, GateRef right, ProfileOperation callback)
23 {
24     auto env = GetEnvironment();
25     Label entry(env);
26     env->SubCfgEntry(&entry);
27     Label exit(env);
28     Label isHole(env);
29     Label notHole(env);
30     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
31     result = FastEqual(glue, left, right, callback);
32     BRANCH(TaggedIsHole(*result), &isHole, &notHole);
33     Bind(&isHole);
34     {
35         // slow path
36         result = CallRuntime(glue, RTSTUB_ID(Eq), { left, right });
37         Jump(&exit);
38     }
39     Bind(&notHole);
40     {
41         Label resultIsTrue(env);
42         Label resultNotTrue(env);
43         BRANCH(TaggedIsTrue(*result), &resultIsTrue, &resultNotTrue);
44         Bind(&resultIsTrue);
45         {
46             callback.ProfileBranch(true);
47             Jump(&exit);
48         }
49         Bind(&resultNotTrue);
50         {
51             callback.ProfileBranch(false);
52             Jump(&exit);
53         }
54     }
55     Bind(&exit);
56     auto ret = *result;
57     env->SubCfgExit();
58     return ret;
59 }
60 
NotEqual(GateRef glue, GateRef left, GateRef right, ProfileOperation callback)61 GateRef OperationsStubBuilder::NotEqual(GateRef glue, GateRef left, GateRef right, ProfileOperation callback)
62 {
63     auto env = GetEnvironment();
64     Label entry(env);
65     env->SubCfgEntry(&entry);
66     Label exit(env);
67 
68     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
69     result = FastEqual(glue, left, right, callback);
70     Label isHole(env);
71     Label notHole(env);
72     BRANCH(TaggedIsHole(*result), &isHole, &notHole);
73     Bind(&isHole);
74     {
75         // slow path
76         result = CallRuntime(glue, RTSTUB_ID(NotEq), { left, right });
77         Jump(&exit);
78     }
79     Bind(&notHole);
80     {
81         Label resultIsTrue(env);
82         Label resultNotTrue(env);
83         BRANCH(TaggedIsTrue(*result), &resultIsTrue, &resultNotTrue);
84         Bind(&resultIsTrue);
85         {
86             result = TaggedFalse();
87             callback.ProfileBranch(false);
88             Jump(&exit);
89         }
90         Bind(&resultNotTrue);
91         {
92             callback.ProfileBranch(true);
93             result = TaggedTrue();
94             Jump(&exit);
95         }
96     }
97     Bind(&exit);
98     auto ret = *result;
99     env->SubCfgExit();
100     return ret;
101 }
102 
StrictEqual(GateRef glue, GateRef left, GateRef right, ProfileOperation callback)103 GateRef OperationsStubBuilder::StrictEqual(GateRef glue, GateRef left, GateRef right, ProfileOperation callback)
104 {
105     auto env = GetEnvironment();
106     Label entry(env);
107     env->SubCfgEntry(&entry);
108     Label exit(env);
109     Label strictEqual(env);
110     Label notStrictEqual(env);
111     DEFVARIABLE(result, VariableType::JS_ANY(), TaggedTrue());
112     BRANCH(FastStrictEqual(glue, left, right, callback), &strictEqual, &notStrictEqual);
113     Bind(&strictEqual);
114     {
115         callback.ProfileBranch(true);
116         Jump(&exit);
117     }
118     Bind(&notStrictEqual);
119     {
120         result = TaggedFalse();
121         callback.ProfileBranch(false);
122         Jump(&exit);
123     }
124     Bind(&exit);
125     auto ret = *result;
126     env->SubCfgExit();
127     return ret;
128 }
129 
StrictNotEqual(GateRef glue, GateRef left, GateRef right, ProfileOperation callback)130 GateRef OperationsStubBuilder::StrictNotEqual(GateRef glue, GateRef left, GateRef right, ProfileOperation callback)
131 {
132     auto env = GetEnvironment();
133     Label entry(env);
134     env->SubCfgEntry(&entry);
135     Label exit(env);
136     Label strictEqual(env);
137     Label notStrictEqual(env);
138     DEFVARIABLE(result, VariableType::JS_ANY(), TaggedTrue());
139     BRANCH(FastStrictEqual(glue, left, right, callback), &strictEqual, &notStrictEqual);
140     Bind(&strictEqual);
141     {
142         result = TaggedFalse();
143         callback.ProfileBranch(false);
144         Jump(&exit);
145     }
146     Bind(&notStrictEqual);
147     {
148         callback.ProfileBranch(true);
149         Jump(&exit);
150     }
151     Bind(&exit);
152     auto ret = *result;
153     env->SubCfgExit();
154     return ret;
155 }
156 
Less(GateRef glue, GateRef left, GateRef right, ProfileOperation callback)157 GateRef OperationsStubBuilder::Less(GateRef glue, GateRef left, GateRef right, ProfileOperation callback)
158 {
159     auto env = GetEnvironment();
160     Label entry(env);
161     env->SubCfgEntry(&entry);
162     Label exit(env);
163     Label leftIsInt(env);
164     Label leftOrRightNotInt(env);
165     Label leftLessRight(env);
166     Label leftNotLessRight(env);
167     Label slowPath(env);
168 
169     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
170     BRANCH(TaggedIsInt(left), &leftIsInt, &leftOrRightNotInt);
171     Bind(&leftIsInt);
172     {
173         Label rightIsInt(env);
174         BRANCH(TaggedIsInt(right), &rightIsInt, &leftOrRightNotInt);
175         Bind(&rightIsInt);
176         {
177             callback.ProfileOpType(TaggedInt(PGOSampleType::IntType()));
178             GateRef intLeft = TaggedGetInt(left);
179             GateRef intRight = TaggedGetInt(right);
180             BRANCH(Int32LessThan(intLeft, intRight), &leftLessRight, &leftNotLessRight);
181         }
182     }
183     Bind(&leftOrRightNotInt);
184     {
185         Label leftIsNumber(env);
186         BRANCH(TaggedIsNumber(left), &leftIsNumber, &slowPath);
187         Bind(&leftIsNumber);
188         {
189             Label rightIsNumber(env);
190             BRANCH(TaggedIsNumber(right), &rightIsNumber, &slowPath);
191             Bind(&rightIsNumber);
192             {
193                 // fast path
194                 DEFVARIABLE(doubleLeft, VariableType::FLOAT64(), Double(0));
195                 DEFVARIABLE(doubleRight, VariableType::FLOAT64(), Double(0));
196                 DEFVARIABLE(curType, VariableType::INT64(), TaggedInt(PGOSampleType::IntType()));
197                 Label leftIsInt1(env);
198                 Label leftNotInt1(env);
199                 Label exit1(env);
200                 Label exit2(env);
201                 Label rightIsInt1(env);
202                 Label rightNotInt1(env);
203                 BRANCH(TaggedIsInt(left), &leftIsInt1, &leftNotInt1);
204                 Bind(&leftIsInt1);
205                 {
206                     doubleLeft = ChangeInt32ToFloat64(TaggedGetInt(left));
207                     Jump(&exit1);
208                 }
209                 Bind(&leftNotInt1);
210                 {
211                     curType = TaggedInt(PGOSampleType::DoubleType());
212                     doubleLeft = GetDoubleOfTDouble(left);
213                     Jump(&exit1);
214                 }
215                 Bind(&exit1);
216                 {
217                     BRANCH(TaggedIsInt(right), &rightIsInt1, &rightNotInt1);
218                 }
219                 Bind(&rightIsInt1);
220                 {
221                     GateRef type = TaggedInt(PGOSampleType::IntType());
222                     COMBINE_TYPE_CALL_BACK(curType, type);
223                     doubleRight = ChangeInt32ToFloat64(TaggedGetInt(right));
224                     Jump(&exit2);
225                 }
226                 Bind(&rightNotInt1);
227                 {
228                     GateRef type = TaggedInt(PGOSampleType::DoubleType());
229                     COMBINE_TYPE_CALL_BACK(curType, type);
230                     doubleRight = GetDoubleOfTDouble(right);
231                     Jump(&exit2);
232                 }
233                 Bind(&exit2);
234                 {
235                     BRANCH(DoubleLessThan(*doubleLeft, *doubleRight), &leftLessRight, &leftNotLessRight);
236                 }
237             }
238         }
239     }
240     Bind(&leftLessRight);
241     {
242         callback.ProfileBranch(true);
243         result = TaggedTrue();
244         Jump(&exit);
245     }
246     Bind(&leftNotLessRight);
247     {
248         callback.ProfileBranch(false);
249         result = TaggedFalse();
250         Jump(&exit);
251     }
252     Bind(&slowPath);
253     {
254         callback.ProfileOpType(TaggedInt(PGOSampleType::AnyType()));
255         result = CallRuntime(glue, RTSTUB_ID(Less), { left, right });
256         Jump(&exit);
257     }
258     Bind(&exit);
259     auto ret = *result;
260     env->SubCfgExit();
261     return ret;
262 }
263 
LessEq(GateRef glue, GateRef left, GateRef right, ProfileOperation callback)264 GateRef OperationsStubBuilder::LessEq(GateRef glue, GateRef left, GateRef right, ProfileOperation callback)
265 {
266     auto env = GetEnvironment();
267     Label entry(env);
268     env->SubCfgEntry(&entry);
269     Label exit(env);
270     Label leftIsInt(env);
271     Label leftOrRightNotInt(env);
272     Label leftLessEqRight(env);
273     Label leftNotLessEqRight(env);
274     Label slowPath(env);
275 
276     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
277     BRANCH(TaggedIsInt(left), &leftIsInt, &leftOrRightNotInt);
278     Bind(&leftIsInt);
279     {
280         Label rightIsInt(env);
281         BRANCH(TaggedIsInt(right), &rightIsInt, &leftOrRightNotInt);
282         Bind(&rightIsInt);
283         {
284             callback.ProfileOpType(TaggedInt(PGOSampleType::IntType()));
285             GateRef intLeft = TaggedGetInt(left);
286             GateRef intRight = TaggedGetInt(right);
287             BRANCH(Int32LessThanOrEqual(intLeft, intRight), &leftLessEqRight, &leftNotLessEqRight);
288         }
289     }
290     Bind(&leftOrRightNotInt);
291     {
292         Label leftIsNumber(env);
293         BRANCH(TaggedIsNumber(left), &leftIsNumber, &slowPath);
294         Bind(&leftIsNumber);
295         {
296             Label rightIsNumber(env);
297             BRANCH(TaggedIsNumber(right), &rightIsNumber, &slowPath);
298             Bind(&rightIsNumber);
299             {
300                 // fast path
301                 DEFVARIABLE(doubleLeft, VariableType::FLOAT64(), Double(0));
302                 DEFVARIABLE(doubleRight, VariableType::FLOAT64(), Double(0));
303                 DEFVARIABLE(curType, VariableType::INT64(), TaggedInt(PGOSampleType::IntType()));
304                 Label leftIsInt1(env);
305                 Label leftNotInt1(env);
306                 Label exit1(env);
307                 Label exit2(env);
308                 Label rightIsInt1(env);
309                 Label rightNotInt1(env);
310                 BRANCH(TaggedIsInt(left), &leftIsInt1, &leftNotInt1);
311                 Bind(&leftIsInt1);
312                 {
313                     doubleLeft = ChangeInt32ToFloat64(TaggedGetInt(left));
314                     Jump(&exit1);
315                 }
316                 Bind(&leftNotInt1);
317                 {
318                     curType = TaggedInt(PGOSampleType::DoubleType());
319                     doubleLeft = GetDoubleOfTDouble(left);
320                     Jump(&exit1);
321                 }
322                 Bind(&exit1);
323                 {
324                     BRANCH(TaggedIsInt(right), &rightIsInt1, &rightNotInt1);
325                 }
326                 Bind(&rightIsInt1);
327                 {
328                     GateRef type = TaggedInt(PGOSampleType::IntType());
329                     COMBINE_TYPE_CALL_BACK(curType, type);
330                     doubleRight = ChangeInt32ToFloat64(TaggedGetInt(right));
331                     Jump(&exit2);
332                 }
333                 Bind(&rightNotInt1);
334                 {
335                     GateRef type = TaggedInt(PGOSampleType::DoubleType());
336                     COMBINE_TYPE_CALL_BACK(curType, type);
337                     doubleRight = GetDoubleOfTDouble(right);
338                     Jump(&exit2);
339                 }
340                 Bind(&exit2);
341                 {
342                     BRANCH(DoubleLessThanOrEqual(*doubleLeft, *doubleRight), &leftLessEqRight, &leftNotLessEqRight);
343                 }
344             }
345         }
346     }
347     Bind(&leftLessEqRight);
348     {
349         callback.ProfileBranch(true);
350         result = TaggedTrue();
351         Jump(&exit);
352     }
353     Bind(&leftNotLessEqRight);
354     {
355         callback.ProfileBranch(false);
356         result = TaggedFalse();
357         Jump(&exit);
358     }
359     Bind(&slowPath);
360     {
361         callback.ProfileOpType(TaggedInt(PGOSampleType::AnyType()));
362         result = CallRuntime(glue, RTSTUB_ID(LessEq), { left, right });
363         Jump(&exit);
364     }
365     Bind(&exit);
366     auto ret = *result;
367     env->SubCfgExit();
368     return ret;
369 }
370 
Greater(GateRef glue, GateRef left, GateRef right, ProfileOperation callback)371 GateRef OperationsStubBuilder::Greater(GateRef glue, GateRef left, GateRef right, ProfileOperation callback)
372 {
373     auto env = GetEnvironment();
374     Label entry(env);
375     env->SubCfgEntry(&entry);
376     Label exit(env);
377     Label leftIsInt(env);
378     Label leftOrRightNotInt(env);
379     Label leftGreaterRight(env);
380     Label leftNotGreaterRight(env);
381     Label slowPath(env);
382     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
383     BRANCH(TaggedIsInt(left), &leftIsInt, &leftOrRightNotInt);
384     Bind(&leftIsInt);
385     {
386         Label rightIsInt(env);
387         BRANCH(TaggedIsInt(right), &rightIsInt, &leftOrRightNotInt);
388         Bind(&rightIsInt);
389         {
390             callback.ProfileOpType(TaggedInt(PGOSampleType::IntType()));
391             GateRef intLeft = TaggedGetInt(left);
392             GateRef intRight = TaggedGetInt(right);
393             BRANCH(Int32GreaterThan(intLeft, intRight), &leftGreaterRight, &leftNotGreaterRight);
394         }
395     }
396     Bind(&leftOrRightNotInt);
397     {
398         Label leftIsNumber(env);
399         BRANCH(TaggedIsNumber(left), &leftIsNumber, &slowPath);
400         Bind(&leftIsNumber);
401         {
402             Label rightIsNumber(env);
403             BRANCH(TaggedIsNumber(right), &rightIsNumber, &slowPath);
404             Bind(&rightIsNumber);
405             {
406                 // fast path
407                 DEFVARIABLE(doubleLeft, VariableType::FLOAT64(), Double(0));
408                 DEFVARIABLE(doubleRight, VariableType::FLOAT64(), Double(0));
409                 DEFVARIABLE(curType, VariableType::INT64(), TaggedInt(PGOSampleType::IntType()));
410                 Label leftIsInt1(env);
411                 Label leftNotInt1(env);
412                 Label exit1(env);
413                 Label exit2(env);
414                 Label rightIsInt1(env);
415                 Label rightNotInt1(env);
416                 BRANCH(TaggedIsInt(left), &leftIsInt1, &leftNotInt1);
417                 Bind(&leftIsInt1);
418                 {
419                     doubleLeft = ChangeInt32ToFloat64(TaggedGetInt(left));
420                     Jump(&exit1);
421                 }
422                 Bind(&leftNotInt1);
423                 {
424                     curType = TaggedInt(PGOSampleType::DoubleType());
425                     doubleLeft = GetDoubleOfTDouble(left);
426                     Jump(&exit1);
427                 }
428                 Bind(&exit1);
429                 {
430                     BRANCH(TaggedIsInt(right), &rightIsInt1, &rightNotInt1);
431                 }
432                 Bind(&rightIsInt1);
433                 {
434                     GateRef type = TaggedInt(PGOSampleType::IntType());
435                     COMBINE_TYPE_CALL_BACK(curType, type);
436                     doubleRight = ChangeInt32ToFloat64(TaggedGetInt(right));
437                     Jump(&exit2);
438                 }
439                 Bind(&rightNotInt1);
440                 {
441                     GateRef type = TaggedInt(PGOSampleType::DoubleType());
442                     COMBINE_TYPE_CALL_BACK(curType, type);
443                     doubleRight = GetDoubleOfTDouble(right);
444                     Jump(&exit2);
445                 }
446                 Bind(&exit2);
447                 {
448                     BRANCH(DoubleGreaterThan(*doubleLeft, *doubleRight), &leftGreaterRight, &leftNotGreaterRight);
449                 }
450             }
451         }
452     }
453     Bind(&leftGreaterRight);
454     {
455         callback.ProfileBranch(true);
456         result = TaggedTrue();
457         Jump(&exit);
458     }
459     Bind(&leftNotGreaterRight);
460     {
461         callback.ProfileBranch(false);
462         result = TaggedFalse();
463         Jump(&exit);
464     }
465     Bind(&slowPath);
466     {
467         callback.ProfileOpType(TaggedInt(PGOSampleType::AnyType()));
468         result = CallRuntime(glue, RTSTUB_ID(Greater), { left, right });
469         Jump(&exit);
470     }
471     Bind(&exit);
472     auto ret = *result;
473     env->SubCfgExit();
474     return ret;
475 }
476 
GreaterEq(GateRef glue, GateRef left, GateRef right, ProfileOperation callback)477 GateRef OperationsStubBuilder::GreaterEq(GateRef glue, GateRef left, GateRef right, ProfileOperation callback)
478 {
479     auto env = GetEnvironment();
480     Label entry(env);
481     env->SubCfgEntry(&entry);
482     Label exit(env);
483     Label leftIsInt(env);
484     Label leftOrRightNotInt(env);
485     Label leftGreaterEqRight(env);
486     Label leftNotGreaterEQRight(env);
487     Label slowPath(env);
488     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
489     BRANCH(TaggedIsInt(left), &leftIsInt, &leftOrRightNotInt);
490     Bind(&leftIsInt);
491     {
492         Label rightIsInt(env);
493         BRANCH(TaggedIsInt(right), &rightIsInt, &leftOrRightNotInt);
494         Bind(&rightIsInt);
495         {
496             callback.ProfileOpType(TaggedInt(PGOSampleType::IntType()));
497             GateRef intLeft = TaggedGetInt(left);
498             GateRef intRight = TaggedGetInt(right);
499             BRANCH(Int32GreaterThanOrEqual(intLeft, intRight), &leftGreaterEqRight, &leftNotGreaterEQRight);
500         }
501     }
502     Bind(&leftOrRightNotInt);
503     {
504         Label leftIsNumber(env);
505         BRANCH(TaggedIsNumber(left), &leftIsNumber, &slowPath);
506         Bind(&leftIsNumber);
507         {
508             Label rightIsNumber(env);
509             BRANCH(TaggedIsNumber(right), &rightIsNumber, &slowPath);
510             Bind(&rightIsNumber);
511             {
512                 // fast path
513                 DEFVARIABLE(doubleLeft, VariableType::FLOAT64(), Double(0));
514                 DEFVARIABLE(doubleRight, VariableType::FLOAT64(), Double(0));
515                 DEFVARIABLE(curType, VariableType::INT64(), TaggedInt(PGOSampleType::IntType()));
516                 Label leftIsInt1(env);
517                 Label leftNotInt1(env);
518                 Label exit1(env);
519                 Label exit2(env);
520                 Label rightIsInt1(env);
521                 Label rightNotInt1(env);
522                 BRANCH(TaggedIsInt(left), &leftIsInt1, &leftNotInt1);
523                 Bind(&leftIsInt1);
524                 {
525                     doubleLeft = ChangeInt32ToFloat64(TaggedGetInt(left));
526                     Jump(&exit1);
527                 }
528                 Bind(&leftNotInt1);
529                 {
530                     curType = TaggedInt(PGOSampleType::DoubleType());
531                     doubleLeft = GetDoubleOfTDouble(left);
532                     Jump(&exit1);
533                 }
534                 Bind(&exit1);
535                 {
536                     BRANCH(TaggedIsInt(right), &rightIsInt1, &rightNotInt1);
537                 }
538                 Bind(&rightIsInt1);
539                 {
540                     GateRef type = TaggedInt(PGOSampleType::IntType());
541                     COMBINE_TYPE_CALL_BACK(curType, type);
542                     doubleRight = ChangeInt32ToFloat64(TaggedGetInt(right));
543                     Jump(&exit2);
544                 }
545                 Bind(&rightNotInt1);
546                 {
547                     GateRef type = TaggedInt(PGOSampleType::DoubleType());
548                     COMBINE_TYPE_CALL_BACK(curType, type);
549                     doubleRight = GetDoubleOfTDouble(right);
550                     Jump(&exit2);
551                 }
552                 Bind(&exit2);
553                 {
554                     BRANCH(DoubleGreaterThanOrEqual(*doubleLeft, *doubleRight),
555                         &leftGreaterEqRight, &leftNotGreaterEQRight);
556                 }
557             }
558         }
559     }
560     Bind(&leftGreaterEqRight);
561     {
562         callback.ProfileBranch(true);
563         result = TaggedTrue();
564         Jump(&exit);
565     }
566     Bind(&leftNotGreaterEQRight);
567     {
568         callback.ProfileBranch(false);
569         result = TaggedFalse();
570         Jump(&exit);
571     }
572     Bind(&slowPath);
573     {
574         callback.ProfileOpType(TaggedInt(PGOSampleType::AnyType()));
575         result = CallRuntime(glue, RTSTUB_ID(GreaterEq), { left, right });
576         Jump(&exit);
577     }
578     Bind(&exit);
579     auto ret = *result;
580     env->SubCfgExit();
581     return ret;
582 }
583 
Add(GateRef glue, GateRef left, GateRef right, ProfileOperation callback)584 GateRef OperationsStubBuilder::Add(GateRef glue, GateRef left, GateRef right, ProfileOperation callback)
585 {
586     auto env = GetEnvironment();
587     Label entry(env);
588     env->SubCfgEntry(&entry);
589     Label exit(env);
590     Label slowPath(env);
591     DEFVARIABLE(result, VariableType::JS_ANY(), FastAdd(glue, left, right, callback));
592     BRANCH(TaggedIsHole(*result), &slowPath, &exit);
593     Bind(&slowPath);
594     {
595         callback.ProfileOpType(TaggedInt(PGOSampleType::AnyType()));
596         result = CallRuntime(glue, RTSTUB_ID(Add2), { left, right });
597         Jump(&exit);
598     }
599     Bind(&exit);
600     auto ret = *result;
601     env->SubCfgExit();
602     return ret;
603 }
604 
Sub(GateRef glue, GateRef left, GateRef right, ProfileOperation callback)605 GateRef OperationsStubBuilder::Sub(GateRef glue, GateRef left, GateRef right, ProfileOperation callback)
606 {
607     auto env = GetEnvironment();
608     Label entry(env);
609     env->SubCfgEntry(&entry);
610     Label exit(env);
611     Label slowPath(env);
612     DEFVARIABLE(result, VariableType::JS_ANY(), FastSub(glue, left, right, callback));
613     BRANCH(TaggedIsHole(*result), &slowPath, &exit);
614     Bind(&slowPath);
615     {
616         callback.ProfileOpType(TaggedInt(PGOSampleType::AnyType()));
617         result = CallRuntime(glue, RTSTUB_ID(Sub2), { left, right });
618         Jump(&exit);
619     }
620     Bind(&exit);
621     auto ret = *result;
622     env->SubCfgExit();
623     return ret;
624 }
625 
Mul(GateRef glue, GateRef left, GateRef right, ProfileOperation callback)626 GateRef OperationsStubBuilder::Mul(GateRef glue, GateRef left, GateRef right, ProfileOperation callback)
627 {
628     auto env = GetEnvironment();
629     Label entry(env);
630     env->SubCfgEntry(&entry);
631     Label exit(env);
632     Label slowPath(env);
633     DEFVARIABLE(result, VariableType::JS_ANY(), FastMul(glue, left, right, callback));
634     BRANCH(TaggedIsHole(*result), &slowPath, &exit);
635     Bind(&slowPath);
636     {
637         callback.ProfileOpType(TaggedInt(PGOSampleType::AnyType()));
638         result = CallRuntime(glue, RTSTUB_ID(Mul2), { left, right });
639         Jump(&exit);
640     }
641     Bind(&exit);
642     auto ret = *result;
643     env->SubCfgExit();
644     return ret;
645 }
646 
Div(GateRef glue, GateRef left, GateRef right, ProfileOperation callback)647 GateRef OperationsStubBuilder::Div(GateRef glue, GateRef left, GateRef right, ProfileOperation callback)
648 {
649     auto env = GetEnvironment();
650     Label entry(env);
651     env->SubCfgEntry(&entry);
652     Label exit(env);
653     Label slowPath(env);
654     DEFVARIABLE(result, VariableType::JS_ANY(), FastDiv(left, right, callback));
655     BRANCH(TaggedIsHole(*result), &slowPath, &exit);
656     Bind(&slowPath);
657     {
658         callback.ProfileOpType(TaggedInt(PGOSampleType::AnyType()));
659         result = CallRuntime(glue, RTSTUB_ID(Div2), { left, right });
660         Jump(&exit);
661     }
662     Bind(&exit);
663     auto ret = *result;
664     env->SubCfgExit();
665     return ret;
666 }
667 
Mod(GateRef glue, GateRef left, GateRef right, ProfileOperation callback)668 GateRef OperationsStubBuilder::Mod(GateRef glue, GateRef left, GateRef right, ProfileOperation callback)
669 {
670     auto env = GetEnvironment();
671     Label entry(env);
672     env->SubCfgEntry(&entry);
673     Label exit(env);
674     Label slowPath(env);
675     DEFVARIABLE(result, VariableType::JS_ANY(), FastMod(glue, left, right, callback));
676     BRANCH(TaggedIsHole(*result), &slowPath, &exit);
677     Bind(&slowPath);
678     {
679         callback.ProfileOpType(TaggedInt(PGOSampleType::AnyType()));
680         result = CallRuntime(glue, RTSTUB_ID(Mod2), { left, right });
681         Jump(&exit);
682     }
683     Bind(&exit);
684     auto ret = *result;
685     env->SubCfgExit();
686     return ret;
687 }
688 
Shl(GateRef glue, GateRef left, GateRef right, ProfileOperation callback)689 GateRef OperationsStubBuilder::Shl(GateRef glue, GateRef left, GateRef right, ProfileOperation callback)
690 {
691     auto env = GetEnvironment();
692     Label entry(env);
693     env->SubCfgEntry(&entry);
694     Label exit(env);
695 
696     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
697     DEFVARIABLE(opNumber0, VariableType::INT32(), Int32(0));
698     DEFVARIABLE(opNumber1, VariableType::INT32(), Int32(0));
699 
700     Label calculate(env);
701     Label leftIsNumber(env);
702     Label leftNotNumberOrRightNotNumber(env);
703     BRANCH(TaggedIsNumber(left), &leftIsNumber, &leftNotNumberOrRightNotNumber);
704     Bind(&leftIsNumber);
705     {
706         Label rightIsNumber(env);
707         BRANCH(TaggedIsNumber(right), &rightIsNumber, &leftNotNumberOrRightNotNumber);
708         Bind(&rightIsNumber);
709         {
710             Label leftIsInt(env);
711             Label leftIsDouble(env);
712             BRANCH(TaggedIsInt(left), &leftIsInt, &leftIsDouble);
713             Bind(&leftIsInt);
714             {
715                 Label rightIsInt(env);
716                 Label rightIsDouble(env);
717                 BRANCH(TaggedIsInt(right), &rightIsInt, &rightIsDouble);
718                 Bind(&rightIsInt);
719                 {
720                     callback.ProfileOpType(TaggedInt(PGOSampleType::IntType()));
721                     opNumber0 = GetInt32OfTInt(left);
722                     opNumber1 = GetInt32OfTInt(right);
723                     Jump(&calculate);
724                 }
725                 Bind(&rightIsDouble);
726                 {
727                     callback.ProfileOpType(TaggedInt(PGOSampleType::NumberType()));
728                     GateRef rightDouble = GetDoubleOfTDouble(right);
729                     opNumber0 = GetInt32OfTInt(left);
730                     opNumber1 = DoubleToInt(glue, rightDouble);
731                     Jump(&calculate);
732                 }
733             }
734             Bind(&leftIsDouble);
735             {
736                 Label rightIsInt(env);
737                 Label rightIsDouble(env);
738                 BRANCH(TaggedIsInt(right), &rightIsInt, &rightIsDouble);
739                 Bind(&rightIsInt);
740                 {
741                     callback.ProfileOpType(TaggedInt(PGOSampleType::NumberType()));
742                     GateRef leftDouble = GetDoubleOfTDouble(left);
743                     opNumber0 = DoubleToInt(glue, leftDouble);
744                     opNumber1 = GetInt32OfTInt(right);
745                     Jump(&calculate);
746                 }
747                 Bind(&rightIsDouble);
748                 {
749                     callback.ProfileOpType(TaggedInt(PGOSampleType::DoubleType()));
750                     GateRef rightDouble = GetDoubleOfTDouble(right);
751                     GateRef leftDouble = GetDoubleOfTDouble(left);
752                     opNumber0 = DoubleToInt(glue, leftDouble);
753                     opNumber1 = DoubleToInt(glue, rightDouble);
754                     Jump(&calculate);
755                 }
756             }
757         }
758     }
759     // slow path
760     Bind(&leftNotNumberOrRightNotNumber);
761     {
762         callback.ProfileOpType(TaggedInt(PGOSampleType::AnyType()));
763         result = CallRuntime(glue, RTSTUB_ID(Shl2), { left, right });
764         Jump(&exit);
765     }
766     Bind(&calculate);
767     {
768         GateRef shift = Int32And(*opNumber1, Int32(0x1f));
769         GateRef val = Int32LSL(*opNumber0, shift);
770         result = IntToTaggedPtr(val);
771         Jump(&exit);
772     }
773     Bind(&exit);
774     auto ret = *result;
775     env->SubCfgExit();
776     return ret;
777 }
778 
Shr(GateRef glue, GateRef left, GateRef right, ProfileOperation callback)779 GateRef OperationsStubBuilder::Shr(GateRef glue, GateRef left, GateRef right, ProfileOperation callback)
780 {
781     auto env = GetEnvironment();
782     Label entry(env);
783     env->SubCfgEntry(&entry);
784     Label exit(env);
785 
786     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
787     DEFVARIABLE(opNumber0, VariableType::INT32(), Int32(0));
788     DEFVARIABLE(opNumber1, VariableType::INT32(), Int32(0));
789     DEFVARIABLE(curType, VariableType::INT64(), TaggedInt(PGOSampleType::None()));
790 
791     Label doShr(env);
792     Label overflow(env);
793     Label notOverflow(env);
794     Label leftIsNumber(env);
795     Label leftNotNumberOrRightNotNumber(env);
796     BRANCH(TaggedIsNumber(left), &leftIsNumber, &leftNotNumberOrRightNotNumber);
797     Bind(&leftIsNumber);
798     {
799         Label rightIsNumber(env);
800         BRANCH(TaggedIsNumber(right), &rightIsNumber, &leftNotNumberOrRightNotNumber);
801         Bind(&rightIsNumber);
802         {
803             Label leftIsInt(env);
804             Label leftIsDouble(env);
805             BRANCH(TaggedIsInt(left), &leftIsInt, &leftIsDouble);
806             Bind(&leftIsInt);
807             {
808                 Label rightIsInt(env);
809                 Label rightIsDouble(env);
810                 BRANCH(TaggedIsInt(right), &rightIsInt, &rightIsDouble);
811                 Bind(&rightIsInt);
812                 {
813                     curType = TaggedInt(PGOSampleType::IntType());
814                     opNumber0 = GetInt32OfTInt(left);
815                     opNumber1 = GetInt32OfTInt(right);
816                     Jump(&doShr);
817                 }
818                 Bind(&rightIsDouble);
819                 {
820                     curType = TaggedInt(PGOSampleType::NumberType());
821                     GateRef rightDouble = GetDoubleOfTDouble(right);
822                     opNumber0 = GetInt32OfTInt(left);
823                     opNumber1 = DoubleToInt(glue, rightDouble);
824                     Jump(&doShr);
825                 }
826             }
827             Bind(&leftIsDouble);
828             {
829                 Label rightIsInt(env);
830                 Label rightIsDouble(env);
831                 BRANCH(TaggedIsInt(right), &rightIsInt, &rightIsDouble);
832                 Bind(&rightIsInt);
833                 {
834                     curType = TaggedInt(PGOSampleType::NumberType());
835                     GateRef leftDouble = GetDoubleOfTDouble(left);
836                     opNumber0 = DoubleToInt(glue, leftDouble);
837                     opNumber1 = GetInt32OfTInt(right);
838                     Jump(&doShr);
839                 }
840                 Bind(&rightIsDouble);
841                 {
842                     curType = TaggedInt(PGOSampleType::DoubleType());
843                     GateRef rightDouble = GetDoubleOfTDouble(right);
844                     GateRef leftDouble = GetDoubleOfTDouble(left);
845                     opNumber0 = DoubleToInt(glue, leftDouble);
846                     opNumber1 = DoubleToInt(glue, rightDouble);
847                     Jump(&doShr);
848                 }
849             }
850         }
851     }
852     // slow path
853     Bind(&leftNotNumberOrRightNotNumber);
854     {
855         callback.ProfileOpType(TaggedInt(PGOSampleType::AnyType()));
856         result = CallRuntime(glue, RTSTUB_ID(Shr2), { left, right });
857         Jump(&exit);
858     }
859     Bind(&doShr);
860     {
861         GateRef shift = Int32And(*opNumber1, Int32(0x1f));
862         GateRef val = Int32LSR(*opNumber0, shift);
863         auto condition = Int32UnsignedGreaterThan(val, Int32(INT32_MAX));
864         BRANCH(condition, &overflow, &notOverflow);
865         Bind(&overflow);
866         {
867             callback.ProfileOpType(TaggedInt(PGOSampleType::IntOverFlowType()));
868             result = DoubleToTaggedDoublePtr(ChangeUInt32ToFloat64(val));
869             Jump(&exit);
870         }
871         Bind(&notOverflow);
872         {
873             callback.ProfileOpType(*curType);
874             result = IntToTaggedPtr(val);
875             Jump(&exit);
876         }
877     }
878     Bind(&exit);
879     auto ret = *result;
880     env->SubCfgExit();
881     return ret;
882 }
883 
Ashr(GateRef glue, GateRef left, GateRef right, ProfileOperation callback)884 GateRef OperationsStubBuilder::Ashr(GateRef glue, GateRef left, GateRef right, ProfileOperation callback)
885 {
886     auto env = GetEnvironment();
887     Label entry(env);
888     env->SubCfgEntry(&entry);
889     Label exit(env);
890 
891     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
892     DEFVARIABLE(opNumber0, VariableType::INT32(), Int32(0));
893     DEFVARIABLE(opNumber1, VariableType::INT32(), Int32(0));
894 
895     Label calculate(env);
896     Label leftIsNumber(env);
897     Label leftNotNumberOrRightNotNumber(env);
898     BRANCH(TaggedIsNumber(left), &leftIsNumber, &leftNotNumberOrRightNotNumber);
899     Bind(&leftIsNumber);
900     {
901         Label rightIsNumber(env);
902         BRANCH(TaggedIsNumber(right), &rightIsNumber, &leftNotNumberOrRightNotNumber);
903         Bind(&rightIsNumber);
904         {
905             Label leftIsInt(env);
906             Label leftIsDouble(env);
907             BRANCH(TaggedIsInt(left), &leftIsInt, &leftIsDouble);
908             Bind(&leftIsInt);
909             {
910                 Label rightIsInt(env);
911                 Label rightIsDouble(env);
912                 BRANCH(TaggedIsInt(right), &rightIsInt, &rightIsDouble);
913                 Bind(&rightIsInt);
914                 {
915                     callback.ProfileOpType(TaggedInt(PGOSampleType::IntType()));
916                     opNumber0 = GetInt32OfTInt(left);
917                     opNumber1 = GetInt32OfTInt(right);
918                     Jump(&calculate);
919                 }
920                 Bind(&rightIsDouble);
921                 {
922                     callback.ProfileOpType(TaggedInt(PGOSampleType::NumberType()));
923                     GateRef rightDouble = GetDoubleOfTDouble(right);
924                     opNumber0 = GetInt32OfTInt(left);
925                     opNumber1 = DoubleToInt(glue, rightDouble);
926                     Jump(&calculate);
927                 }
928             }
929             Bind(&leftIsDouble);
930             {
931                 Label rightIsInt(env);
932                 Label rightIsDouble(env);
933                 BRANCH(TaggedIsInt(right), &rightIsInt, &rightIsDouble);
934                 Bind(&rightIsInt);
935                 {
936                     callback.ProfileOpType(TaggedInt(PGOSampleType::NumberType()));
937                     GateRef leftDouble = GetDoubleOfTDouble(left);
938                     opNumber0 = DoubleToInt(glue, leftDouble);
939                     opNumber1 = GetInt32OfTInt(right);
940                     Jump(&calculate);
941                 }
942                 Bind(&rightIsDouble);
943                 {
944                     callback.ProfileOpType(TaggedInt(PGOSampleType::DoubleType()));
945                     GateRef rightDouble = GetDoubleOfTDouble(right);
946                     GateRef leftDouble = GetDoubleOfTDouble(left);
947                     opNumber0 = DoubleToInt(glue, leftDouble);
948                     opNumber1 = DoubleToInt(glue, rightDouble);
949                     Jump(&calculate);
950                 }
951             }
952         }
953     }
954     // slow path
955     Bind(&leftNotNumberOrRightNotNumber);
956     {
957         callback.ProfileOpType(TaggedInt(PGOSampleType::AnyType()));
958         result = CallRuntime(glue, RTSTUB_ID(Ashr2), { left, right });
959         Jump(&exit);
960     }
961     Bind(&calculate);
962     {
963         GateRef shift = Int32And(*opNumber1, Int32(0x1f));
964         GateRef val = Int32ASR(*opNumber0, shift);
965         result = IntToTaggedPtr(val);
966         Jump(&exit);
967     }
968     Bind(&exit);
969     auto ret = *result;
970     env->SubCfgExit();
971     return ret;
972 }
973 
And(GateRef glue, GateRef left, GateRef right, ProfileOperation callback)974 GateRef OperationsStubBuilder::And(GateRef glue, GateRef left, GateRef right, ProfileOperation callback)
975 {
976     auto env = GetEnvironment();
977     Label entry(env);
978     env->SubCfgEntry(&entry);
979     Label exit(env);
980 
981     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
982     DEFVARIABLE(opNumber0, VariableType::INT32(), Int32(0));
983     DEFVARIABLE(opNumber1, VariableType::INT32(), Int32(0));
984 
985     Label calculate(env);
986     Label leftIsNumber(env);
987     Label leftNotNumberOrRightNotNumber(env);
988     BRANCH(TaggedIsNumber(left), &leftIsNumber, &leftNotNumberOrRightNotNumber);
989     Bind(&leftIsNumber);
990     {
991         Label rightIsNumber(env);
992         BRANCH(TaggedIsNumber(right), &rightIsNumber, &leftNotNumberOrRightNotNumber);
993         Bind(&rightIsNumber);
994         {
995             Label leftIsInt(env);
996             Label leftIsDouble(env);
997             BRANCH(TaggedIsInt(left), &leftIsInt, &leftIsDouble);
998             Bind(&leftIsInt);
999             {
1000                 Label rightIsInt(env);
1001                 Label rightIsDouble(env);
1002                 BRANCH(TaggedIsInt(right), &rightIsInt, &rightIsDouble);
1003                 Bind(&rightIsInt);
1004                 {
1005                     callback.ProfileOpType(TaggedInt(PGOSampleType::IntType()));
1006                     opNumber0 = GetInt32OfTInt(left);
1007                     opNumber1 = GetInt32OfTInt(right);
1008                     Jump(&calculate);
1009                 }
1010                 Bind(&rightIsDouble);
1011                 {
1012                     callback.ProfileOpType(TaggedInt(PGOSampleType::NumberType()));
1013                     opNumber0 = GetInt32OfTInt(left);
1014                     GateRef rightDouble = GetDoubleOfTDouble(right);
1015                     opNumber1 = DoubleToInt(glue, rightDouble);
1016                     Jump(&calculate);
1017                 }
1018             }
1019             Bind(&leftIsDouble);
1020             {
1021                 Label rightIsInt(env);
1022                 Label rightIsDouble(env);
1023                 BRANCH(TaggedIsInt(right), &rightIsInt, &rightIsDouble);
1024                 Bind(&rightIsInt);
1025                 {
1026                     callback.ProfileOpType(TaggedInt(PGOSampleType::NumberType()));
1027                     GateRef leftDouble = GetDoubleOfTDouble(left);
1028                     opNumber0 = DoubleToInt(glue, leftDouble);
1029                     opNumber1 = GetInt32OfTInt(right);
1030                     Jump(&calculate);
1031                 }
1032                 Bind(&rightIsDouble);
1033                 {
1034                     callback.ProfileOpType(TaggedInt(PGOSampleType::DoubleType()));
1035                     GateRef rightDouble = GetDoubleOfTDouble(right);
1036                     GateRef leftDouble = GetDoubleOfTDouble(left);
1037                     opNumber0 = DoubleToInt(glue, leftDouble);
1038                     opNumber1 = DoubleToInt(glue, rightDouble);
1039                     Jump(&calculate);
1040                 }
1041             }
1042         }
1043     }
1044     // slow path
1045     Bind(&leftNotNumberOrRightNotNumber);
1046     {
1047         callback.ProfileOpType(TaggedInt(PGOSampleType::AnyType()));
1048         result = CallRuntime(glue, RTSTUB_ID(And2), { left, right });
1049         Jump(&exit);
1050     }
1051     Bind(&calculate);
1052     {
1053         GateRef val = Int32And(*opNumber0, *opNumber1);
1054         result = IntToTaggedPtr(val);
1055         Jump(&exit);
1056     }
1057     Bind(&exit);
1058     auto ret = *result;
1059     env->SubCfgExit();
1060     return ret;
1061 }
1062 
Or(GateRef glue, GateRef left, GateRef right, ProfileOperation callback)1063 GateRef OperationsStubBuilder::Or(GateRef glue, GateRef left, GateRef right, ProfileOperation callback)
1064 {
1065     auto env = GetEnvironment();
1066     Label entry(env);
1067     env->SubCfgEntry(&entry);
1068     Label exit(env);
1069 
1070     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
1071     DEFVARIABLE(opNumber0, VariableType::INT32(), Int32(0));
1072     DEFVARIABLE(opNumber1, VariableType::INT32(), Int32(0));
1073 
1074     Label calculate(env);
1075     Label leftIsNumber(env);
1076     Label leftNotNumberOrRightNotNumber(env);
1077     BRANCH(TaggedIsNumber(left), &leftIsNumber, &leftNotNumberOrRightNotNumber);
1078     Bind(&leftIsNumber);
1079     {
1080         Label rightIsNumber(env);
1081         BRANCH(TaggedIsNumber(right), &rightIsNumber, &leftNotNumberOrRightNotNumber);
1082         Bind(&rightIsNumber);
1083         {
1084             Label leftIsInt(env);
1085             Label leftIsDouble(env);
1086             BRANCH(TaggedIsInt(left), &leftIsInt, &leftIsDouble);
1087             Bind(&leftIsInt);
1088             {
1089                 Label rightIsInt(env);
1090                 Label rightIsDouble(env);
1091                 BRANCH(TaggedIsInt(right), &rightIsInt, &rightIsDouble);
1092                 Bind(&rightIsInt);
1093                 {
1094                     callback.ProfileOpType(TaggedInt(PGOSampleType::IntType()));
1095                     opNumber0 = GetInt32OfTInt(left);
1096                     opNumber1 = GetInt32OfTInt(right);
1097                     Jump(&calculate);
1098                 }
1099                 Bind(&rightIsDouble);
1100                 {
1101                     callback.ProfileOpType(TaggedInt(PGOSampleType::NumberType()));
1102                     GateRef rightDouble = GetDoubleOfTDouble(right);
1103                     opNumber0 = GetInt32OfTInt(left);
1104                     opNumber1 = DoubleToInt(glue, rightDouble);
1105                     Jump(&calculate);
1106                 }
1107             }
1108             Bind(&leftIsDouble);
1109             {
1110                 Label rightIsInt(env);
1111                 Label rightIsDouble(env);
1112                 BRANCH(TaggedIsInt(right), &rightIsInt, &rightIsDouble);
1113                 Bind(&rightIsInt);
1114                 {
1115                     callback.ProfileOpType(TaggedInt(PGOSampleType::NumberType()));
1116                     GateRef leftDouble = GetDoubleOfTDouble(left);
1117                     opNumber0 = DoubleToInt(glue, leftDouble);
1118                     opNumber1 = GetInt32OfTInt(right);
1119                     Jump(&calculate);
1120                 }
1121                 Bind(&rightIsDouble);
1122                 {
1123                     callback.ProfileOpType(TaggedInt(PGOSampleType::DoubleType()));
1124                     GateRef rightDouble = GetDoubleOfTDouble(right);
1125                     GateRef leftDouble = GetDoubleOfTDouble(left);
1126                     opNumber0 = DoubleToInt(glue, leftDouble);
1127                     opNumber1 = DoubleToInt(glue, rightDouble);
1128                     Jump(&calculate);
1129                 }
1130             }
1131         }
1132     }
1133     // slow path
1134     Bind(&leftNotNumberOrRightNotNumber);
1135     {
1136         callback.ProfileOpType(TaggedInt(PGOSampleType::AnyType()));
1137         result = CallRuntime(glue, RTSTUB_ID(Or2), { left, right });
1138         Jump(&exit);
1139     }
1140     Bind(&calculate);
1141     {
1142         GateRef val = Int32Or(*opNumber0, *opNumber1);
1143         result = IntToTaggedPtr(val);
1144         Jump(&exit);
1145     }
1146     Bind(&exit);
1147     auto ret = *result;
1148     env->SubCfgExit();
1149     return ret;
1150 }
1151 
Xor(GateRef glue, GateRef left, GateRef right, ProfileOperation callback)1152 GateRef OperationsStubBuilder::Xor(GateRef glue, GateRef left, GateRef right, ProfileOperation callback)
1153 {
1154     auto env = GetEnvironment();
1155     Label entry(env);
1156     env->SubCfgEntry(&entry);
1157     Label exit(env);
1158 
1159     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
1160     DEFVARIABLE(opNumber0, VariableType::INT32(), Int32(0));
1161     DEFVARIABLE(opNumber1, VariableType::INT32(), Int32(0));
1162 
1163     Label calculate(env);
1164     Label leftIsNumber(env);
1165     Label leftNotNumberOrRightNotNumber(env);
1166     BRANCH(TaggedIsNumber(left), &leftIsNumber, &leftNotNumberOrRightNotNumber);
1167     Bind(&leftIsNumber);
1168     {
1169         Label rightIsNumber(env);
1170         BRANCH(TaggedIsNumber(right), &rightIsNumber, &leftNotNumberOrRightNotNumber);
1171         Bind(&rightIsNumber);
1172         {
1173             Label leftIsInt(env);
1174             Label leftIsDouble(env);
1175             BRANCH(TaggedIsInt(left), &leftIsInt, &leftIsDouble);
1176             Bind(&leftIsInt);
1177             {
1178                 Label rightIsInt(env);
1179                 Label rightIsDouble(env);
1180                 BRANCH(TaggedIsInt(right), &rightIsInt, &rightIsDouble);
1181                 Bind(&rightIsInt);
1182                 {
1183                     callback.ProfileOpType(TaggedInt(PGOSampleType::IntType()));
1184                     opNumber0 = GetInt32OfTInt(left);
1185                     opNumber1 = GetInt32OfTInt(right);
1186                     Jump(&calculate);
1187                 }
1188                 Bind(&rightIsDouble);
1189                 {
1190                     callback.ProfileOpType(TaggedInt(PGOSampleType::NumberType()));
1191                     GateRef rightDouble = GetDoubleOfTDouble(right);
1192                     opNumber0 = GetInt32OfTInt(left);
1193                     opNumber1 = DoubleToInt(glue, rightDouble);
1194                     Jump(&calculate);
1195                 }
1196             }
1197             Bind(&leftIsDouble);
1198             {
1199                 Label rightIsInt(env);
1200                 Label rightIsDouble(env);
1201                 BRANCH(TaggedIsInt(right), &rightIsInt, &rightIsDouble);
1202                 Bind(&rightIsInt);
1203                 {
1204                     callback.ProfileOpType(TaggedInt(PGOSampleType::NumberType()));
1205                     GateRef leftDouble = GetDoubleOfTDouble(left);
1206                     opNumber0 = DoubleToInt(glue, leftDouble);
1207                     opNumber1 = GetInt32OfTInt(right);
1208                     Jump(&calculate);
1209                 }
1210                 Bind(&rightIsDouble);
1211                 {
1212                     callback.ProfileOpType(TaggedInt(PGOSampleType::DoubleType()));
1213                     GateRef rightDouble = GetDoubleOfTDouble(right);
1214                     GateRef leftDouble = GetDoubleOfTDouble(left);
1215                     opNumber0 = DoubleToInt(glue, leftDouble);
1216                     opNumber1 = DoubleToInt(glue, rightDouble);
1217                     Jump(&calculate);
1218                 }
1219             }
1220         }
1221     }
1222     // slow path
1223     Bind(&leftNotNumberOrRightNotNumber);
1224     {
1225         callback.ProfileOpType(TaggedInt(PGOSampleType::AnyType()));
1226         result = CallRuntime(glue, RTSTUB_ID(Xor2), { left, right });
1227         Jump(&exit);
1228     }
1229     Bind(&calculate);
1230     {
1231         GateRef val = Int32Xor(*opNumber0, *opNumber1);
1232         result = IntToTaggedPtr(val);
1233         Jump(&exit);
1234     }
1235     Bind(&exit);
1236     auto ret = *result;
1237     env->SubCfgExit();
1238     return ret;
1239 }
1240 
Inc(GateRef glue, GateRef value, ProfileOperation callback)1241 GateRef OperationsStubBuilder::Inc(GateRef glue, GateRef value, ProfileOperation callback)
1242 {
1243     auto env = GetEnvironment();
1244     Label entry(env);
1245     env->SubCfgEntry(&entry);
1246     Label exit(env);
1247 
1248     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
1249     Label valueIsInt(env);
1250     Label valueNotInt(env);
1251     Label slowPath(env);
1252     BRANCH(TaggedIsInt(value), &valueIsInt, &valueNotInt);
1253     Bind(&valueIsInt);
1254     {
1255         GateRef valueInt = GetInt32OfTInt(value);
1256         Label valueNoOverflow(env);
1257         BRANCH(Int32Equal(valueInt, Int32(INT32_MAX)), &valueNotInt, &valueNoOverflow);
1258         Bind(&valueNoOverflow);
1259         {
1260             callback.ProfileOpType(TaggedInt(PGOSampleType::IntType()));
1261             result = IntToTaggedPtr(Int32Add(valueInt, Int32(1)));
1262             Jump(&exit);
1263         }
1264     }
1265     Bind(&valueNotInt);
1266     {
1267         Label valueIsDouble(env);
1268         BRANCH(TaggedIsDouble(value), &valueIsDouble, &slowPath);
1269         Bind(&valueIsDouble);
1270         {
1271             callback.ProfileOpType(TaggedInt(PGOSampleType::DoubleType()));
1272             GateRef valueDouble = GetDoubleOfTDouble(value);
1273             result = DoubleToTaggedDoublePtr(DoubleAdd(valueDouble, Double(1.0)));
1274             Jump(&exit);
1275         }
1276     }
1277     Bind(&slowPath);
1278     {
1279         callback.ProfileOpType(TaggedInt(PGOSampleType::AnyType()));
1280         result = CallRuntime(glue, RTSTUB_ID(Inc), { value });
1281         Jump(&exit);
1282     }
1283     Bind(&exit);
1284     auto ret = *result;
1285     env->SubCfgExit();
1286     return ret;
1287 }
1288 
Dec(GateRef glue, GateRef value, ProfileOperation callback)1289 GateRef OperationsStubBuilder::Dec(GateRef glue, GateRef value, ProfileOperation callback)
1290 {
1291     auto env = GetEnvironment();
1292     Label entry(env);
1293     env->SubCfgEntry(&entry);
1294     Label exit(env);
1295 
1296     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
1297     Label valueIsInt(env);
1298     Label valueNotInt(env);
1299     Label slowPath(env);
1300     BRANCH(TaggedIsInt(value), &valueIsInt, &valueNotInt);
1301     Bind(&valueIsInt);
1302     {
1303         GateRef valueInt = GetInt32OfTInt(value);
1304         Label valueNoOverflow(env);
1305         BRANCH(Int32Equal(valueInt, Int32(INT32_MIN)), &valueNotInt, &valueNoOverflow);
1306         Bind(&valueNoOverflow);
1307         {
1308             callback.ProfileOpType(TaggedInt(PGOSampleType::IntType()));
1309             result = IntToTaggedPtr(Int32Sub(valueInt, Int32(1)));
1310             Jump(&exit);
1311         }
1312     }
1313     Bind(&valueNotInt);
1314     {
1315         Label valueIsDouble(env);
1316         BRANCH(TaggedIsDouble(value), &valueIsDouble, &slowPath);
1317         Bind(&valueIsDouble);
1318         {
1319             callback.ProfileOpType(TaggedInt(PGOSampleType::DoubleType()));
1320             GateRef valueDouble = GetDoubleOfTDouble(value);
1321             result = DoubleToTaggedDoublePtr(DoubleSub(valueDouble, Double(1.0)));
1322             Jump(&exit);
1323         }
1324     }
1325     Bind(&slowPath);
1326     {
1327         callback.ProfileOpType(TaggedInt(PGOSampleType::AnyType()));
1328         result = CallRuntime(glue, RTSTUB_ID(Dec), { value });
1329         Jump(&exit);
1330     }
1331 
1332     Bind(&exit);
1333     auto ret = *result;
1334     env->SubCfgExit();
1335     return ret;
1336 }
1337 
Neg(GateRef glue, GateRef value, ProfileOperation callback)1338 GateRef OperationsStubBuilder::Neg(GateRef glue, GateRef value, ProfileOperation callback)
1339 {
1340     auto env = GetEnvironment();
1341     Label entry(env);
1342     env->SubCfgEntry(&entry);
1343     Label exit(env);
1344 
1345     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
1346     Label valueIsInt(env);
1347     Label valueNotInt(env);
1348     BRANCH(TaggedIsInt(value), &valueIsInt, &valueNotInt);
1349     Bind(&valueIsInt);
1350     {
1351         GateRef valueInt = GetInt32OfTInt(value);
1352         Label valueIsZero(env);
1353         Label valueNotZero(env);
1354         BRANCH(Int32Equal(valueInt, Int32(0)), &valueIsZero, &valueNotZero);
1355         Bind(&valueIsZero);
1356         {
1357             callback.ProfileOpType(TaggedInt(PGOSampleType::IntOverFlowType()));
1358             result = DoubleToTaggedDoublePtr(Double(-0.0));
1359             Jump(&exit);
1360         }
1361         Bind(&valueNotZero);
1362         {
1363             Label valueIsInt32Min(env);
1364             Label valueNotInt32Min(env);
1365             BRANCH(Int32Equal(valueInt, Int32(INT32_MIN)), &valueIsInt32Min, &valueNotInt32Min);
1366             Bind(&valueIsInt32Min);
1367             {
1368                 callback.ProfileOpType(TaggedInt(PGOSampleType::IntOverFlowType()));
1369                 result = DoubleToTaggedDoublePtr(Double(-static_cast<double>(INT32_MIN)));
1370                 Jump(&exit);
1371             }
1372             Bind(&valueNotInt32Min);
1373             {
1374                 callback.ProfileOpType(TaggedInt(PGOSampleType::IntType()));
1375                 result = IntToTaggedPtr(Int32Sub(Int32(0), valueInt));
1376                 Jump(&exit);
1377             }
1378         }
1379     }
1380     Bind(&valueNotInt);
1381     {
1382         Label valueIsDouble(env);
1383         Label valueNotDouble(env);
1384         BRANCH(TaggedIsDouble(value), &valueIsDouble, &valueNotDouble);
1385         Bind(&valueIsDouble);
1386         {
1387             callback.ProfileOpType(TaggedInt(PGOSampleType::DoubleType()));
1388             GateRef valueDouble = GetDoubleOfTDouble(value);
1389             result = DoubleToTaggedDoublePtr(DoubleMul(Double(-1), valueDouble));
1390             Jump(&exit);
1391         }
1392         Bind(&valueNotDouble);
1393         {
1394             // slow path
1395             callback.ProfileOpType(TaggedInt(PGOSampleType::AnyType()));
1396             result = CallRuntime(glue, RTSTUB_ID(Neg), { value });
1397             Jump(&exit);
1398         }
1399     }
1400     Bind(&exit);
1401     auto ret = *result;
1402     env->SubCfgExit();
1403     return ret;
1404 }
1405 
Not(GateRef glue, GateRef value, ProfileOperation callback)1406 GateRef OperationsStubBuilder::Not(GateRef glue, GateRef value, ProfileOperation callback)
1407 {
1408     auto env = GetEnvironment();
1409     Label entry(env);
1410     env->SubCfgEntry(&entry);
1411     Label exit(env);
1412 
1413     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
1414     Label numberIsInt(env);
1415     Label numberNotInt(env);
1416     BRANCH(TaggedIsInt(value), &numberIsInt, &numberNotInt);
1417     Bind(&numberIsInt);
1418     {
1419         callback.ProfileOpType(TaggedInt(PGOSampleType::IntType()));
1420         GateRef valueInt = GetInt32OfTInt(value);
1421         result = IntToTaggedPtr(Int32Not(valueInt));
1422         Jump(&exit);
1423     }
1424     Bind(&numberNotInt);
1425     {
1426         Label numberIsDouble(env);
1427         Label numberNotDouble(env);
1428         BRANCH(TaggedIsDouble(value), &numberIsDouble, &numberNotDouble);
1429         Bind(&numberIsDouble);
1430         {
1431             callback.ProfileOpType(TaggedInt(PGOSampleType::DoubleType()));
1432             GateRef valueDouble = GetDoubleOfTDouble(value);
1433             result = IntToTaggedPtr(Int32Not(DoubleToInt(glue, valueDouble)));
1434             Jump(&exit);
1435         }
1436         Bind(&numberNotDouble);
1437         {
1438             // slow path
1439             callback.ProfileOpType(TaggedInt(PGOSampleType::AnyType()));
1440             result = CallRuntime(glue, RTSTUB_ID(Not), { value });
1441             Jump(&exit);
1442         }
1443     }
1444     Bind(&exit);
1445     auto ret = *result;
1446     env->SubCfgExit();
1447     return ret;
1448 }
1449 }  // namespace panda::ecmascript::kungfu
1450