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