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