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 28namespace panda::ecmascript::kungfu { 29void 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 43void 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 50void 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 73void 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 90void 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 137void 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 176void 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 228void 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 312void 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 337GateRef 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 360void 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 415GateRef ProfilerStubBuilder::IsProfileTypeInfoDumped(GateRef profileTypeInfo, ProfileOperation callback) 416{ 417 if (callback.IsEmpty()) { 418 return Boolean(true); 419 } 420 return IsProfileTypeInfoDumped(profileTypeInfo); 421} 422 423GateRef 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 462void 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 495void 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 520GateRef 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 558void 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 637void 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 661GateRef 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 728void 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 783GateRef 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 808GateRef 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 816GateRef 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 823GateRef 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 830GateRef 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 837GateRef 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 858GateRef 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 865void 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 872void 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 879GateRef 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 888GateRef 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 895GateRef ProfilerStubBuilder::GetJitHotnessCntOffset(GateRef profileTypeInfo) 896{ 897 GateRef thresholdOffset = GetJitHotnessThresholdOffset(profileTypeInfo); 898 return PtrAdd(thresholdOffset, IntPtr(ProfileTypeInfo::JIT_CNT_OFFSET_FROM_THRESHOLD)); 899} 900 901void ProfilerStubBuilder::SetJitHotnessCnt(GateRef glue, GateRef profileTypeInfo, GateRef hotnessCnt) 902{ 903 GateRef hotnessCntOffset = GetJitHotnessCntOffset(profileTypeInfo); 904 Store(VariableType::INT16(), glue, profileTypeInfo, hotnessCntOffset, hotnessCnt); 905} 906 907GateRef ProfilerStubBuilder::GetJitHotnessCnt(GateRef profileTypeInfo) 908{ 909 GateRef hotnessCntOffset = GetJitHotnessCntOffset(profileTypeInfo); 910 GateRef hotnessCnt = Load(VariableType::INT16(), profileTypeInfo, hotnessCntOffset); 911 return ZExtInt16ToInt32(hotnessCnt); 912} 913 914GateRef ProfilerStubBuilder::GetJitHotnessThreshold(GateRef profileTypeInfo) 915{ 916 GateRef hotnessThresholdOffset = GetJitHotnessThresholdOffset(profileTypeInfo); 917 GateRef hotnessThreshold = Load(VariableType::INT16(), profileTypeInfo, hotnessThresholdOffset); 918 return ZExtInt16ToInt32(hotnessThreshold); 919} 920 921GateRef 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 928GateRef ProfilerStubBuilder::GetJitCallThreshold(GateRef profileTypeInfo) 929{ 930 GateRef jitCallThresholdOffset = GetJitCallThresholdOffset(profileTypeInfo); 931 GateRef jitCallThreshold = Load(VariableType::INT8(), profileTypeInfo, jitCallThresholdOffset); 932 return ZExtInt8ToInt32(jitCallThreshold); 933} 934 935GateRef 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 941GateRef ProfilerStubBuilder::GetJitCallCnt(GateRef profileTypeInfo) 942{ 943 GateRef jitCallCntOffset = GetJitCallCntOffset(profileTypeInfo); 944 GateRef jitCallCnt = Load(VariableType::INT8(), profileTypeInfo, jitCallCntOffset); 945 return ZExtInt8ToInt32(jitCallCnt); 946} 947 948GateRef 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 955GateRef ProfilerStubBuilder::GetOsrHotnessThreshold(GateRef profileTypeInfo) 956{ 957 GateRef hotnessThresholdOffset = GetOsrHotnessThresholdOffset(profileTypeInfo); 958 GateRef hotnessThreshold = Load(VariableType::INT16(), profileTypeInfo, hotnessThresholdOffset); 959 return ZExtInt16ToInt32(hotnessThreshold); 960} 961 962GateRef 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 969GateRef ProfilerStubBuilder::GetBaselineJitHotnessThreshold(GateRef profileTypeInfo) 970{ 971 GateRef hotnessThresholdOffset = GetBaselineJitHotnessThresholdOffset(profileTypeInfo); 972 GateRef hotnessThreshold = Load(VariableType::INT16(), profileTypeInfo, hotnessThresholdOffset); 973 return ZExtInt16ToInt32(hotnessThreshold); 974} 975 976GateRef ProfilerStubBuilder::GetOsrHotnessCntOffset(GateRef profileTypeInfo) 977{ 978 GateRef thresholdOffset = GetOsrHotnessThresholdOffset(profileTypeInfo); 979 return PtrAdd(thresholdOffset, IntPtr(ProfileTypeInfo::OSR_CNT_OFFSET_FROM_OSR_THRESHOLD)); 980} 981 982GateRef ProfilerStubBuilder::GetOsrHotnessCnt(GateRef profileTypeInfo) 983{ 984 GateRef hotnessCntOffset = GetOsrHotnessCntOffset(profileTypeInfo); 985 GateRef hotnessCnt = Load(VariableType::INT16(), profileTypeInfo, hotnessCntOffset); 986 return ZExtInt16ToInt32(hotnessCnt); 987} 988 989GateRef 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 1046void 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 1167void 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