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