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