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 
28 namespace panda::ecmascript::kungfu {
PGOProfiler(GateRef glue, GateRef pc, GateRef func, GateRef profileTypeInfo, const std::vector<GateRef> &values, SlotIDFormat format, OperationType type)29 void 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 
PGOProfiler(GateRef glue, GateRef func, GateRef profileTypeInfo, GateRef slotId, const std::vector<GateRef> &values, OperationType type)43 void 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 
TryDump(GateRef glue, GateRef func, GateRef profileTypeInfo)50 void 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 
TryPreDump(GateRef glue, GateRef func, GateRef profileTypeInfo)73 void 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 
ProfileOpType( GateRef glue, SlotIDInfo slotInfo, GateRef func, GateRef profileTypeInfo, GateRef type)90 void 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 
ProfileDefineClass( GateRef glue, SlotIDInfo slotInfo, GateRef func, GateRef constructor, GateRef profileTypeInfo)137 void 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 
ProfileCreateObject( GateRef glue, SlotIDInfo slotInfo, GateRef func, GateRef newObj, GateRef profileTypeInfo)176 void 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 
ProfileCall( GateRef glue, SlotIDInfo slotInfo, GateRef func, GateRef target, GateRef profileTypeInfo)228 void 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 
ProfileGetterSetterCall(GateRef glue, GateRef target)312 void 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 
TryGetBuiltinFunctionId(GateRef target)337 GateRef 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 
ProfileNativeCall( GateRef glue, SlotIDInfo slotInfo, GateRef func, GateRef target, GateRef profileTypeInfo)360 void 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 
IsProfileTypeInfoDumped(GateRef profileTypeInfo, ProfileOperation callback)415 GateRef ProfilerStubBuilder::IsProfileTypeInfoDumped(GateRef profileTypeInfo, ProfileOperation callback)
416 {
417     if (callback.IsEmpty()) {
418         return Boolean(true);
419     }
420     return IsProfileTypeInfoDumped(profileTypeInfo);
421 }
422 
UpdateTrackTypeInPropAttr(GateRef attr, GateRef value, ProfileOperation callback)423 GateRef 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 
UpdatePropAttrIC( GateRef glue, GateRef receiver, GateRef value, GateRef handler, ProfileOperation callback)462 void 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 
UpdatePropAttrWithValue(GateRef glue, GateRef receiver, GateRef attr, GateRef value, ProfileOperation callback)495 void 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 
TaggedToTrackType(GateRef value)520 GateRef 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 
ProfileBranch( GateRef glue, SlotIDInfo slotInfo, GateRef func, GateRef profileTypeInfo, bool isTrue)558 void 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 
TryPreDumpInner(GateRef glue, GateRef func, GateRef profileTypeInfo)637 void 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 
GetIterationFunctionId(GateRef glue, GateRef iterator)661 GateRef 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 
ProfileGetIterator( GateRef glue, SlotIDInfo slotInfo, GateRef func, GateRef iterator, GateRef profileTypeInfo)728 void 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 
GetSlotID(const SlotIDInfo &slotInfo)783 GateRef 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 
GetBitFieldOffsetFromProfileTypeInfo(GateRef profileTypeInfo)808 GateRef 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 
IsProfileTypeInfoDumped(GateRef profileTypeInfo)816 GateRef 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 
IsProfileTypeInfoPreDumped(GateRef profileTypeInfo)823 GateRef 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 
IsProfileTypeInfoWithBigMethod(GateRef profileTypeInfo)830 GateRef 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 
IsProfileTypeInfoHotAndValid(GateRef profileTypeInfo)837 GateRef 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 
IsEnableForceIC(GateRef glue)858 GateRef 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 
SetDumpPeriodIndex(GateRef glue, GateRef profileTypeInfo)865 void 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 
SetPreDumpPeriodIndex(GateRef glue, GateRef profileTypeInfo)872 void 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 
IsCompiledOrTryCompile(GateRef glue, GateRef func, GateRef profileTypeInfo, ProfileOperation callback)879 GateRef 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 
GetJitHotnessThresholdOffset(GateRef profileTypeInfo)888 GateRef 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 
GetJitHotnessCntOffset(GateRef profileTypeInfo)895 GateRef ProfilerStubBuilder::GetJitHotnessCntOffset(GateRef profileTypeInfo)
896 {
897     GateRef thresholdOffset = GetJitHotnessThresholdOffset(profileTypeInfo);
898     return PtrAdd(thresholdOffset, IntPtr(ProfileTypeInfo::JIT_CNT_OFFSET_FROM_THRESHOLD));
899 }
900 
SetJitHotnessCnt(GateRef glue, GateRef profileTypeInfo, GateRef hotnessCnt)901 void ProfilerStubBuilder::SetJitHotnessCnt(GateRef glue, GateRef profileTypeInfo, GateRef hotnessCnt)
902 {
903     GateRef hotnessCntOffset = GetJitHotnessCntOffset(profileTypeInfo);
904     Store(VariableType::INT16(), glue, profileTypeInfo, hotnessCntOffset, hotnessCnt);
905 }
906 
GetJitHotnessCnt(GateRef profileTypeInfo)907 GateRef ProfilerStubBuilder::GetJitHotnessCnt(GateRef profileTypeInfo)
908 {
909     GateRef hotnessCntOffset = GetJitHotnessCntOffset(profileTypeInfo);
910     GateRef hotnessCnt = Load(VariableType::INT16(), profileTypeInfo, hotnessCntOffset);
911     return ZExtInt16ToInt32(hotnessCnt);
912 }
913 
GetJitHotnessThreshold(GateRef profileTypeInfo)914 GateRef ProfilerStubBuilder::GetJitHotnessThreshold(GateRef profileTypeInfo)
915 {
916     GateRef hotnessThresholdOffset = GetJitHotnessThresholdOffset(profileTypeInfo);
917     GateRef hotnessThreshold = Load(VariableType::INT16(), profileTypeInfo, hotnessThresholdOffset);
918     return ZExtInt16ToInt32(hotnessThreshold);
919 }
920 
GetJitCallThresholdOffset(GateRef profileTypeInfo)921 GateRef 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 
GetJitCallThreshold(GateRef profileTypeInfo)928 GateRef ProfilerStubBuilder::GetJitCallThreshold(GateRef profileTypeInfo)
929 {
930     GateRef jitCallThresholdOffset = GetJitCallThresholdOffset(profileTypeInfo);
931     GateRef jitCallThreshold = Load(VariableType::INT8(), profileTypeInfo, jitCallThresholdOffset);
932     return ZExtInt8ToInt32(jitCallThreshold);
933 }
934 
GetJitCallCntOffset(GateRef profileTypeInfo)935 GateRef 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 
GetJitCallCnt(GateRef profileTypeInfo)941 GateRef ProfilerStubBuilder::GetJitCallCnt(GateRef profileTypeInfo)
942 {
943     GateRef jitCallCntOffset = GetJitCallCntOffset(profileTypeInfo);
944     GateRef jitCallCnt = Load(VariableType::INT8(), profileTypeInfo, jitCallCntOffset);
945     return ZExtInt8ToInt32(jitCallCnt);
946 }
947 
GetOsrHotnessThresholdOffset(GateRef profileTypeInfo)948 GateRef 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 
GetOsrHotnessThreshold(GateRef profileTypeInfo)955 GateRef ProfilerStubBuilder::GetOsrHotnessThreshold(GateRef profileTypeInfo)
956 {
957     GateRef hotnessThresholdOffset = GetOsrHotnessThresholdOffset(profileTypeInfo);
958     GateRef hotnessThreshold = Load(VariableType::INT16(), profileTypeInfo, hotnessThresholdOffset);
959     return ZExtInt16ToInt32(hotnessThreshold);
960 }
961 
GetBaselineJitHotnessThresholdOffset(GateRef profileTypeInfo)962 GateRef 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 
GetBaselineJitHotnessThreshold(GateRef profileTypeInfo)969 GateRef ProfilerStubBuilder::GetBaselineJitHotnessThreshold(GateRef profileTypeInfo)
970 {
971     GateRef hotnessThresholdOffset = GetBaselineJitHotnessThresholdOffset(profileTypeInfo);
972     GateRef hotnessThreshold = Load(VariableType::INT16(), profileTypeInfo, hotnessThresholdOffset);
973     return ZExtInt16ToInt32(hotnessThreshold);
974 }
975 
GetOsrHotnessCntOffset(GateRef profileTypeInfo)976 GateRef ProfilerStubBuilder::GetOsrHotnessCntOffset(GateRef profileTypeInfo)
977 {
978     GateRef thresholdOffset = GetOsrHotnessThresholdOffset(profileTypeInfo);
979     return PtrAdd(thresholdOffset, IntPtr(ProfileTypeInfo::OSR_CNT_OFFSET_FROM_OSR_THRESHOLD));
980 }
981 
GetOsrHotnessCnt(GateRef profileTypeInfo)982 GateRef ProfilerStubBuilder::GetOsrHotnessCnt(GateRef profileTypeInfo)
983 {
984     GateRef hotnessCntOffset = GetOsrHotnessCntOffset(profileTypeInfo);
985     GateRef hotnessCnt = Load(VariableType::INT16(), profileTypeInfo, hotnessCntOffset);
986     return ZExtInt16ToInt32(hotnessCnt);
987 }
988 
IsCompiledOrTryCompile(GateRef glue, GateRef func, GateRef profileTypeInfo)989 GateRef 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 
TryJitCompile(GateRef glue, OffsetInfo offsetInfo, GateRef func, GateRef profileTypeInfo)1046 void 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 
PGOProfiler(GateRef glue, GateRef func, GateRef profileTypeInfo, SlotIDInfo slotIdInfo, const std::vector<GateRef> &values, OperationType type)1167 void 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