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