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