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
21namespace panda::ecmascript::kungfu {
22GateRef 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
61GateRef 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
103GateRef 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
130GateRef 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
157GateRef 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
264GateRef 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
371GateRef 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
477GateRef 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
584GateRef 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
605GateRef 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
626GateRef 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
647GateRef 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
668GateRef 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
689GateRef 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
779GateRef 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
884GateRef 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
974GateRef 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
1063GateRef 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
1152GateRef 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
1241GateRef 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
1289GateRef 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
1338GateRef 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
1406GateRef 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