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