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