1/*
2 * Copyright (c) 2023 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/profiler_stub_builder.h"
17
18#include "ecmascript/base/number_helper.h"
19#include "ecmascript/compiler/circuit_builder_helper.h"
20#include "ecmascript/compiler/rt_call_signature.h"
21#include "ecmascript/compiler/share_gate_meta_data.h"
22#include "ecmascript/compiler/interpreter_stub-inl.h"
23#include "ecmascript/compiler/stub_builder.h"
24#include "ecmascript/compiler/stub_builder-inl.h"
25#include "ecmascript/compiler/variable_type.h"
26#include "ecmascript/ic/profile_type_info.h"
27
28namespace panda::ecmascript::kungfu {
29void ProfilerStubBuilder::PGOProfiler(GateRef glue, GateRef pc, GateRef func, GateRef profileTypeInfo,
30    const std::vector<GateRef> &values, SlotIDFormat format, OperationType type)
31{
32    if (type == OperationType::TRUE_BRANCH ||
33        type == OperationType::FALSE_BRANCH ||
34        type == OperationType::TRY_JIT) {
35        SlotIDInfo slotIdInfo(pc, SlotIDInfo::SlotIDInfoType::PC);
36        PGOProfiler(glue, func, profileTypeInfo, slotIdInfo, values, type);
37    } else {
38        SlotIDInfo slotIdInfo(pc, format);
39        PGOProfiler(glue, func, profileTypeInfo, slotIdInfo, values, type);
40    }
41}
42
43void ProfilerStubBuilder::PGOProfiler(GateRef glue, GateRef func, GateRef profileTypeInfo,
44    GateRef slotId, const std::vector<GateRef> &values, OperationType type)
45{
46    SlotIDInfo slotIdInfo(slotId, SlotIDInfo::SlotIDInfoType::SLOT_ID);
47    PGOProfiler(glue, func, profileTypeInfo, slotIdInfo, values, type);
48}
49
50void ProfilerStubBuilder::TryDump(GateRef glue, GateRef func, GateRef profileTypeInfo)
51{
52    auto env = GetEnvironment();
53    Label subEntry(env);
54    env->SubCfgEntry(&subEntry);
55
56    Label updatePeriodCounter(env);
57    Label exit(env);
58    Label needDump(env);
59
60    BRANCH(IsProfileTypeInfoWithBigMethod(profileTypeInfo), &exit, &needDump);
61    Bind(&needDump);
62    BRANCH(IsProfileTypeInfoDumped(profileTypeInfo), &exit, &updatePeriodCounter);
63    Bind(&updatePeriodCounter);
64    {
65        SetDumpPeriodIndex(glue, profileTypeInfo);
66        CallRuntime(glue, RTSTUB_ID(PGODump), { func });
67        Jump(&exit);
68    }
69    Bind(&exit);
70    env->SubCfgExit();
71}
72
73void ProfilerStubBuilder::TryPreDump(GateRef glue, GateRef func, GateRef profileTypeInfo)
74{
75    auto env = GetEnvironment();
76    Label subEntry(env);
77    env->SubCfgEntry(&subEntry);
78    Label exit(env);
79    Label profiler(env);
80    BRANCH(IsProfileTypeInfoHotAndValid(profileTypeInfo), &profiler, &exit);
81    Bind(&profiler);
82    {
83        TryPreDumpInner(glue, func, profileTypeInfo);
84        Jump(&exit);
85    }
86    Bind(&exit);
87    env->SubCfgExit();
88}
89
90void ProfilerStubBuilder::ProfileOpType(
91    GateRef glue, SlotIDInfo slotInfo, GateRef func, GateRef profileTypeInfo, GateRef type)
92{
93    auto env = GetEnvironment();
94    Label subEntry(env);
95    env->SubCfgEntry(&subEntry);
96
97    Label exit(env);
98    Label profiler(env);
99    BRANCH(IsProfileTypeInfoHotAndValid(profileTypeInfo), &profiler, &exit);
100    Bind(&profiler);
101    {
102        Label icSlotValid(env);
103        Label uninitialized(env);
104        Label compareLabel(env);
105        Label updateSlot(env);
106
107        GateRef slotId = GetSlotID(slotInfo);
108        GateRef length = GetLengthOfTaggedArray(profileTypeInfo);
109        BRANCH(Int32LessThan(slotId, length), &icSlotValid, &exit);
110        Bind(&icSlotValid);
111        GateRef slotValue = GetValueFromTaggedArray(profileTypeInfo, slotId);
112        DEFVARIABLE(curTaggedSlotValue, VariableType::INT64(), type);
113        BRANCH(TaggedIsInt(slotValue), &compareLabel, &uninitialized);
114        Bind(&compareLabel);
115        {
116            GateRef oldTaggedSlotValue = ChangeTaggedPointerToInt64(slotValue);
117            curTaggedSlotValue = Int64Or(oldTaggedSlotValue, type);
118            BRANCH(Int64Equal(oldTaggedSlotValue, *curTaggedSlotValue), &exit, &updateSlot);
119        }
120        Bind(&uninitialized);
121        {
122            // Only when slot value is undefined, it means uninitialized, so we need to update the slot.
123            // When the slot value is hole, it means slot is overflow (0xff). Otherwise, do nothing.
124            BRANCH(TaggedIsUndefined(slotValue), &updateSlot, &exit);
125        }
126        Bind(&updateSlot);
127        {
128            SetValueToTaggedArray(VariableType::JS_ANY(), glue, profileTypeInfo, slotId, *curTaggedSlotValue);
129            TryPreDumpInner(glue, func, profileTypeInfo);
130            Jump(&exit);
131        }
132    }
133    Bind(&exit);
134    env->SubCfgExit();
135}
136
137void ProfilerStubBuilder::ProfileDefineClass(
138    GateRef glue, SlotIDInfo slotInfo, GateRef func, GateRef constructor, GateRef profileTypeInfo)
139{
140    auto env = GetEnvironment();
141    Label subEntry(env);
142    env->SubCfgEntry(&subEntry);
143
144    Label exit(env);
145    Label profiler(env);
146    BRANCH(IsProfileTypeInfoHotAndValid(profileTypeInfo), &profiler, &exit);
147    Bind(&profiler);
148    {
149        Label icSlotValid(env);
150        Label updateSlot(env);
151        Label isHeapObject(env);
152        Label isProfileTypeInfoCell0(env);
153
154        GateRef slotId = GetSlotID(slotInfo);
155        GateRef length = GetLengthOfTaggedArray(profileTypeInfo);
156        BRANCH(Int32LessThan(slotId, length), &icSlotValid, &exit);
157        Bind(&icSlotValid);
158        GateRef slotValue = GetValueFromTaggedArray(profileTypeInfo, slotId);
159        Branch(TaggedIsHeapObject(slotValue), &isHeapObject, &exit);
160        Bind(&isHeapObject);
161        Branch(IsProfileTypeInfoCell0(slotValue), &isProfileTypeInfoCell0, &exit);
162        Bind(&isProfileTypeInfoCell0);
163        GateRef handleOffset = IntPtr(ProfileTypeInfoCell::HANDLE_OFFSET);
164        GateRef handle = Load(VariableType::JS_ANY(), slotValue, handleOffset);
165        BRANCH(TaggedIsUndefined(handle), &updateSlot, &exit);
166        Bind(&updateSlot);
167        auto weakCtor = env->GetBuilder()->CreateWeakRef(constructor);
168        Store(VariableType::JS_POINTER(), glue, slotValue, handleOffset, weakCtor);
169        TryPreDumpInner(glue, func, profileTypeInfo);
170        Jump(&exit);
171    }
172    Bind(&exit);
173    env->SubCfgExit();
174}
175
176void ProfilerStubBuilder::ProfileCreateObject(
177    GateRef glue, SlotIDInfo slotInfo, GateRef func, GateRef newObj, GateRef profileTypeInfo)
178{
179    auto env = GetEnvironment();
180    Label subEntry(env);
181    env->SubCfgEntry(&subEntry);
182    Label exit(env);
183
184    Label profiler(env);
185    BRANCH(IsProfileTypeInfoHotAndValid(profileTypeInfo), &profiler, &exit);
186    Bind(&profiler);
187    {
188        Label icSlotValid(env);
189        Label isHeapObject(env);
190        Label isWeak(env);
191        Label uninitialized(env);
192        Label updateSlot(env);
193
194        GateRef slotId = GetSlotID(slotInfo);
195        GateRef length = GetLengthOfTaggedArray(profileTypeInfo);
196        BRANCH(Int32LessThan(slotId, length), &icSlotValid, &exit);
197        Bind(&icSlotValid);
198        auto hclass = LoadHClass(newObj);
199        GateRef slotValue = GetValueFromTaggedArray(profileTypeInfo, slotId);
200        BRANCH(TaggedIsHeapObject(slotValue), &isHeapObject, &uninitialized);
201        Bind(&isHeapObject);
202        {
203            BRANCH(TaggedIsWeak(slotValue), &isWeak, &updateSlot);
204        }
205        Bind(&isWeak);
206        {
207            auto cachedHClass = LoadObjectFromWeakRef(slotValue);
208            BRANCH(Equal(cachedHClass, hclass), &exit, &updateSlot);
209        }
210        Bind(&uninitialized);
211        {
212            // Only when slot value is undefined, it means uninitialized, so we need to update the slot.
213            // When the slot value is hole, it means slot is overflow (0xff). Otherwise, do nothing.
214            BRANCH(TaggedIsUndefined(slotValue), &updateSlot, &exit);
215        }
216        Bind(&updateSlot);
217        {
218            auto weakCtor = env->GetBuilder()->CreateWeakRef(hclass);
219            SetValueToTaggedArray(VariableType::JS_ANY(), glue, profileTypeInfo, slotId, weakCtor);
220            TryPreDumpInner(glue, func, profileTypeInfo);
221            Jump(&exit);
222        }
223    }
224    Bind(&exit);
225    env->SubCfgExit();
226}
227
228void ProfilerStubBuilder::ProfileCall(
229    GateRef glue, SlotIDInfo slotInfo, GateRef func, GateRef target, GateRef profileTypeInfo)
230{
231    auto env = GetEnvironment();
232    Label subEntry(env);
233    env->SubCfgEntry(&subEntry);
234
235    Label exit(env);
236    Label slowPath(env);
237    Label fastPath(env);
238    Label targetIsFunction(env);
239
240    BRANCH(IsJSFunction(target), &targetIsFunction, &exit);
241    Bind(&targetIsFunction);
242    {
243        GateRef targetProfileInfo = GetProfileTypeInfo(target);
244        Label targetIsNotHot(env);
245        Label targetIsHot(env);
246        Label currentIsHot(env);
247        Label updateTargetIC(env);
248
249        BRANCH(IsEnableForceIC(glue), &updateTargetIC, &targetIsHot);
250        Bind(&updateTargetIC);
251        {
252            BRANCH(IsProfileTypeInfoHotAndValid(targetProfileInfo), &targetIsHot, &targetIsNotHot);
253            Bind(&targetIsNotHot);
254            {
255                CallRuntime(glue, RTSTUB_ID(UpdateHotnessCounterWithProf), { target });
256                Jump(&targetIsHot);
257            }
258        }
259        Bind(&targetIsHot);
260        {
261            BRANCH(IsProfileTypeInfoHotAndValid(profileTypeInfo), &currentIsHot, &exit);
262        }
263        Bind(&currentIsHot);
264        {
265            Label icSlotValid(env);
266            Label isHeapObject(env);
267            Label uninitialized(env);
268            Label updateSlot(env);
269
270            GateRef slotId = GetSlotID(slotInfo);
271            GateRef length = GetLengthOfTaggedArray(profileTypeInfo);
272            BRANCH(Int32LessThan(slotId, length), &icSlotValid, &exit);
273            Bind(&icSlotValid);
274            GateRef slotValue = GetValueFromTaggedArray(profileTypeInfo, slotId);
275            BRANCH(TaggedIsHeapObject(slotValue), &isHeapObject, &uninitialized);
276            Bind(&isHeapObject);
277            {
278                Label change(env);
279                Label resetSlot(env);
280                BRANCH(Int64Equal(slotValue, target), &exit, &change);
281                Bind(&change);
282                {
283                    BRANCH(Int64Equal(ChangeTaggedPointerToInt64(slotValue), Int64(0)), &exit, &resetSlot);
284                }
285                Bind(&resetSlot);
286                {
287                    // NOTICE-PGO: lx about poly
288                    GateRef nonType = TaggedInt(0);
289                    SetValueToTaggedArray(VariableType::JS_ANY(), glue, profileTypeInfo, slotId, nonType);
290                    TryPreDumpInner(glue, func, profileTypeInfo);
291                    Jump(&exit);
292                }
293            }
294            Bind(&uninitialized);
295            {
296                // Only when slot value is undefined, it means uninitialized, so we need to update the slot.
297                // When the slot value is hole, it means slot is overflow (0xff). Otherwise, do nothing.
298                BRANCH(TaggedIsUndefined(slotValue), &updateSlot, &exit);
299            }
300            Bind(&updateSlot);
301            {
302                SetValueToTaggedArray(VariableType::JS_ANY(), glue, profileTypeInfo, slotId, target);
303                TryPreDumpInner(glue, func, profileTypeInfo);
304                Jump(&exit);
305            }
306        }
307    }
308    Bind(&exit);
309    env->SubCfgExit();
310}
311
312void ProfilerStubBuilder::ProfileGetterSetterCall(GateRef glue, GateRef target)
313{
314    auto env = GetEnvironment();
315    Label subEntry(env);
316    env->SubCfgEntry(&subEntry);
317
318    Label exit(env);
319
320    Label targetIsFunction(env);
321    BRANCH(IsJSFunction(target), &targetIsFunction, &exit);
322    Bind(&targetIsFunction);
323    {
324        GateRef targetProfileInfo = GetProfileTypeInfo(target);
325        Label targetNonHotness(env);
326        BRANCH(TaggedIsUndefined(targetProfileInfo), &targetNonHotness, &exit);
327        Bind(&targetNonHotness);
328        {
329            CallRuntime(glue, RTSTUB_ID(UpdateHotnessCounterWithProf), { target });
330            Jump(&exit);
331        }
332    }
333    Bind(&exit);
334    env->SubCfgExit();
335}
336
337GateRef ProfilerStubBuilder::TryGetBuiltinFunctionId(GateRef target)
338{
339    auto env = GetEnvironment();
340    Label subEntry(env);
341    env->SubCfgEntry(&subEntry);
342    Label targetIsFunction(env);
343    Label exit(env);
344
345    DEFVARIABLE(functionId, VariableType::INT32(), Int32(PGO_BUILTINS_STUB_ID(NONE)));
346
347    BRANCH(IsJSFunction(target), &targetIsFunction, &exit);
348    Bind(&targetIsFunction);
349    {
350        auto builtinsId = env->GetBuilder()->GetBuiltinsId(target);
351        functionId = Int32Mul(TruncInt64ToInt32(builtinsId), Int32(-1));
352        Jump(&exit);
353    }
354    Bind(&exit);
355    auto ret = *functionId;
356    env->SubCfgExit();
357    return ret;
358}
359
360void ProfilerStubBuilder::ProfileNativeCall(
361    GateRef glue, SlotIDInfo slotInfo, GateRef func, GateRef target, GateRef profileTypeInfo)
362{
363    auto env = GetEnvironment();
364    Label subEntry(env);
365    env->SubCfgEntry(&subEntry);
366
367    Label exit(env);
368    Label currentIsHot(env);
369
370    BRANCH(IsProfileTypeInfoHotAndValid(profileTypeInfo), &currentIsHot, &exit);
371    Bind(&currentIsHot);
372    {
373        Label icSlotValid(env);
374        Label updateSlot(env);
375        Label initSlot(env);
376        Label sameValueCheck(env);
377        Label invalidate(env);
378        Label notOverflow(env);
379
380        GateRef slotId = GetSlotID(slotInfo);
381        GateRef length = GetLengthOfTaggedArray(profileTypeInfo);
382        BRANCH(Int32LessThan(slotId, length), &icSlotValid, &exit);
383        Bind(&icSlotValid);
384        GateRef slotValue = GetValueFromTaggedArray(profileTypeInfo, slotId);
385        BRANCH(TaggedIsHole(slotValue), &exit, &notOverflow); // hole -- slot is overflow
386        Bind(&notOverflow);
387        BRANCH(TaggedIsInt(slotValue), &updateSlot, &initSlot);
388        Bind(&updateSlot);
389        GateRef oldId = TaggedGetInt(slotValue);
390        BRANCH(Int32Equal(oldId, Int32(PGO_BUILTINS_STUB_ID(NONE))), &exit, &sameValueCheck);
391        Bind(&sameValueCheck);
392        {
393            GateRef newId = TryGetBuiltinFunctionId(target);
394            BRANCH(Int32Equal(oldId, newId), &exit, &invalidate);
395        }
396        Bind(&invalidate);
397        {
398            GateRef invalidId = Int32(PGO_BUILTINS_STUB_ID(NONE));
399            SetValueToTaggedArray(VariableType::JS_ANY(), glue, profileTypeInfo, slotId, IntToTaggedInt(invalidId));
400            TryPreDumpInner(glue, func, profileTypeInfo);
401            Jump(&exit);
402        }
403        Bind(&initSlot);
404        {
405            GateRef newId = TryGetBuiltinFunctionId(target);
406            SetValueToTaggedArray(VariableType::JS_ANY(), glue, profileTypeInfo, slotId, IntToTaggedInt(newId));
407            TryPreDumpInner(glue, func, profileTypeInfo);
408            Jump(&exit);
409        }
410    }
411    Bind(&exit);
412    env->SubCfgExit();
413}
414
415GateRef ProfilerStubBuilder::IsProfileTypeInfoDumped(GateRef profileTypeInfo, ProfileOperation callback)
416{
417    if (callback.IsEmpty()) {
418        return Boolean(true);
419    }
420    return IsProfileTypeInfoDumped(profileTypeInfo);
421}
422
423GateRef ProfilerStubBuilder::UpdateTrackTypeInPropAttr(GateRef attr, GateRef value, ProfileOperation callback)
424{
425    if (callback.IsEmpty()) {
426        return attr;
427    }
428    auto env = GetEnvironment();
429    Label entry(env);
430    env->SubCfgEntry(&entry);
431
432    GateRef oldTrackType = GetTrackTypeInPropAttr(attr);
433    DEFVARIABLE(newTrackType, VariableType::INT32(), Int32(static_cast<int32_t>(TrackType::TAGGED)));
434    DEFVARIABLE(result, VariableType::INT64(), attr);
435
436    Label exit(env);
437    Label judgeValue(env);
438    BRANCH(Equal(oldTrackType, Int32(static_cast<int32_t>(TrackType::TAGGED))), &exit, &judgeValue);
439    Bind(&judgeValue);
440    {
441        newTrackType = TaggedToTrackType(value);
442        Label update(env);
443        Label merge(env);
444        BRANCH(Int32Equal(*newTrackType, Int32(static_cast<int32_t>(TrackType::TAGGED))), &update, &merge);
445        Bind(&merge);
446        {
447            newTrackType = Int32Or(oldTrackType, *newTrackType);
448            BRANCH(Int32Equal(oldTrackType, *newTrackType), &exit, &update);
449        }
450        Bind(&update);
451        {
452            result = SetTrackTypeInPropAttr(attr, *newTrackType);
453            Jump(&exit);
454        }
455    }
456    Bind(&exit);
457    auto ret = *result;
458    env->SubCfgExit();
459    return ret;
460}
461
462void ProfilerStubBuilder::UpdatePropAttrIC(
463    GateRef glue, GateRef receiver, GateRef value, GateRef handler, ProfileOperation callback)
464{
465    if (callback.IsEmpty()) {
466        return;
467    }
468    auto env = GetEnvironment();
469    Label entry(env);
470    env->SubCfgEntry(&entry);
471    Label exit(env);
472    Label handleUnShared(env);
473    Label updateLayout(env);
474
475    GateRef attrIndex = HandlerBaseGetAttrIndex(handler);
476    GateRef hclass = LoadHClass(receiver);
477    GateRef layout = GetLayoutFromHClass(hclass);
478    GateRef attr = GetPropAttrFromLayoutInfo(layout, attrIndex);
479    GateRef newAttr = UpdateTrackTypeInPropAttr(attr, value, callback);
480    BRANCH(IsJSShared(receiver), &exit, &handleUnShared);
481    Bind(&handleUnShared);
482    {
483        BRANCH(Equal(attr, newAttr), &exit, &updateLayout);
484        Bind(&updateLayout);
485        {
486            UpdateFieldType(glue, LoadHClass(receiver), newAttr);
487            callback.TryPreDump();
488            Jump(&exit);
489        }
490    }
491    Bind(&exit);
492    env->SubCfgExit();
493}
494
495void ProfilerStubBuilder::UpdatePropAttrWithValue(GateRef glue, GateRef receiver, GateRef attr,
496                                                  GateRef value, ProfileOperation callback)
497{
498    if (callback.IsEmpty()) {
499        return;
500    }
501    auto env = GetEnvironment();
502    Label entry(env);
503    env->SubCfgEntry(&entry);
504    Label exit(env);
505    Label updateLayout(env);
506    Label isNotJSShared(env);
507    BRANCH(IsJSShared(receiver), &exit, &isNotJSShared);
508    Bind(&isNotJSShared);
509    GateRef newAttr = UpdateTrackTypeInPropAttr(attr, value, callback);
510    BRANCH(Equal(attr, newAttr), &exit, &updateLayout);
511    Bind(&updateLayout);
512    {
513        UpdateFieldType(glue, LoadHClass(receiver), newAttr);
514        Jump(&exit);
515    }
516    Bind(&exit);
517    env->SubCfgExit();
518}
519
520GateRef ProfilerStubBuilder::TaggedToTrackType(GateRef value)
521{
522    auto env = GetEnvironment();
523    Label entry(env);
524    env->SubCfgEntry(&entry);
525
526    DEFVARIABLE(newTrackType, VariableType::INT32(), Int32(static_cast<int32_t>(TrackType::TAGGED)));
527    Label exit(env);
528    Label isInt(env);
529    Label notInt(env);
530    BRANCH(TaggedIsInt(value), &isInt, &notInt);
531    Bind(&isInt);
532    {
533        newTrackType = Int32(static_cast<int32_t>(TrackType::INT));
534        Jump(&exit);
535    }
536    Bind(&notInt);
537    {
538        Label isObject(env);
539        Label isDouble(env);
540        BRANCH(TaggedIsObject(value), &isObject, &isDouble);
541        Bind(&isObject);
542        {
543            newTrackType = Int32(static_cast<int32_t>(TrackType::TAGGED));
544            Jump(&exit);
545        }
546        Bind(&isDouble);
547        {
548            newTrackType = Int32(static_cast<int32_t>(TrackType::DOUBLE));
549            Jump(&exit);
550        }
551    }
552    Bind(&exit);
553    auto ret = *newTrackType;
554    env->SubCfgExit();
555    return ret;
556}
557
558void ProfilerStubBuilder::ProfileBranch(
559    GateRef glue, SlotIDInfo slotInfo, GateRef func, GateRef profileTypeInfo, bool isTrue)
560{
561    auto env = GetEnvironment();
562    Label subEntry(env);
563    env->SubCfgEntry(&subEntry);
564    Label profiler(env);
565    Label icSlotValid(env);
566    Label hasSlot(env);
567    Label currentIsTrue(env);
568    Label currentIsFalse(env);
569    Label genCurrentWeight(env);
570    Label compareLabel(env);
571    Label updateSlot(env);
572    Label preProfile(env);
573    Label needUpdate(env);
574    Label exit(env);
575    DEFVARIABLE(oldPrama, VariableType::INT32(), Int32(PGOSampleType::None()));
576    DEFVARIABLE(newTrue, VariableType::INT32(), isTrue ? Int32(1) : Int32(0));
577    DEFVARIABLE(newFalse, VariableType::INT32(), isTrue ? Int32(0) : Int32(1));
578
579    BRANCH(IsProfileTypeInfoHotAndValid(profileTypeInfo), &profiler, &exit);
580    Bind(&profiler);
581    {
582        GateRef slotId = GetSlotID(slotInfo);
583        GateRef length = GetLengthOfTaggedArray(profileTypeInfo);
584        BRANCH(Int32LessThan(slotId, length), &icSlotValid, &exit);
585        Bind(&icSlotValid);
586        GateRef slotValue = GetValueFromTaggedArray(profileTypeInfo, slotId);
587        BRANCH(TaggedIsHole(slotValue), &exit, &hasSlot); // ishole -- isundefined
588        Bind(&hasSlot);
589        {
590            Label uninitialized(env);
591            BRANCH(TaggedIsInt(slotValue), &compareLabel, &uninitialized);
592            Bind(&compareLabel);
593            {
594                GateRef oldSlotValue = TaggedGetInt(slotValue);
595                GateRef oldTrue = Int32LSR(oldSlotValue, Int32(PGOSampleType::WEIGHT_TRUE_START_BIT));
596                GateRef oldFalse = Int32LSR(oldSlotValue, Int32(PGOSampleType::WEIGHT_START_BIT));
597                oldFalse = Int32And(oldFalse, Int32(PGOSampleType::WEIGHT_MASK));
598                oldPrama = Int32And(oldSlotValue, Int32(PGOSampleType::AnyType()));
599                auto condition = BitAnd(Int32LessThan(oldTrue, Int32(PGOSampleType::WEIGHT_THRESHOLD)),
600                                        Int32LessThan(oldFalse, Int32(PGOSampleType::WEIGHT_THRESHOLD)));
601                BRANCH(condition, &needUpdate, &exit); // WEIGHT_THRESHOLD: 2047 limit
602                Bind(&needUpdate);
603                {
604                    newTrue = Int32Add(*newTrue, oldTrue);
605                    newFalse = Int32Add(*newFalse, oldFalse);
606                    Jump(&updateSlot);
607                }
608            }
609            Bind(&uninitialized);
610            {
611                // Only when slot value is undefined, it means uninitialized, so we need to update the slot.
612                // When the slot value is hole, it means slot is overflow (0xff). Otherwise, do nothing.
613                BRANCH(TaggedIsUndefined(slotValue), &updateSlot, &exit);
614            }
615            Bind(&updateSlot);
616            {
617                GateRef newSlotValue =
618                    Int32Or(*oldPrama, Int32LSL(*newTrue, Int32(PGOSampleType::WEIGHT_TRUE_START_BIT)));
619                newSlotValue = Int32Or(newSlotValue, Int32LSL(*newFalse, Int32(PGOSampleType::WEIGHT_START_BIT)));
620                SetValueToTaggedArray(
621                    VariableType::JS_ANY(), glue, profileTypeInfo, slotId, IntToTaggedInt(newSlotValue));
622                auto isFinal = BitOr(Int32Equal(*newTrue, Int32(PGOSampleType::WEIGHT_THRESHOLD)),
623                                     Int32Equal(*newFalse, Int32(PGOSampleType::WEIGHT_THRESHOLD)));
624                BRANCH(isFinal, &preProfile, &exit);
625            }
626            Bind(&preProfile);
627            {
628                TryPreDumpInner(glue, func, profileTypeInfo);
629                Jump(&exit);
630            }
631        }
632    }
633    Bind(&exit);
634    env->SubCfgExit();
635}
636
637void ProfilerStubBuilder::TryPreDumpInner(GateRef glue, GateRef func, GateRef profileTypeInfo)
638{
639    auto env = GetEnvironment();
640    Label subEntry(env);
641    env->SubCfgEntry(&subEntry);
642    Label setPreDumpPeriodIndex(env);
643    Label isInPredumpWorkList(env);
644    Label addPredumpWorkList(env);
645    Label exit(env);
646    BRANCH(IsProfileTypeInfoPreDumped(profileTypeInfo), &exit, &setPreDumpPeriodIndex);
647    Bind(&setPreDumpPeriodIndex);
648    {
649        SetPreDumpPeriodIndex(glue, profileTypeInfo);
650        Jump(&addPredumpWorkList);
651    }
652    Bind(&addPredumpWorkList);
653    {
654        CallRuntime(glue, RTSTUB_ID(PGOPreDump), { func });
655        Jump(&exit);
656    }
657    Bind(&exit);
658    env->SubCfgExit();
659}
660
661GateRef ProfilerStubBuilder::GetIterationFunctionId(GateRef glue, GateRef iterator)
662{
663    auto env = GetEnvironment();
664    Label subEntry(env);
665    env->SubCfgEntry(&subEntry);
666    Label exit(env);
667
668    DEFVARIABLE(functionId, VariableType::INT32(), Int32(PGO_BUILTINS_STUB_ID(NONE)));
669    DEFVARIABLE(maybeFunc, VariableType::JS_ANY(), Undefined());
670    Label isArrayProtoValues(env);
671    Label notArrayProtoValues(env);
672    Label isSetProtoValues(env);
673    Label notSetProtoValues(env);
674    Label isMapProtoEntries(env);
675    Label notMapProtoEntries(env);
676    Label isStringProtoIter(env);
677    Label notStringProtoIter(env);
678    Label isTypedArrayProtoValues(env);
679
680    GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit()));
681    GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset);
682    maybeFunc = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::ARRAY_PROTO_VALUES_FUNCTION_INDEX);
683    BRANCH(Int64Equal(iterator, *maybeFunc), &isArrayProtoValues, &notArrayProtoValues);
684    Bind(&isArrayProtoValues);
685    {
686        functionId = Int32(PGO_BUILTINS_STUB_ID(ArrayProtoIterator));
687        Jump(&exit);
688    }
689    Bind(&notArrayProtoValues);
690    maybeFunc = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::SET_PROTO_VALUES_FUNCTION_INDEX);
691    BRANCH(Int64Equal(iterator, *maybeFunc), &isSetProtoValues, &notSetProtoValues);
692    Bind(&isSetProtoValues);
693    {
694        functionId = Int32(PGO_BUILTINS_STUB_ID(SetProtoIterator));
695        Jump(&exit);
696    }
697    Bind(&notSetProtoValues);
698    maybeFunc = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::MAP_PROTO_ENTRIES_FUNCTION_INDEX);
699    BRANCH(Int64Equal(iterator, *maybeFunc), &isMapProtoEntries, &notMapProtoEntries);
700    Bind(&isMapProtoEntries);
701    {
702        functionId = Int32(PGO_BUILTINS_STUB_ID(MapProtoIterator));
703        Jump(&exit);
704    }
705    Bind(&notMapProtoEntries);
706    maybeFunc = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::STRING_PROTO_ITER_FUNCTION_INDEX);
707    BRANCH(Int64Equal(iterator, *maybeFunc), &isStringProtoIter, &notStringProtoIter);
708    Bind(&isStringProtoIter);
709    {
710        functionId = Int32(PGO_BUILTINS_STUB_ID(StringProtoIterator));
711        Jump(&exit);
712    }
713    Bind(&notStringProtoIter);
714    maybeFunc = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv,
715                                  GlobalEnv::TYPED_ARRAY_PROTO_VALUES_FUNCTION_INDEX);
716    BRANCH(Int64Equal(iterator, *maybeFunc), &isTypedArrayProtoValues, &exit);
717    Bind(&isTypedArrayProtoValues);
718    {
719        functionId = Int32(PGO_BUILTINS_STUB_ID(TypeArrayProtoIterator));
720        Jump(&exit);
721    }
722    Bind(&exit);
723    auto ret = *functionId;
724    env->SubCfgExit();
725    return ret;
726}
727
728void ProfilerStubBuilder::ProfileGetIterator(
729    GateRef glue, SlotIDInfo slotInfo, GateRef func, GateRef iterator, GateRef profileTypeInfo)
730{
731    auto env = GetEnvironment();
732    Label subEntry(env);
733    env->SubCfgEntry(&subEntry);
734
735    Label exit(env);
736    Label profiler(env);
737    BRANCH(IsProfileTypeInfoHotAndValid(profileTypeInfo), &profiler, &exit);
738    Bind(&profiler);
739    {
740        Label icSlotValid(env);
741        Label updateSlot(env);
742        Label initSlot(env);
743        Label sameValueCheck(env);
744        Label invalidate(env);
745        Label notOverflow(env);
746
747        GateRef slotId = GetSlotID(slotInfo);
748        GateRef length = GetLengthOfTaggedArray(profileTypeInfo);
749        BRANCH(Int32LessThan(slotId, length), &icSlotValid, &exit);
750        Bind(&icSlotValid);
751        GateRef slotValue = GetValueFromTaggedArray(profileTypeInfo, slotId);
752        BRANCH(TaggedIsHole(slotValue), &exit, &notOverflow); // hole -- slot is overflow
753        Bind(&notOverflow);
754        BRANCH(TaggedIsInt(slotValue), &updateSlot, &initSlot);
755        Bind(&updateSlot);
756        GateRef oldIterKind = TaggedGetInt(slotValue);
757        BRANCH(Int32Equal(oldIterKind, Int32(PGO_BUILTINS_STUB_ID(NONE))),
758            &exit, &sameValueCheck);
759        Bind(&sameValueCheck);
760        {
761            GateRef newIterKind = GetIterationFunctionId(glue, iterator);
762            BRANCH(Int32Equal(oldIterKind, newIterKind), &exit, &invalidate);
763        }
764        Bind(&invalidate);
765        {
766            GateRef invalidKind = Int32(PGO_BUILTINS_STUB_ID(NONE));
767            SetValueToTaggedArray(VariableType::JS_ANY(), glue, profileTypeInfo, slotId, IntToTaggedInt(invalidKind));
768            TryPreDumpInner(glue, func, profileTypeInfo);
769            Jump(&exit);
770        }
771        Bind(&initSlot);
772        {
773            GateRef newIterKind = GetIterationFunctionId(glue, iterator);
774            SetValueToTaggedArray(VariableType::JS_ANY(), glue, profileTypeInfo, slotId, IntToTaggedInt(newIterKind));
775            TryPreDumpInner(glue, func, profileTypeInfo);
776            Jump(&exit);
777        }
778    }
779    Bind(&exit);
780    env->SubCfgExit();
781}
782
783GateRef ProfilerStubBuilder::GetSlotID(const SlotIDInfo &slotInfo)
784{
785    auto slotType = slotInfo.GetSlotType();
786    if (slotType == SlotIDInfo::SlotIDInfoType::SLOT_ID) {
787        return slotInfo.GetSlotID();
788    }
789    if (slotType == SlotIDInfo::SlotIDInfoType::PC) {
790        // for PROFILE_BRANCH
791        return ZExtInt8ToInt32(Load(VariableType::INT8(), slotInfo.GetPC(), IntPtr(1)));
792    }
793    ASSERT(slotType == SlotIDInfo::SlotIDInfoType::PC_FORMAT);
794    auto format = slotInfo.GetFormat();
795    auto pc = slotInfo.GetPC();
796    if (format == SlotIDFormat::IMM16) {
797        auto hight = Load(VariableType::INT8(), pc, IntPtr(2)); // 2 : skip 1 byte of bytecode
798        hight = Int16LSL(ZExtInt8ToInt16(hight), Int16(8)); // 8 : set as high 8 bits
799        auto low = Load(VariableType::INT8(), pc, IntPtr(1));
800        auto result = Int16Add(hight, ZExtInt8ToInt16(low));
801        return ZExtInt16ToInt32(result);
802    } else if (format == SlotIDFormat::PREF_IMM8) {
803        return ZExtInt8ToInt32(Load(VariableType::INT8(), pc, IntPtr(2)));
804    }
805    return ZExtInt8ToInt32(Load(VariableType::INT8(), pc, IntPtr(1)));
806}
807
808GateRef ProfilerStubBuilder::GetBitFieldOffsetFromProfileTypeInfo(GateRef profileTypeInfo)
809{
810    auto length = GetLengthOfTaggedArray(profileTypeInfo);
811    auto index = Int32Sub(length, Int32(ProfileTypeInfo::BIT_FIELD_INDEX));
812    auto indexOffset = PtrMul(ZExtInt32ToPtr(index), IntPtr(JSTaggedValue::TaggedTypeSize()));
813    return PtrAdd(indexOffset, IntPtr(TaggedArray::DATA_OFFSET));
814}
815
816GateRef ProfilerStubBuilder::IsProfileTypeInfoDumped(GateRef profileTypeInfo)
817{
818    GateRef periodCounterOffset = GetBitFieldOffsetFromProfileTypeInfo(profileTypeInfo);
819    GateRef count = Load(VariableType::INT32(), profileTypeInfo, periodCounterOffset);
820    return Int32Equal(count, Int32(ProfileTypeInfo::DUMP_PERIOD_INDEX));
821}
822
823GateRef ProfilerStubBuilder::IsProfileTypeInfoPreDumped(GateRef profileTypeInfo)
824{
825    GateRef periodCounterOffset = GetBitFieldOffsetFromProfileTypeInfo(profileTypeInfo);
826    GateRef count = Load(VariableType::INT32(), profileTypeInfo, periodCounterOffset);
827    return Int32Equal(count, Int32(ProfileTypeInfo::PRE_DUMP_PERIOD_INDEX));
828}
829
830GateRef ProfilerStubBuilder::IsProfileTypeInfoWithBigMethod(GateRef profileTypeInfo)
831{
832    GateRef periodCounterOffset = GetBitFieldOffsetFromProfileTypeInfo(profileTypeInfo);
833    GateRef count = Load(VariableType::INT32(), profileTypeInfo, periodCounterOffset);
834    return Int32Equal(count, Int32(ProfileTypeInfo::BIG_METHOD_PERIOD_INDEX));
835}
836
837GateRef ProfilerStubBuilder::IsProfileTypeInfoHotAndValid(GateRef profileTypeInfo)
838{
839    auto env = GetEnvironment();
840    Label subEntry(env);
841    env->SubCfgEntry(&subEntry);
842    Label exit(env);
843    Label isHot(env);
844    Label hotAndValid(env);
845    DEFVARIABLE(res, VariableType::BOOL(), Boolean(false));
846    BRANCH(TaggedIsUndefined(profileTypeInfo), &exit, &isHot);
847    Bind(&isHot);
848    {
849        res = BoolNot(IsProfileTypeInfoWithBigMethod(profileTypeInfo));
850        Jump(&exit);
851    }
852    Bind(&exit);
853    auto ret = *res;
854    env->SubCfgExit();
855    return ret;
856}
857
858GateRef ProfilerStubBuilder::IsEnableForceIC(GateRef glue)
859{
860    auto env = GetEnvironment();
861    GateRef offset = IntPtr(JSThread::GlueData::GetIsEnableForceICOffSet(env->Is32Bit()));
862    return Load(VariableType::BOOL(), glue, offset);
863}
864
865void ProfilerStubBuilder::SetDumpPeriodIndex(GateRef glue, GateRef profileTypeInfo)
866{
867    GateRef periodCounterOffset = GetBitFieldOffsetFromProfileTypeInfo(profileTypeInfo);
868    GateRef newCount = Int32(ProfileTypeInfo::DUMP_PERIOD_INDEX);
869    Store(VariableType::INT32(), glue, profileTypeInfo, periodCounterOffset, newCount);
870}
871
872void ProfilerStubBuilder::SetPreDumpPeriodIndex(GateRef glue, GateRef profileTypeInfo)
873{
874    GateRef periodCounterOffset = GetBitFieldOffsetFromProfileTypeInfo(profileTypeInfo);
875    GateRef newCount = Int32(ProfileTypeInfo::PRE_DUMP_PERIOD_INDEX);
876    Store(VariableType::INT32(), glue, profileTypeInfo, periodCounterOffset, newCount);
877}
878
879GateRef ProfilerStubBuilder::IsCompiledOrTryCompile(GateRef glue, GateRef func, GateRef profileTypeInfo,
880                                                    ProfileOperation callback)
881{
882    if (callback.IsEmpty() && callback.IsJitEmpty()) {
883        return Boolean(true);
884    }
885    return IsCompiledOrTryCompile(glue, func, profileTypeInfo);
886}
887
888GateRef ProfilerStubBuilder::GetJitHotnessThresholdOffset(GateRef profileTypeInfo)
889{
890    GateRef bitFieldOffset = GetBitFieldOffsetFromProfileTypeInfo(profileTypeInfo);
891    return PtrAdd(bitFieldOffset,
892        IntPtr(ProfileTypeInfo::JIT_HOTNESS_THRESHOLD_OFFSET_FROM_BITFIELD));
893}
894
895GateRef ProfilerStubBuilder::GetJitHotnessCntOffset(GateRef profileTypeInfo)
896{
897    GateRef thresholdOffset = GetJitHotnessThresholdOffset(profileTypeInfo);
898    return PtrAdd(thresholdOffset, IntPtr(ProfileTypeInfo::JIT_CNT_OFFSET_FROM_THRESHOLD));
899}
900
901void ProfilerStubBuilder::SetJitHotnessCnt(GateRef glue, GateRef profileTypeInfo, GateRef hotnessCnt)
902{
903    GateRef hotnessCntOffset = GetJitHotnessCntOffset(profileTypeInfo);
904    Store(VariableType::INT16(), glue, profileTypeInfo, hotnessCntOffset, hotnessCnt);
905}
906
907GateRef ProfilerStubBuilder::GetJitHotnessCnt(GateRef profileTypeInfo)
908{
909    GateRef hotnessCntOffset = GetJitHotnessCntOffset(profileTypeInfo);
910    GateRef hotnessCnt = Load(VariableType::INT16(), profileTypeInfo, hotnessCntOffset);
911    return ZExtInt16ToInt32(hotnessCnt);
912}
913
914GateRef ProfilerStubBuilder::GetJitHotnessThreshold(GateRef profileTypeInfo)
915{
916    GateRef hotnessThresholdOffset = GetJitHotnessThresholdOffset(profileTypeInfo);
917    GateRef hotnessThreshold = Load(VariableType::INT16(), profileTypeInfo, hotnessThresholdOffset);
918    return ZExtInt16ToInt32(hotnessThreshold);
919}
920
921GateRef ProfilerStubBuilder::GetJitCallThresholdOffset(GateRef profileTypeInfo)
922{
923    GateRef bitFieldOffset = GetBitFieldOffsetFromProfileTypeInfo(profileTypeInfo);
924    return PtrAdd(bitFieldOffset,
925                  IntPtr(ProfileTypeInfo::JIT_CALL_THRESHOLD_OFFSET_FROM_BITFIELD));
926}
927
928GateRef ProfilerStubBuilder::GetJitCallThreshold(GateRef profileTypeInfo)
929{
930    GateRef jitCallThresholdOffset = GetJitCallThresholdOffset(profileTypeInfo);
931    GateRef jitCallThreshold = Load(VariableType::INT8(), profileTypeInfo, jitCallThresholdOffset);
932    return ZExtInt8ToInt32(jitCallThreshold);
933}
934
935GateRef ProfilerStubBuilder::GetJitCallCntOffset(GateRef profileTypeInfo)
936{
937    GateRef jitCallThresholdOffset = GetJitCallThresholdOffset(profileTypeInfo);
938    return PtrAdd(jitCallThresholdOffset, IntPtr(ProfileTypeInfo::JIT_CALL_CNT_OFFSET_FROM_JIT_CALL_THRESHOLD));
939}
940
941GateRef ProfilerStubBuilder::GetJitCallCnt(GateRef profileTypeInfo)
942{
943    GateRef jitCallCntOffset = GetJitCallCntOffset(profileTypeInfo);
944    GateRef jitCallCnt = Load(VariableType::INT8(), profileTypeInfo, jitCallCntOffset);
945    return ZExtInt8ToInt32(jitCallCnt);
946}
947
948GateRef ProfilerStubBuilder::GetOsrHotnessThresholdOffset(GateRef profileTypeInfo)
949{
950    GateRef bitFieldOffset = GetBitFieldOffsetFromProfileTypeInfo(profileTypeInfo);
951    return PtrAdd(bitFieldOffset,
952                  IntPtr(ProfileTypeInfo::OSR_HOTNESS_THRESHOLD_OFFSET_FROM_BITFIELD));
953}
954
955GateRef ProfilerStubBuilder::GetOsrHotnessThreshold(GateRef profileTypeInfo)
956{
957    GateRef hotnessThresholdOffset = GetOsrHotnessThresholdOffset(profileTypeInfo);
958    GateRef hotnessThreshold = Load(VariableType::INT16(), profileTypeInfo, hotnessThresholdOffset);
959    return ZExtInt16ToInt32(hotnessThreshold);
960}
961
962GateRef ProfilerStubBuilder::GetBaselineJitHotnessThresholdOffset(GateRef profileTypeInfo)
963{
964    GateRef bitFieldOffset = GetBitFieldOffsetFromProfileTypeInfo(profileTypeInfo);
965    return PtrAdd(bitFieldOffset,
966                  IntPtr(ProfileTypeInfo::BASELINEJIT_HOTNESS_THRESHOLD_OFFSET_FROM_BITFIELD));
967}
968
969GateRef ProfilerStubBuilder::GetBaselineJitHotnessThreshold(GateRef profileTypeInfo)
970{
971    GateRef hotnessThresholdOffset = GetBaselineJitHotnessThresholdOffset(profileTypeInfo);
972    GateRef hotnessThreshold = Load(VariableType::INT16(), profileTypeInfo, hotnessThresholdOffset);
973    return ZExtInt16ToInt32(hotnessThreshold);
974}
975
976GateRef ProfilerStubBuilder::GetOsrHotnessCntOffset(GateRef profileTypeInfo)
977{
978    GateRef thresholdOffset = GetOsrHotnessThresholdOffset(profileTypeInfo);
979    return PtrAdd(thresholdOffset, IntPtr(ProfileTypeInfo::OSR_CNT_OFFSET_FROM_OSR_THRESHOLD));
980}
981
982GateRef ProfilerStubBuilder::GetOsrHotnessCnt(GateRef profileTypeInfo)
983{
984    GateRef hotnessCntOffset = GetOsrHotnessCntOffset(profileTypeInfo);
985    GateRef hotnessCnt = Load(VariableType::INT16(), profileTypeInfo, hotnessCntOffset);
986    return ZExtInt16ToInt32(hotnessCnt);
987}
988
989GateRef ProfilerStubBuilder::IsCompiledOrTryCompile(GateRef glue, GateRef func, GateRef profileTypeInfo)
990{
991    auto env = GetEnvironment();
992    Label subEntry(env);
993    env->SubCfgEntry(&subEntry);
994
995    DEFVARIABLE(result, VariableType::BOOL(), False());
996
997    GateRef hotnessThreshold = GetJitHotnessThreshold(profileTypeInfo);
998    GateRef hotnessCnt = GetJitHotnessCnt(profileTypeInfo);
999    GateRef jitCallThreshold = GetJitCallThreshold(profileTypeInfo);
1000    GateRef jitCallCnt = GetJitCallCnt(profileTypeInfo);
1001
1002    Label cmpJitHotnessCnt(env);
1003    Label checkJitCallThreshold(env);
1004    Label cmpJitCallThreshold(env);
1005    Label equalJitCallThreshold(env);
1006    Label notEqualJitCallThreshold(env);
1007    Label incJitCallCnt(env);
1008    Label setResultAsTrue(env);
1009    Label exit(env);
1010
1011    Branch(Int32Equal(hotnessThreshold, Int32(ProfileTypeInfo::JIT_DISABLE_FLAG)), &setResultAsTrue, &cmpJitHotnessCnt);
1012    Bind(&cmpJitHotnessCnt);
1013    BRANCH(Int32GreaterThan(hotnessCnt, hotnessThreshold), &setResultAsTrue, &checkJitCallThreshold);
1014    Bind(&checkJitCallThreshold);
1015    BRANCH(Int32Equal(jitCallThreshold, Int32(ProfileTypeInfo::INITIAL_JIT_CALL_THRESHOLD)),
1016           &exit, &cmpJitCallThreshold);
1017    Bind(&cmpJitCallThreshold);
1018    BRANCH(Int32Equal(jitCallCnt, jitCallThreshold), &equalJitCallThreshold, &notEqualJitCallThreshold);
1019    Bind(&equalJitCallThreshold);
1020    {
1021        DEFVARIABLE(invalidOsrOffset, VariableType::INT32(), Int32(MachineCode::INVALID_OSR_OFFSET));
1022        CallRuntime(glue, RTSTUB_ID(JitCompile), { func, IntToTaggedInt(*invalidOsrOffset) });
1023        GateRef newJitCallCnt = Int32Add(jitCallCnt, Int32(1));
1024        GateRef jitCallCntOffset = GetJitCallCntOffset(profileTypeInfo);
1025        Store(VariableType::INT8(), glue, profileTypeInfo, jitCallCntOffset, TruncInt32ToInt8(newJitCallCnt));
1026        Jump(&setResultAsTrue);
1027    }
1028    Bind(&notEqualJitCallThreshold);
1029    BRANCH(Int32LessThan(jitCallCnt, jitCallThreshold), &incJitCallCnt, &setResultAsTrue);
1030    Bind(&incJitCallCnt);
1031    {
1032        GateRef newJitCallCnt = Int32Add(jitCallCnt, Int32(1));
1033        GateRef jitCallCntOffset = GetJitCallCntOffset(profileTypeInfo);
1034        Store(VariableType::INT8(), glue, profileTypeInfo, jitCallCntOffset, TruncInt32ToInt8(newJitCallCnt));
1035        Jump(&exit);
1036    }
1037    Bind(&setResultAsTrue);
1038    result = True();
1039    Jump(&exit);
1040    Bind(&exit);
1041    GateRef ret = *result;
1042    env->SubCfgExit();
1043    return ret;
1044}
1045
1046void ProfilerStubBuilder::TryJitCompile(GateRef glue, OffsetInfo offsetInfo,
1047                                        GateRef func, GateRef profileTypeInfo)
1048{
1049    auto env = GetEnvironment();
1050    Label subEntry(env);
1051    env->SubCfgEntry(&subEntry);
1052    Label equalJitThreshold(env);
1053    Label equalBaselineJitThreshold(env);
1054    Label notEqualJitThreshold(env);
1055    Label checkEqualJitThreshold(env);
1056    Label incJitHotnessCntAndCmpOpcode(env);
1057    Label incJitHotnessCntAndExit(env);
1058    Label cmpOpcode(env);
1059    Label cmpOsrThreshold(env);
1060    Label equalOsrThreshold(env);
1061    Label notEqualOsrThreshold(env);
1062    Label incOsrHotnessCnt(env);
1063    Label checkFastJit(env);
1064    Label checkBaselineJit(env);
1065    Label exit(env);
1066    Label checkNeedIncHotnessCnt(env);
1067
1068    GateRef jitHotnessThreshold = GetJitHotnessThreshold(profileTypeInfo);
1069    GateRef jitHotnessCnt = GetJitHotnessCnt(profileTypeInfo);
1070    GateRef osrHotnessThreshold = GetOsrHotnessThreshold(profileTypeInfo);
1071    GateRef osrHotnessCnt = GetOsrHotnessCnt(profileTypeInfo);
1072    GateRef baselineJitHotnessThreshold = GetBaselineJitHotnessThreshold(profileTypeInfo);
1073    Branch(Int32Equal(baselineJitHotnessThreshold, Int32(ProfileTypeInfo::JIT_DISABLE_FLAG)),
1074        &checkFastJit, &checkBaselineJit);
1075
1076    Bind(&checkBaselineJit);
1077    BRANCH(Int32Equal(jitHotnessCnt, baselineJitHotnessThreshold),
1078        &equalBaselineJitThreshold, &checkFastJit);
1079    Bind(&equalBaselineJitThreshold);
1080    {
1081        CallRuntime(glue, RTSTUB_ID(BaselineJitCompile), { func });
1082        Jump(&checkFastJit);
1083    }
1084
1085    Bind(&checkFastJit);
1086    Branch(Int32Equal(jitHotnessThreshold, Int32(ProfileTypeInfo::JIT_DISABLE_FLAG)),
1087        &checkNeedIncHotnessCnt, &checkEqualJitThreshold);
1088    Bind(&checkNeedIncHotnessCnt);
1089    Branch(Int32Equal(baselineJitHotnessThreshold, Int32(ProfileTypeInfo::JIT_DISABLE_FLAG)),
1090        &exit, &incJitHotnessCntAndExit);
1091
1092    Bind(&checkEqualJitThreshold);
1093    BRANCH(Int32Equal(jitHotnessCnt, jitHotnessThreshold), &equalJitThreshold, &notEqualJitThreshold);
1094    Bind(&equalJitThreshold);
1095    {
1096        DEFVARIABLE(varOffset, VariableType::INT32(), Int32(MachineCode::INVALID_OSR_OFFSET));
1097        CallRuntime(glue, RTSTUB_ID(JitCompile), { func, IntToTaggedInt(*varOffset) });
1098        Jump(&incJitHotnessCntAndExit);
1099    }
1100    Bind(&notEqualJitThreshold);
1101    {
1102        BRANCH(Int32LessThan(jitHotnessCnt, jitHotnessThreshold), &incJitHotnessCntAndCmpOpcode, &exit);
1103    }
1104    Bind(&incJitHotnessCntAndCmpOpcode);
1105    {
1106#if ECMASCRIPT_ENABLE_JIT_WARMUP_PROFILER
1107        CallRuntime(glue, RTSTUB_ID(CountInterpExecFuncs), { func });
1108#endif
1109        GateRef newJitHotnessCnt = Int16Add(jitHotnessCnt, Int16(1));
1110        GateRef jitHotnessCntOffset = GetJitHotnessCntOffset(profileTypeInfo);
1111        Store(VariableType::INT16(), glue, profileTypeInfo, jitHotnessCntOffset, newJitHotnessCnt);
1112        Jump(&cmpOpcode);
1113    }
1114    Bind(&incJitHotnessCntAndExit);
1115    {
1116        GateRef newJitHotnessCnt = Int16Add(jitHotnessCnt, Int16(1));
1117        GateRef jitHotnessCntOffset = GetJitHotnessCntOffset(profileTypeInfo);
1118        Store(VariableType::INT16(), glue, profileTypeInfo, jitHotnessCntOffset, newJitHotnessCnt);
1119        Jump(&exit);
1120    }
1121    Bind(&cmpOpcode);
1122    {
1123        GateRef isJmp = 0;
1124        if (offsetInfo.isPc) {
1125            GateRef opcode = Load(VariableType::INT8(), offsetInfo.pc);
1126            GateRef jmpImm8 = Int8(static_cast<uint8_t>(EcmaOpcode::JMP_IMM8));
1127            GateRef jmpImm16 = Int8(static_cast<uint8_t>(EcmaOpcode::JMP_IMM16));
1128            GateRef jmpImm32 = Int8(static_cast<uint8_t>(EcmaOpcode::JMP_IMM32));
1129            isJmp = BitOr(Int8Equal(opcode, jmpImm8), Int8Equal(opcode, jmpImm16));
1130            isJmp = BitOr(isJmp, Int8Equal(opcode, jmpImm32));
1131        } else {
1132            isJmp = Boolean(offsetInfo.offset == 0);
1133        }
1134        BRANCH(isJmp, &cmpOsrThreshold, &exit);
1135    }
1136    Bind(&cmpOsrThreshold);
1137    {
1138        BRANCH(Int32Equal(osrHotnessCnt, osrHotnessThreshold), &equalOsrThreshold, &notEqualOsrThreshold);
1139    }
1140    Bind(&equalOsrThreshold);
1141    {
1142        GateRef method = GetMethodFromJSFunctionOrProxy(func);
1143        GateRef firstPC = Load(VariableType::NATIVE_POINTER(), method,
1144                               IntPtr(Method::NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET));
1145        GateRef offset = offsetInfo.isPc ? TaggedPtrToTaggedIntPtr(PtrSub(offsetInfo.pc, firstPC))
1146                                         : offsetInfo.offset;
1147        CallRuntime(glue, RTSTUB_ID(JitCompile), { func, offset });
1148        GateRef osrHotnessCntOffset = GetOsrHotnessCntOffset(profileTypeInfo);
1149        Store(VariableType::INT16(), glue, profileTypeInfo, osrHotnessCntOffset, Int16(0));
1150        Jump(&exit);
1151    }
1152    Bind(&notEqualOsrThreshold);
1153    {
1154        BRANCH(Int32LessThan(osrHotnessCnt, osrHotnessThreshold), &incOsrHotnessCnt, &exit);
1155    }
1156    Bind(&incOsrHotnessCnt);
1157    {
1158        GateRef newOsrHotnessCnt = Int16Add(osrHotnessCnt, Int16(1));
1159        GateRef osrHotnessCntOffset = GetOsrHotnessCntOffset(profileTypeInfo);
1160        Store(VariableType::INT16(), glue, profileTypeInfo, osrHotnessCntOffset, newOsrHotnessCnt);
1161        Jump(&exit);
1162    }
1163    Bind(&exit);
1164    env->SubCfgExit();
1165}
1166
1167void ProfilerStubBuilder::PGOProfiler(GateRef glue, GateRef func, GateRef profileTypeInfo,
1168    SlotIDInfo slotIdInfo, const std::vector<GateRef> &values, OperationType type)
1169{
1170    switch (type) {
1171        case OperationType::CALL:
1172            ProfileCall(glue, slotIdInfo, func, values[0], profileTypeInfo);
1173            break;
1174        case OperationType::NATIVE_CALL:
1175            ProfileNativeCall(glue, slotIdInfo, func, values[0], profileTypeInfo);
1176            break;
1177        case OperationType::GETTER_SETTER_CALL:
1178            ProfileGetterSetterCall(glue, values[0]);
1179            break;
1180        case OperationType::OPERATION_TYPE:
1181            ProfileOpType(glue, slotIdInfo, func, profileTypeInfo, values[0]);
1182            break;
1183        case OperationType::DEFINE_CLASS:
1184            ProfileDefineClass(glue, slotIdInfo, func, values[0], profileTypeInfo);
1185            break;
1186        case OperationType::CREATE_OBJECT:
1187            ProfileCreateObject(glue, slotIdInfo, func, values[0], profileTypeInfo);
1188            break;
1189        case OperationType::TRY_DUMP:
1190            TryDump(glue, func, profileTypeInfo);
1191            break;
1192        case OperationType::TRY_PREDUMP:
1193            TryPreDump(glue, func, profileTypeInfo);
1194            break;
1195        case OperationType::TRUE_BRANCH:
1196            ProfileBranch(glue, slotIdInfo, func, profileTypeInfo, true);
1197            break;
1198        case OperationType::FALSE_BRANCH:
1199            ProfileBranch(glue, slotIdInfo, func, profileTypeInfo, false);
1200            break;
1201        case OperationType::ITERATOR_FUNC_KIND:
1202            ProfileGetIterator(glue, slotIdInfo, func, values[0], profileTypeInfo);
1203            break;
1204        case OperationType::TRY_JIT:
1205            TryJitCompile(glue, { 0, slotIdInfo.GetPC(), true }, func, profileTypeInfo);
1206            break;
1207        default:
1208            break;
1209    }
1210}
1211} // namespace panda::ecmascript::kungfu
1212