• 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     switch (type) {
30         case OperationType::CALL:
31             ProfileCall(glue, pc, func, values[0], profileTypeInfo, format);
32             break;
33         case OperationType::NATIVE_CALL:
34             ProfileNativeCall(glue, pc, func, values[0], profileTypeInfo, format);
35             break;
36         case OperationType::OPERATION_TYPE:
37             ProfileOpType(glue, pc, func, profileTypeInfo, values[0], format);
38             break;
39         case OperationType::DEFINE_CLASS:
40             ProfileDefineClass(glue, pc, func, values[0], profileTypeInfo, format);
41             break;
42         case OperationType::CREATE_OBJECT:
43             ProfileCreateObject(glue, pc, func, values[0], profileTypeInfo, format);
44             break;
45         case OperationType::TRY_DUMP:
46             TryDump(glue, func, profileTypeInfo);
47             break;
48         case OperationType::TRY_PREDUMP:
49             TryPreDump(glue, func, profileTypeInfo);
50             break;
51         case OperationType::TRUE_BRANCH:
52             ProfileBranch(glue, pc, func, profileTypeInfo, true);
53             break;
54         case OperationType::FALSE_BRANCH:
55             ProfileBranch(glue, pc, func, profileTypeInfo, false);
56             break;
57         case OperationType::ITERATOR_FUNC_KIND:
58             ProfileGetIterator(glue, pc, func, values[0], profileTypeInfo, format);
59             break;
60         case OperationType::TRY_JIT:
61             TryJitCompile(glue, func, profileTypeInfo);
62             break;
63         default:
64             break;
65     }
66 }
67 
TryDump(GateRef glue,GateRef func,GateRef profileTypeInfo)68 void ProfilerStubBuilder::TryDump(GateRef glue, GateRef func, GateRef profileTypeInfo)
69 {
70     auto env = GetEnvironment();
71     Label subEntry(env);
72     env->SubCfgEntry(&subEntry);
73 
74     Label updatePeriodCounter(env);
75     Label exit(env);
76 
77     Branch(IsProfileTypeInfoDumped(profileTypeInfo), &exit, &updatePeriodCounter);
78     Bind(&updatePeriodCounter);
79     {
80         SetDumpPeriodIndex(glue, profileTypeInfo);
81         CallRuntime(glue, RTSTUB_ID(PGODump), { func });
82         Jump(&exit);
83     }
84     Bind(&exit);
85     env->SubCfgExit();
86 }
87 
TryPreDump(GateRef glue,GateRef func,GateRef profileTypeInfo)88 void ProfilerStubBuilder::TryPreDump(GateRef glue, GateRef func, GateRef profileTypeInfo)
89 {
90     auto env = GetEnvironment();
91     Label subEntry(env);
92     env->SubCfgEntry(&subEntry);
93     Label exit(env);
94     Label profiler(env);
95     Branch(TaggedIsUndefined(profileTypeInfo), &exit, &profiler);
96     Bind(&profiler);
97     {
98         TryPreDumpInner(glue, func, profileTypeInfo);
99         Jump(&exit);
100     }
101     Bind(&exit);
102     env->SubCfgExit();
103 }
104 
ProfileOpType(GateRef glue,GateRef pc,GateRef func,GateRef profileTypeInfo,GateRef type,SlotIDFormat format)105 void ProfilerStubBuilder::ProfileOpType(
106     GateRef glue, GateRef pc, GateRef func, GateRef profileTypeInfo, GateRef type, SlotIDFormat format)
107 {
108     auto env = GetEnvironment();
109     Label subEntry(env);
110     env->SubCfgEntry(&subEntry);
111 
112     Label exit(env);
113     Label profiler(env);
114     Branch(TaggedIsUndefined(profileTypeInfo), &exit, &profiler);
115     Bind(&profiler);
116     {
117         Label icSlotValid(env);
118         Label uninitialize(env);
119         Label compareLabel(env);
120         Label updateSlot(env);
121 
122         GateRef slotId = GetSlotID(pc, format);
123         GateRef length = GetLengthOfTaggedArray(profileTypeInfo);
124         Branch(Int32LessThan(slotId, length), &icSlotValid, &exit);
125         Bind(&icSlotValid);
126         GateRef slotValue = GetValueFromTaggedArray(profileTypeInfo, slotId);
127         DEFVARIABLE(curType, VariableType::INT32(), type);
128         DEFVARIABLE(curCount, VariableType::INT32(), Int32(0));
129         Branch(TaggedIsInt(slotValue), &compareLabel, &uninitialize);
130         Bind(&compareLabel);
131         {
132             GateRef oldSlotValue = TaggedGetInt(slotValue);
133             GateRef oldType = Int32And(oldSlotValue, Int32(PGOSampleType::AnyType()));
134             curType = Int32Or(oldType, type);
135             curCount = Int32And(oldSlotValue, Int32(0xfffffc00));   // 0xfffffc00: count bits
136             Branch(Int32Equal(oldType, *curType), &exit, &updateSlot);
137         }
138         Bind(&uninitialize);
139         {
140             // Slot maybe overflow.
141             Branch(TaggedIsUndefined(slotValue), &updateSlot, &exit);
142         }
143         Bind(&updateSlot);
144         {
145             GateRef newSlotValue = Int32Or(*curCount, *curType);
146             SetValueToTaggedArray(VariableType::JS_ANY(), glue, profileTypeInfo, slotId, IntToTaggedInt(newSlotValue));
147             TryPreDumpInner(glue, func, profileTypeInfo);
148             Jump(&exit);
149         }
150     }
151     Bind(&exit);
152     env->SubCfgExit();
153 }
154 
ProfileDefineClass(GateRef glue,GateRef pc,GateRef func,GateRef constructor,GateRef profileTypeInfo,SlotIDFormat format)155 void ProfilerStubBuilder::ProfileDefineClass(
156     GateRef glue, GateRef pc, GateRef func, GateRef constructor, GateRef profileTypeInfo, SlotIDFormat format)
157 {
158     auto env = GetEnvironment();
159     Label subEntry(env);
160     env->SubCfgEntry(&subEntry);
161 
162     Label exit(env);
163     Label profiler(env);
164     Branch(TaggedIsUndefined(profileTypeInfo), &exit, &profiler);
165     Bind(&profiler);
166     {
167         Label icSlotValid(env);
168         Label updateSlot(env);
169 
170         GateRef slotId = GetSlotID(pc, format);
171         GateRef length = GetLengthOfTaggedArray(profileTypeInfo);
172         Branch(Int32LessThan(slotId, length), &icSlotValid, &exit);
173         Bind(&icSlotValid);
174         GateRef slotValue = GetValueFromTaggedArray(profileTypeInfo, slotId);
175         Branch(TaggedIsUndefined(slotValue), &updateSlot, &exit);
176         Bind(&updateSlot);
177         auto weakCtor = env->GetBuilder()->CreateWeakRef(constructor);
178         SetValueToTaggedArray(VariableType::JS_ANY(), glue, profileTypeInfo, slotId, weakCtor);
179         TryPreDumpInner(glue, func, profileTypeInfo);
180         Jump(&exit);
181     }
182     Bind(&exit);
183     env->SubCfgExit();
184 }
185 
ProfileCreateObject(GateRef glue,GateRef pc,GateRef func,GateRef newObj,GateRef profileTypeInfo,SlotIDFormat format)186 void ProfilerStubBuilder::ProfileCreateObject(
187     GateRef glue, GateRef pc, GateRef func, GateRef newObj, GateRef profileTypeInfo, SlotIDFormat format)
188 {
189     auto env = GetEnvironment();
190     Label subEntry(env);
191     env->SubCfgEntry(&subEntry);
192     Label exit(env);
193 
194     Label profiler(env);
195     Branch(TaggedIsUndefined(profileTypeInfo), &exit, &profiler);
196     Bind(&profiler);
197     {
198         Label icSlotValid(env);
199         Label isHeapObject(env);
200         Label isWeak(env);
201         Label uninitialized(env);
202         Label updateSlot(env);
203 
204         GateRef slotId = GetSlotID(pc, format);
205         GateRef length = GetLengthOfTaggedArray(profileTypeInfo);
206         Branch(Int32LessThan(slotId, length), &icSlotValid, &exit);
207         Bind(&icSlotValid);
208         auto hclass = LoadHClass(newObj);
209         GateRef slotValue = GetValueFromTaggedArray(profileTypeInfo, slotId);
210         Branch(TaggedIsHeapObject(slotValue), &isHeapObject, &uninitialized);
211         Bind(&isHeapObject);
212         {
213             Branch(TaggedIsWeak(slotValue), &isWeak, &updateSlot);
214         }
215         Bind(&isWeak);
216         {
217             auto cachedHClass = LoadObjectFromWeakRef(slotValue);
218             Branch(Equal(cachedHClass, hclass), &exit, &updateSlot);
219         }
220         Bind(&uninitialized);
221         {
222             Branch(TaggedIsUndefined(slotValue), &updateSlot, &exit);
223         }
224         Bind(&updateSlot);
225         {
226             auto weakCtor = env->GetBuilder()->CreateWeakRef(hclass);
227             SetValueToTaggedArray(VariableType::JS_ANY(), glue, profileTypeInfo, slotId, weakCtor);
228             TryPreDumpInner(glue, func, profileTypeInfo);
229             Jump(&exit);
230         }
231     }
232     Bind(&exit);
233     env->SubCfgExit();
234 }
235 
ProfileCall(GateRef glue,GateRef pc,GateRef func,GateRef target,GateRef profileTypeInfo,SlotIDFormat format)236 void ProfilerStubBuilder::ProfileCall(
237     GateRef glue, GateRef pc, GateRef func, GateRef target, GateRef profileTypeInfo, SlotIDFormat format)
238 {
239     auto env = GetEnvironment();
240     Label subEntry(env);
241     env->SubCfgEntry(&subEntry);
242 
243     Label exit(env);
244     Label slowpath(env);
245     Label fastpath(env);
246 
247     Label targetIsFunction(env);
248     Branch(IsJSFunction(target), &targetIsFunction, &exit);
249     Bind(&targetIsFunction);
250     {
251         GateRef targetProfileInfo = GetProfileTypeInfo(target);
252         Label targetNonHotness(env);
253         Label IsCurrentHotness(env);
254         Label currentIsHotness(env);
255         Branch(TaggedIsUndefined(targetProfileInfo), &targetNonHotness, &IsCurrentHotness);
256         Bind(&targetNonHotness);
257         {
258             CallRuntime(glue, RTSTUB_ID(UpdateHotnessCounterWithProf), { target });
259             Jump(&IsCurrentHotness);
260         }
261         Bind(&IsCurrentHotness);
262         {
263             Branch(TaggedIsUndefined(profileTypeInfo), &exit, &currentIsHotness);
264         }
265         Bind(&currentIsHotness);
266         {
267             Label icSlotValid(env);
268             Label isInt(env);
269             Label uninitialized(env);
270             Label updateSlot(env);
271 
272             GateRef slotId = GetSlotID(pc, format);
273             GateRef length = GetLengthOfTaggedArray(profileTypeInfo);
274             Branch(Int32LessThan(slotId, length), &icSlotValid, &exit);
275             Bind(&icSlotValid);
276             GateRef slotValue = GetValueFromTaggedArray(profileTypeInfo, slotId);
277             Branch(TaggedIsInt(slotValue), &isInt, &uninitialized);
278             Bind(&isInt);
279             {
280                 Label change(env);
281                 Label resetSlot(env);
282                 GateRef oldSlotValue = TaggedGetInt(slotValue);
283                 GateRef methodId = env->GetBuilder()->GetMethodId(target);
284                 Branch(Int32Equal(oldSlotValue, TruncInt64ToInt32(methodId)), &exit, &change);
285                 Bind(&change);
286                 {
287                     GateRef polyCallCheck = Int32Equal(oldSlotValue, Int32(base::PGO_POLY_INLINE_REP));
288                     GateRef emptyCallCheck = Int32Equal(oldSlotValue, Int32(0));
289                     Branch(BoolOr(polyCallCheck, emptyCallCheck), &exit, &resetSlot);
290                 }
291                 Bind(&resetSlot);
292                 {
293                     GateRef nonType = IntToTaggedInt(Int32(base::PGO_POLY_INLINE_REP));
294                     SetValueToTaggedArray(VariableType::JS_ANY(), glue, profileTypeInfo, slotId, nonType);
295                     TryPreDumpInner(glue, func, profileTypeInfo);
296                     Jump(&exit);
297                 }
298             }
299             Bind(&uninitialized);
300             {
301                 Branch(TaggedIsUndefined(slotValue), &updateSlot, &exit);
302             }
303             Bind(&updateSlot);
304             {
305                 GateRef methodId = env->GetBuilder()->GetMethodId(target);
306                 GateRef methodIdValue = IntToTaggedInt(TruncInt64ToInt32(methodId));
307                 SetValueToTaggedArray(VariableType::JS_ANY(), glue, profileTypeInfo, slotId, methodIdValue);
308                 TryPreDumpInner(glue, func, profileTypeInfo);
309                 Jump(&exit);
310             }
311         }
312     }
313     Bind(&exit);
314     env->SubCfgExit();
315 }
316 
TryGetBuiltinFunctionId(GateRef target)317 GateRef ProfilerStubBuilder::TryGetBuiltinFunctionId(GateRef target)
318 {
319     auto env = GetEnvironment();
320     Label subEntry(env);
321     env->SubCfgEntry(&subEntry);
322     Label targetIsFunction(env);
323     Label exit(env);
324 
325     DEFVARIABLE(functionId, VariableType::INT32(), Int32(PGO_BUILTINS_STUB_ID(NONE)));
326     Branch(IsJSFunction(target), &targetIsFunction, &exit);
327     Bind(&targetIsFunction);
328     {
329         auto builtinsId = env->GetBuilder()->GetBuiltinsId(target);
330         functionId = Int32Mul(TruncInt64ToInt32(builtinsId), Int32(-1));
331         Jump(&exit);
332     }
333     Bind(&exit);
334     auto ret = *functionId;
335     env->SubCfgExit();
336     return ret;
337 }
338 
ProfileNativeCall(GateRef glue,GateRef pc,GateRef func,GateRef target,GateRef profileTypeInfo,SlotIDFormat format)339 void ProfilerStubBuilder::ProfileNativeCall(
340     GateRef glue, GateRef pc, GateRef func, GateRef target, GateRef profileTypeInfo, SlotIDFormat format)
341 {
342     auto env = GetEnvironment();
343     Label subEntry(env);
344     env->SubCfgEntry(&subEntry);
345 
346     Label exit(env);
347     Label currentIsHot(env);
348 
349     Branch(TaggedIsUndefined(profileTypeInfo), &exit, &currentIsHot);
350     Bind(&currentIsHot);
351     {
352         Label icSlotValid(env);
353         Label updateSlot(env);
354         Label initSlot(env);
355         Label sameValueCheck(env);
356         Label invalidate(env);
357 
358         GateRef slotId = GetSlotID(pc, format);
359         GateRef length = GetLengthOfTaggedArray(profileTypeInfo);
360         Branch(Int32LessThan(slotId, length), &icSlotValid, &exit);
361         Bind(&icSlotValid);
362         GateRef slotValue = GetValueFromTaggedArray(profileTypeInfo, slotId);
363         Branch(TaggedIsInt(slotValue), &updateSlot, &initSlot);
364         Bind(&updateSlot);
365         GateRef oldId = TaggedGetInt(slotValue);
366         Branch(Int32Equal(oldId, Int32(PGO_BUILTINS_STUB_ID(NONE))), &exit, &sameValueCheck);
367         Bind(&sameValueCheck);
368         {
369             GateRef newId = TryGetBuiltinFunctionId(target);
370             Branch(Int32Equal(oldId, newId), &exit, &invalidate);
371         }
372         Bind(&invalidate);
373         {
374             GateRef invalidId = Int32(PGO_BUILTINS_STUB_ID(NONE));
375             SetValueToTaggedArray(VariableType::JS_ANY(), glue, profileTypeInfo, slotId, IntToTaggedInt(invalidId));
376             TryPreDumpInner(glue, func, profileTypeInfo);
377             Jump(&exit);
378         }
379         Bind(&initSlot);
380         {
381             GateRef newId = TryGetBuiltinFunctionId(target);
382             SetValueToTaggedArray(VariableType::JS_ANY(), glue, profileTypeInfo, slotId, IntToTaggedInt(newId));
383             TryPreDumpInner(glue, func, profileTypeInfo);
384             Jump(&exit);
385         }
386     }
387     Bind(&exit);
388     env->SubCfgExit();
389 }
390 
IsProfileTypeInfoDumped(GateRef profileTypeInfo,ProfileOperation callback)391 GateRef ProfilerStubBuilder::IsProfileTypeInfoDumped(GateRef profileTypeInfo, ProfileOperation callback)
392 {
393     if (callback.IsEmpty()) {
394         return Boolean(true);
395     }
396     return IsProfileTypeInfoDumped(profileTypeInfo);
397 }
398 
UpdateTrackTypeInPropAttr(GateRef attr,GateRef value,ProfileOperation callback)399 GateRef ProfilerStubBuilder::UpdateTrackTypeInPropAttr(GateRef attr, GateRef value, ProfileOperation callback)
400 {
401     if (callback.IsEmpty()) {
402         return attr;
403     }
404     auto env = GetEnvironment();
405     Label entry(env);
406     env->SubCfgEntry(&entry);
407 
408     GateRef oldTrackType = GetTrackTypeInPropAttr(attr);
409     DEFVARIABLE(newTrackType, VariableType::INT32(), Int32(static_cast<int32_t>(TrackType::TAGGED)));
410     DEFVARIABLE(result, VariableType::INT32(), attr);
411 
412     Label exit(env);
413     Label judgeValue(env);
414     Branch(Equal(oldTrackType, Int32(static_cast<int32_t>(TrackType::TAGGED))), &exit, &judgeValue);
415     Bind(&judgeValue);
416     {
417         newTrackType = TaggedToTrackType(value);
418         Label update(env);
419         Label merge(env);
420         Branch(Int32Equal(*newTrackType, Int32(static_cast<int32_t>(TrackType::TAGGED))), &update, &merge);
421         Bind(&merge);
422         {
423             newTrackType = Int32Or(oldTrackType, *newTrackType);
424             Branch(Int32Equal(oldTrackType, *newTrackType), &exit, &update);
425         }
426         Bind(&update);
427         {
428             result = SetTrackTypeInPropAttr(attr, *newTrackType);
429             Jump(&exit);
430         }
431     }
432     Bind(&exit);
433     auto ret = *result;
434     env->SubCfgExit();
435     return ret;
436 }
437 
UpdatePropAttrIC(GateRef glue,GateRef receiver,GateRef value,GateRef handler,ProfileOperation callback)438 void ProfilerStubBuilder::UpdatePropAttrIC(
439     GateRef glue, GateRef receiver, GateRef value, GateRef handler, ProfileOperation callback)
440 {
441     if (callback.IsEmpty()) {
442         return;
443     }
444     auto env = GetEnvironment();
445     Label entry(env);
446     env->SubCfgEntry(&entry);
447     Label exit(env);
448     Label handleUnShared(env);
449     Label updateLayout(env);
450 
451     GateRef attrIndex = HandlerBaseGetAttrIndex(handler);
452     GateRef hclass = LoadHClass(receiver);
453     GateRef layout = GetLayoutFromHClass(hclass);
454     GateRef propAttr = GetPropAttrFromLayoutInfo(layout, attrIndex);
455     GateRef attr = GetInt32OfTInt(propAttr);
456     GateRef newAttr = UpdateTrackTypeInPropAttr(attr, value, callback);
457     Branch(IsJSShared(receiver), &exit, &handleUnShared);
458     Bind(&handleUnShared);
459     {
460         Branch(Equal(attr, newAttr), &exit, &updateLayout);
461         Bind(&updateLayout);
462         {
463             SetPropAttrToLayoutInfo(glue, layout, attrIndex, newAttr);
464             callback.TryPreDump();
465             Jump(&exit);
466         }
467     }
468     Bind(&exit);
469     env->SubCfgExit();
470 }
471 
UpdatePropAttrWithValue(GateRef glue,GateRef jsType,GateRef layout,GateRef attr,GateRef attrIndex,GateRef value,ProfileOperation callback)472 void ProfilerStubBuilder::UpdatePropAttrWithValue(GateRef glue, GateRef jsType, GateRef layout, GateRef attr,
473                                                   GateRef attrIndex, GateRef value, ProfileOperation callback)
474 {
475     if (callback.IsEmpty()) {
476         return;
477     }
478     auto env = GetEnvironment();
479     Label entry(env);
480     env->SubCfgEntry(&entry);
481     Label exit(env);
482     Label updateLayout(env);
483     Label notSharedType(env);
484     Branch(IsJSSharedType(jsType), &exit, &notSharedType);
485     Bind(&notSharedType);
486     GateRef newAttr = UpdateTrackTypeInPropAttr(attr, value, callback);
487     Branch(Equal(attr, newAttr), &exit, &updateLayout);
488     Bind(&updateLayout);
489     {
490         SetPropAttrToLayoutInfo(glue, layout, attrIndex, newAttr);
491         Jump(&exit);
492     }
493     Bind(&exit);
494     env->SubCfgExit();
495 }
496 
TaggedToTrackType(GateRef value)497 GateRef ProfilerStubBuilder::TaggedToTrackType(GateRef value)
498 {
499     auto env = GetEnvironment();
500     Label entry(env);
501     env->SubCfgEntry(&entry);
502 
503     DEFVARIABLE(newTrackType, VariableType::INT32(), Int32(static_cast<int32_t>(TrackType::TAGGED)));
504     Label exit(env);
505     Label isInt(env);
506     Label notInt(env);
507     Branch(TaggedIsInt(value), &isInt, &notInt);
508     Bind(&isInt);
509     {
510         newTrackType = Int32(static_cast<int32_t>(TrackType::INT));
511         Jump(&exit);
512     }
513     Bind(&notInt);
514     {
515         Label isObject(env);
516         Label isDouble(env);
517         Branch(TaggedIsObject(value), &isObject, &isDouble);
518         Bind(&isObject);
519         {
520             newTrackType = Int32(static_cast<int32_t>(TrackType::TAGGED));
521             Jump(&exit);
522         }
523         Bind(&isDouble);
524         {
525             newTrackType = Int32(static_cast<int32_t>(TrackType::DOUBLE));
526             Jump(&exit);
527         }
528     }
529     Bind(&exit);
530     auto ret = *newTrackType;
531     env->SubCfgExit();
532     return ret;
533 }
534 
ProfileBranch(GateRef glue,GateRef pc,GateRef func,GateRef profileTypeInfo,bool isTrue)535 void ProfilerStubBuilder::ProfileBranch(GateRef glue, GateRef pc, GateRef func, GateRef profileTypeInfo, bool isTrue)
536 {
537     auto env = GetEnvironment();
538     Label subEntry(env);
539     env->SubCfgEntry(&subEntry);
540     Label profiler(env);
541     Label icSlotValid(env);
542     Label hasSlot(env);
543     Label currentIsTrue(env);
544     Label currentIsFalse(env);
545     Label genCurrentWeight(env);
546     Label compareLabel(env);
547     Label updateSlot(env);
548     Label preProfile(env);
549     Label needUpdate(env);
550     Label exit(env);
551     DEFVARIABLE(oldPrama, VariableType::INT32(), Int32(PGOSampleType::None()));
552     DEFVARIABLE(newTrue, VariableType::INT32(), isTrue ? Int32(1) : Int32(0));
553     DEFVARIABLE(newFalse, VariableType::INT32(), isTrue ? Int32(0) : Int32(1));
554 
555     Branch(TaggedIsUndefined(profileTypeInfo), &exit, &profiler);
556     Bind(&profiler);
557     {
558         GateRef slotId = ZExtInt8ToInt32(Load(VariableType::INT8(), pc, IntPtr(1)));
559         GateRef length = GetLengthOfTaggedArray(profileTypeInfo);
560         Branch(Int32LessThan(slotId, length), &icSlotValid, &exit);
561         Bind(&icSlotValid);
562         GateRef slotValue = GetValueFromTaggedArray(profileTypeInfo, slotId);
563         Branch(TaggedIsHole(slotValue), &exit, &hasSlot);   // ishole -- isundefined
564         Bind(&hasSlot);
565         {
566             Label uninitialized(env);
567             Branch(TaggedIsInt(slotValue), &compareLabel, &uninitialized);
568             Bind(&compareLabel);
569             {
570                 GateRef oldSlotValue = TaggedGetInt(slotValue);
571                 GateRef oldTrue = Int32LSR(oldSlotValue, Int32(PGOSampleType::WEIGHT_TRUE_START_BIT));
572                 GateRef oldFalse = Int32LSR(oldSlotValue, Int32(PGOSampleType::WEIGHT_START_BIT));
573                 oldFalse = Int32And(oldFalse, Int32(PGOSampleType::WEIGHT_MASK));
574                 oldPrama = Int32And(oldSlotValue, Int32(PGOSampleType::AnyType()));
575                 auto condition = BoolAnd(Int32LessThan(oldTrue, Int32(PGOSampleType::WEIGHT_MASK)),
576                     Int32LessThan(oldFalse, Int32(PGOSampleType::WEIGHT_MASK)));
577                 Branch(condition, &needUpdate, &exit);    // 2000: limit
578                 Bind(&needUpdate);
579                 {
580                     newTrue = Int32Add(*newTrue, oldTrue);
581                     newFalse = Int32Add(*newFalse, oldFalse);
582                     Jump(&updateSlot);
583                 }
584             }
585             Bind(&uninitialized);
586             {
587                 Branch(TaggedIsUndefined(slotValue), &updateSlot, &exit);
588             }
589             Bind(&updateSlot);
590             {
591                 GateRef newSlotValue =
592                     Int32Or(*oldPrama, Int32LSL(*newTrue, Int32(PGOSampleType::WEIGHT_TRUE_START_BIT)));
593                 newSlotValue = Int32Or(newSlotValue, Int32LSL(*newFalse, Int32(PGOSampleType::WEIGHT_START_BIT)));
594                 SetValueToTaggedArray(VariableType::JS_ANY(), glue, profileTypeInfo,
595                     slotId, IntToTaggedInt(newSlotValue));
596                 auto totalCount = Int32Add(*newTrue, *newFalse);
597                 auto mask = Int32(0x1FF);
598                 Label updateFinal(env);
599                 Branch(Int32Equal(Int32And(totalCount, mask), Int32(0)), &preProfile, &updateFinal);
600                 Bind(&updateFinal);
601                 {
602                     auto isFinal = BoolOr(Int32Equal(*newTrue, Int32(PGOSampleType::WEIGHT_MASK)),
603                         Int32Equal(*newFalse, Int32(PGOSampleType::WEIGHT_MASK)));
604                     Branch(isFinal, &preProfile, &exit);
605                 }
606             }
607             Bind(&preProfile);
608             {
609                 TryPreDumpInner(glue, func, profileTypeInfo);
610                 Jump(&exit);
611             }
612         }
613     }
614     Bind(&exit);
615     env->SubCfgExit();
616 }
617 
TryPreDumpInner(GateRef glue,GateRef func,GateRef profileTypeInfo)618 void ProfilerStubBuilder::TryPreDumpInner(GateRef glue, GateRef func, GateRef profileTypeInfo)
619 {
620     auto env = GetEnvironment();
621     Label subEntry(env);
622     env->SubCfgEntry(&subEntry);
623     Label setPreDumpPeriodIndex(env);
624     Label isInPredumpWorkList(env);
625     Label addPredumpWorkList(env);
626     Label exit(env);
627     Branch(IsProfileTypeInfoPreDumped(profileTypeInfo), &exit, &setPreDumpPeriodIndex);
628     Bind(&setPreDumpPeriodIndex);
629     {
630         SetPreDumpPeriodIndex(glue, profileTypeInfo);
631         Jump(&addPredumpWorkList);
632     }
633     Bind(&addPredumpWorkList);
634     {
635         CallRuntime(glue, RTSTUB_ID(PGOPreDump), { func });
636         Jump(&exit);
637     }
638     Bind(&exit);
639     env->SubCfgExit();
640 }
641 
GetIterationFunctionId(GateRef glue,GateRef iterator)642 GateRef ProfilerStubBuilder::GetIterationFunctionId(GateRef glue, GateRef iterator)
643 {
644     auto env = GetEnvironment();
645     Label subEntry(env);
646     env->SubCfgEntry(&subEntry);
647     Label exit(env);
648 
649     DEFVARIABLE(functionId, VariableType::INT32(), Int32(PGO_BUILTINS_STUB_ID(NONE)));
650     DEFVARIABLE(maybeFunc, VariableType::JS_ANY(), Undefined());
651     Label isArrayProtoValues(env);
652     Label notArrayProtoValues(env);
653     Label isSetProtoValues(env);
654     Label notSetProtoValues(env);
655     Label isMapProtoEntries(env);
656     Label notMapProtoEntries(env);
657     Label isStringProtoIter(env);
658     Label notStringProtoIter(env);
659     Label isTypedArrayProtoValues(env);
660 
661     GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit()));
662     GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset);
663     maybeFunc = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::ARRAY_PROTO_VALUES_FUNCTION_INDEX);
664     Branch(Int64Equal(iterator, *maybeFunc), &isArrayProtoValues, &notArrayProtoValues);
665     Bind(&isArrayProtoValues);
666     {
667         functionId = Int32(PGO_BUILTINS_STUB_ID(ARRAY_PROTO_ITERATOR));
668         Jump(&exit);
669     }
670     Bind(&notArrayProtoValues);
671     maybeFunc = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::SET_PROTO_VALUES_FUNCTION_INDEX);
672     Branch(Int64Equal(iterator, *maybeFunc), &isSetProtoValues, &notSetProtoValues);
673     Bind(&isSetProtoValues);
674     {
675         functionId = Int32(PGO_BUILTINS_STUB_ID(SET_PROTO_ITERATOR));
676         Jump(&exit);
677     }
678     Bind(&notSetProtoValues);
679     maybeFunc = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::MAP_PROTO_ENTRIES_FUNCTION_INDEX);
680     Branch(Int64Equal(iterator, *maybeFunc), &isMapProtoEntries, &notMapProtoEntries);
681     Bind(&isMapProtoEntries);
682     {
683         functionId = Int32(PGO_BUILTINS_STUB_ID(MAP_PROTO_ITERATOR));
684         Jump(&exit);
685     }
686     Bind(&notMapProtoEntries);
687     maybeFunc = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::STRING_PROTO_ITER_FUNCTION_INDEX);
688     Branch(Int64Equal(iterator, *maybeFunc), &isStringProtoIter, &notStringProtoIter);
689     Bind(&isStringProtoIter);
690     {
691         functionId = Int32(PGO_BUILTINS_STUB_ID(STRING_PROTO_ITERATOR));
692         Jump(&exit);
693     }
694     Bind(&notStringProtoIter);
695     maybeFunc = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv,
696                                   GlobalEnv::TYPED_ARRAY_PROTO_VALUES_FUNCTION_INDEX);
697     Branch(Int64Equal(iterator, *maybeFunc), &isTypedArrayProtoValues, &exit);
698     Bind(&isTypedArrayProtoValues);
699     {
700         functionId = Int32(PGO_BUILTINS_STUB_ID(TYPED_ARRAY_PROTO_ITERATOR));
701         Jump(&exit);
702     }
703     Bind(&exit);
704     auto ret = *functionId;
705     env->SubCfgExit();
706     return ret;
707 }
708 
ProfileGetIterator(GateRef glue,GateRef pc,GateRef func,GateRef iterator,GateRef profileTypeInfo,SlotIDFormat format)709 void ProfilerStubBuilder::ProfileGetIterator(
710     GateRef glue, GateRef pc, GateRef func, GateRef iterator, GateRef profileTypeInfo, SlotIDFormat format)
711 {
712     auto env = GetEnvironment();
713     Label subEntry(env);
714     env->SubCfgEntry(&subEntry);
715 
716     Label exit(env);
717     Label profiler(env);
718     Branch(TaggedIsUndefined(profileTypeInfo), &exit, &profiler);
719     Bind(&profiler);
720     {
721         Label icSlotValid(env);
722         Label updateSlot(env);
723         Label initSlot(env);
724         Label sameValueCheck(env);
725         Label invalidate(env);
726 
727         GateRef slotId = GetSlotID(pc, format);
728         GateRef length = GetLengthOfTaggedArray(profileTypeInfo);
729         Branch(Int32LessThan(slotId, length), &icSlotValid, &exit);
730         Bind(&icSlotValid);
731         GateRef slotValue = GetValueFromTaggedArray(profileTypeInfo, slotId);
732         Branch(TaggedIsInt(slotValue), &updateSlot, &initSlot);
733         Bind(&updateSlot);
734         GateRef oldIterKind = TaggedGetInt(slotValue);
735         Branch(Int32Equal(oldIterKind, Int32(PGO_BUILTINS_STUB_ID(NONE))),
736             &exit, &sameValueCheck);
737         Bind(&sameValueCheck);
738         {
739             GateRef newIterKind = GetIterationFunctionId(glue, iterator);
740             Branch(Int32Equal(oldIterKind, newIterKind), &exit, &invalidate);
741         }
742         Bind(&invalidate);
743         {
744             GateRef invalidKind = Int32(PGO_BUILTINS_STUB_ID(NONE));
745             SetValueToTaggedArray(VariableType::JS_ANY(), glue, profileTypeInfo, slotId, IntToTaggedInt(invalidKind));
746             TryPreDumpInner(glue, func, profileTypeInfo);
747             Jump(&exit);
748         }
749         Bind(&initSlot);
750         {
751             GateRef newIterKind = GetIterationFunctionId(glue, iterator);
752             SetValueToTaggedArray(VariableType::JS_ANY(), glue, profileTypeInfo, slotId, IntToTaggedInt(newIterKind));
753             TryPreDumpInner(glue, func, profileTypeInfo);
754             Jump(&exit);
755         }
756     }
757     Bind(&exit);
758     env->SubCfgExit();
759 }
760 
GetSlotID(GateRef pc,SlotIDFormat format)761 GateRef ProfilerStubBuilder::GetSlotID(GateRef pc, SlotIDFormat format)
762 {
763     if (format == SlotIDFormat::IMM16) {
764         auto hight = Load(VariableType::INT8(), pc, IntPtr(2)); // 2 : skip 1 byte of bytecode
765         hight = Int16LSL(ZExtInt8ToInt16(hight), Int16(8)); // 8 : set as high 8 bits
766         auto low = Load(VariableType::INT8(), pc, IntPtr(1));
767         auto result = Int16Add(hight, ZExtInt8ToInt16(low));
768         return ZExtInt16ToInt32(result);
769     } else if (format == SlotIDFormat::PREF_IMM8) {
770         return ZExtInt8ToInt32(Load(VariableType::INT8(), pc, IntPtr(2)));
771     }
772     return ZExtInt8ToInt32(Load(VariableType::INT8(), pc, IntPtr(1)));
773 }
774 
GetBitFieldOffsetFromProfileTypeInfo(GateRef profileTypeInfo)775 GateRef ProfilerStubBuilder::GetBitFieldOffsetFromProfileTypeInfo(GateRef profileTypeInfo)
776 {
777     auto length = GetLengthOfTaggedArray(profileTypeInfo);
778     auto index = Int32Sub(length, Int32(ProfileTypeInfo::BIT_FIELD_INDEX));
779     auto indexOffset = PtrMul(ZExtInt32ToPtr(index), IntPtr(JSTaggedValue::TaggedTypeSize()));
780     return PtrAdd(indexOffset, IntPtr(TaggedArray::DATA_OFFSET));
781 }
782 
IsProfileTypeInfoDumped(GateRef profileTypeInfo)783 GateRef ProfilerStubBuilder::IsProfileTypeInfoDumped(GateRef profileTypeInfo)
784 {
785     GateRef periodCounterOffset = GetBitFieldOffsetFromProfileTypeInfo(profileTypeInfo);
786     GateRef count = Load(VariableType::INT32(), profileTypeInfo, periodCounterOffset);
787     return Int32Equal(count, Int32(ProfileTypeInfo::DUMP_PEROID_INDEX));
788 }
789 
IsProfileTypeInfoPreDumped(GateRef profileTypeInfo)790 GateRef ProfilerStubBuilder::IsProfileTypeInfoPreDumped(GateRef profileTypeInfo)
791 {
792     GateRef periodCounterOffset = GetBitFieldOffsetFromProfileTypeInfo(profileTypeInfo);
793     GateRef count = Load(VariableType::INT32(), profileTypeInfo, periodCounterOffset);
794     return Int32Equal(count, Int32(ProfileTypeInfo::PRE_DUMP_PEROID_INDEX));
795 }
796 
SetDumpPeriodIndex(GateRef glue,GateRef profileTypeInfo)797 void ProfilerStubBuilder::SetDumpPeriodIndex(GateRef glue, GateRef profileTypeInfo)
798 {
799     GateRef periodCounterOffset = GetBitFieldOffsetFromProfileTypeInfo(profileTypeInfo);
800     GateRef newCount = Int32(ProfileTypeInfo::DUMP_PEROID_INDEX);
801     Store(VariableType::INT32(), glue, profileTypeInfo, periodCounterOffset, newCount);
802 }
803 
SetPreDumpPeriodIndex(GateRef glue,GateRef profileTypeInfo)804 void ProfilerStubBuilder::SetPreDumpPeriodIndex(GateRef glue, GateRef profileTypeInfo)
805 {
806     GateRef periodCounterOffset = GetBitFieldOffsetFromProfileTypeInfo(profileTypeInfo);
807     GateRef newCount = Int32(ProfileTypeInfo::PRE_DUMP_PEROID_INDEX);
808     Store(VariableType::INT32(), glue, profileTypeInfo, periodCounterOffset, newCount);
809 }
810 
IsHotForJitCompiling(GateRef profileTypeInfo,ProfileOperation callback)811 GateRef ProfilerStubBuilder::IsHotForJitCompiling(GateRef profileTypeInfo, ProfileOperation callback)
812 {
813     if (callback.IsJitEmpty()) {
814         return Boolean(true);
815     }
816     return IsHotForJitCompiling(profileTypeInfo);
817 }
818 
GetJitHotnessThresholdOffset(GateRef profileTypeInfo)819 GateRef ProfilerStubBuilder::GetJitHotnessThresholdOffset(GateRef profileTypeInfo)
820 {
821     GateRef bitFieldOffset = GetBitFieldOffsetFromProfileTypeInfo(profileTypeInfo);
822     return PtrAdd(bitFieldOffset,
823         IntPtr(ProfileTypeInfo::JIT_HOTNESS_THRESHOLD_OFFSET_FROM_BITFIELD));
824 }
825 
GetJitHotnessCntOffset(GateRef profileTypeInfo)826 GateRef ProfilerStubBuilder::GetJitHotnessCntOffset(GateRef profileTypeInfo)
827 {
828     GateRef thresholdOffset = GetJitHotnessThresholdOffset(profileTypeInfo);
829     return PtrAdd(thresholdOffset, IntPtr(ProfileTypeInfo::JIT_CNT_OFFSET_FROM_THRESHOLD));
830 }
831 
GetJitHotnessCnt(GateRef profileTypeInfo)832 GateRef ProfilerStubBuilder::GetJitHotnessCnt(GateRef profileTypeInfo)
833 {
834     GateRef hotnessCntOffset = GetJitHotnessCntOffset(profileTypeInfo);
835     GateRef hotnessCnt = Load(VariableType::INT16(), profileTypeInfo, hotnessCntOffset);
836     return ZExtInt16ToInt32(hotnessCnt);
837 }
838 
GetJitHotnessThreshold(GateRef profileTypeInfo)839 GateRef ProfilerStubBuilder::GetJitHotnessThreshold(GateRef profileTypeInfo)
840 {
841     GateRef hotnessThresholdOffset = GetJitHotnessThresholdOffset(profileTypeInfo);
842     GateRef hotnessThreshold = Load(VariableType::INT16(), profileTypeInfo, hotnessThresholdOffset);
843     return ZExtInt16ToInt32(hotnessThreshold);
844 }
845 
IsHotForJitCompiling(GateRef profileTypeInfo)846 GateRef ProfilerStubBuilder::IsHotForJitCompiling(GateRef profileTypeInfo)
847 {
848     auto env = GetEnvironment();
849     Label subEntry(env);
850     env->SubCfgEntry(&subEntry);
851     Label exit(env);
852     DEFVARIABLE(result, VariableType::BOOL(), False());
853     GateRef hotnessThreshold = GetJitHotnessThreshold(profileTypeInfo);
854     GateRef hotnessCnt = GetJitHotnessCnt(profileTypeInfo);
855     Label greaterThreshold(env);
856     Branch(Int32GreaterThan(hotnessCnt, hotnessThreshold), &greaterThreshold, &exit);
857     Bind(&greaterThreshold);
858     result = True();
859     Jump(&exit);
860     Bind(&exit);
861     GateRef ret = *result;
862     env->SubCfgExit();
863     return ret;
864 }
865 
TryJitCompile(GateRef glue,GateRef func,GateRef profileTypeInfo)866 void ProfilerStubBuilder::TryJitCompile(GateRef glue, GateRef func, GateRef profileTypeInfo)
867 {
868     auto env = GetEnvironment();
869     Label subEntry(env);
870     env->SubCfgEntry(&subEntry);
871     Label exit(env);
872 
873     GateRef hotnessThreshold = GetJitHotnessThreshold(profileTypeInfo);
874     GateRef hotnessCnt = GetJitHotnessCnt(profileTypeInfo);
875     Label equalThreshold(env);
876     Label notEqualThreshold(env);
877     Label incCnt(env);
878     Branch(Int32Equal(hotnessCnt, hotnessThreshold), &equalThreshold, &notEqualThreshold);
879     Bind(&equalThreshold);
880     {
881         CallRuntime(glue, RTSTUB_ID(JitCompile), { func });
882         Jump(&incCnt);
883     }
884     Bind(&notEqualThreshold);
885     Branch(Int32LessThan(hotnessCnt, hotnessThreshold), &incCnt, &exit);
886     Bind(&incCnt);
887     {
888         GateRef newCnt = Int16Add(hotnessCnt, Int16(1));
889         GateRef hotnessCntOffset = GetJitHotnessCntOffset(profileTypeInfo);
890         Store(VariableType::INT16(), glue, profileTypeInfo, hotnessCntOffset, newCnt);
891         Jump(&exit);
892     }
893     Bind(&exit);
894     env->SubCfgExit();
895 }
896 } // namespace panda::ecmascript::kungfu
897