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/pgo_profiler/pgo_profiler.h"
17
18#include <chrono>
19#include <memory>
20
21#include "ecmascript/enum_conversion.h"
22#include "ecmascript/interpreter/interpreter-inl.h"
23#include "ecmascript/jit/jit_profiler.h"
24#include "ecmascript/pgo_profiler/pgo_profiler_info.h"
25#include "ecmascript/pgo_profiler/pgo_trace.h"
26
27namespace panda::ecmascript::pgo {
28void PGOProfiler::RecordProfileType(JSHClass *hclass, JSPandaFile *pandaFile, int32_t traceId)
29{
30    if (!isEnable_) {
31        return;
32    }
33    ProfileType traceType = GetProfileType(hclass);
34    if (traceType.IsNone()) {
35        pgo::ApEntityId abcId(0);
36        pgo::PGOProfilerManager::GetInstance()->GetPandaFileId(pandaFile->GetJSPandaFileDesc(), abcId);
37        SetRootProfileType(hclass, abcId, traceId, ProfileType::Kind::ObjectLiteralId);
38    }
39}
40
41void PGOProfiler::ProfileDefineClass(JSTaggedType ctor)
42{
43    if (!isEnable_) {
44        return;
45    }
46    auto ctorValue = JSTaggedValue(ctor);
47    if (!ctorValue.IsJSFunction()) {
48        return;
49    }
50    auto ctorFunc = JSFunction::Cast(ctorValue.GetTaggedObject());
51    auto ctorMethodValue = ctorFunc->GetMethod();
52    if (!ctorMethodValue.IsMethod()) {
53        return;
54    }
55    auto ctorMethod = Method::Cast(ctorMethodValue);
56    auto entityId = ctorMethod->GetMethodId().GetOffset();
57    if (!InsertDefinedCtor(entityId)) {
58        InsertSkipCtorMethodIdSafe(ctorMethod->GetMethodId());
59        return;
60    }
61
62    auto abcId = GetMethodAbcId(ctorFunc);
63    auto chc = ctorFunc->GetClass();
64    SetRootProfileType(chc, abcId, entityId, ProfileType::Kind::ConstructorId);
65
66    auto protoOrHClass = ctorFunc->GetProtoOrHClass();
67    if (protoOrHClass.IsJSHClass()) {
68        auto ihc = JSHClass::Cast(protoOrHClass.GetTaggedObject());
69        SetRootProfileType(ihc, abcId, entityId, ProfileType::Kind::ClassId);
70        protoOrHClass = ihc->GetProto();
71    }
72    if (protoOrHClass.IsJSObject()) {
73        auto phc = protoOrHClass.GetTaggedObject()->GetClass();
74        SetRootProfileType(phc, abcId, entityId, ProfileType::Kind::PrototypeId);
75    }
76}
77
78void PGOProfiler::ProfileClassRootHClass(JSTaggedType ctor, JSTaggedType rootHcValue, ProfileType::Kind kind)
79{
80    if (!isEnable_) {
81        return;
82    }
83
84    auto ctorValue = JSTaggedValue(ctor);
85    if (!ctorValue.IsJSFunction()) {
86        return;
87    }
88    auto ctorFunc = JSFunction::Cast(ctorValue.GetTaggedObject());
89    if (!FunctionKindVerify(ctorFunc)) {
90        return;
91    }
92    auto ctorMethodValue = ctorFunc->GetMethod();
93    if (!ctorMethodValue.IsMethod()) {
94        return;
95    }
96    auto ctorMethod = Method::Cast(ctorMethodValue);
97    auto entityId = ctorMethod->GetMethodId().GetOffset();
98    if (IsSkippableCtor(entityId)) {
99        return;
100    }
101
102    auto rootHc = JSHClass::Cast(JSTaggedValue(rootHcValue).GetTaggedObject());
103    auto abcId = GetMethodAbcId(ctorFunc);
104    SetRootProfileType(rootHc, abcId, entityId, kind);
105}
106
107void PGOProfiler::ProfileProtoTransitionClass(JSHandle<JSFunction> func,
108                                              JSHandle<JSHClass> hclass,
109                                              JSHandle<JSTaggedValue> proto)
110{
111    if (!isEnable_) {
112        return;
113    }
114    auto thread = vm_->GetJSThread();
115    JSHClass *phc = proto->GetTaggedObject()->GetClass();
116    JSHClass *phcRoot = JSHClass::FindRootHClass(phc);
117    auto *transitionTable = thread->GetCurrentEcmaContext()->GetFunctionProtoTransitionTable();
118    JSTaggedType baseIhc = transitionTable->GetFakeParent(JSTaggedType(phcRoot));
119    if (baseIhc == 0) {
120        LOG_ECMA(DEBUG) << "fake parent not found!";
121        ProfileClassRootHClass(func.GetTaggedType(), hclass.GetTaggedType());
122        return;
123    }
124    JSTaggedType ihc = func->GetProtoTransRootHClass().GetRawData();
125    if (JSTaggedValue(ihc).IsUndefined()) {
126        LOG_ECMA(DEBUG) << "maybe the prototype of the current function is just the initial prototype!";
127        ProfileClassRootHClass(func.GetTaggedType(), hclass.GetTaggedType());
128        return;
129    }
130    [[maybe_unused]] bool success = transitionTable->TryInsertFakeParentItem(hclass.GetTaggedType(), ihc);
131    ASSERT(success == true);  // ihc wont conflict
132    // record original ihc type
133    ProfileClassRootHClass(func.GetTaggedType(), ihc, ProfileType::Kind::ClassId);
134    // record transition ihc type
135    ProfileClassRootHClass(func.GetTaggedType(), hclass.GetTaggedType(), ProfileType::Kind::TransitionClassId);
136}
137
138void PGOProfiler::ProfileProtoTransitionPrototype(JSHandle<JSFunction> func,
139                                                  JSHandle<JSTaggedValue> prototype,
140                                                  JSHandle<JSTaggedValue> oldPrototype,
141                                                  JSHandle<JSTaggedValue> baseIhc)
142{
143    if (!isEnable_) {
144        return;
145    }
146
147    // fuzz test modifies prototype explicitly, add check protection
148    if (!oldPrototype->IsECMAObject()) {
149        return;
150    }
151
152    auto method = func->GetMethod();
153    if (Method::Cast(method)->IsNativeWithCallField()) {
154        return;
155    }
156    // set prototype once, and just skip this time
157    if (!func->GetProtoTransRootHClass().IsUndefined()) {
158        return;
159    }
160    auto thread = vm_->GetJSThread();
161    // insert transition item
162    JSHandle<JSTaggedValue> transIhc(thread, JSTaggedValue::Undefined());
163    JSHandle<JSTaggedValue> transPhc(thread, prototype->GetTaggedObject()->GetClass());
164    if (JSHandle<JSHClass>(baseIhc)->IsDictionaryMode() || JSHandle<JSHClass>(transPhc)->IsDictionaryMode()) {
165        return;
166    }
167    auto *transitionTable = thread->GetCurrentEcmaContext()->GetFunctionProtoTransitionTable();
168    bool success = transitionTable->TryInsertFakeParentItem(transPhc.GetTaggedType(), baseIhc.GetTaggedType());
169    if (!success) {
170        return;
171    }
172    // Do not generate ihc lazily, beacause it's used for the key of hash table
173    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
174    JSHandle<JSHClass> ihc = factory->NewEcmaHClass(JSObject::SIZE, JSType::JS_OBJECT, oldPrototype);
175    func->SetProtoTransRootHClass(thread, JSHandle<JSTaggedValue>(ihc));
176
177    // record phc type
178    JSHClass *phc0Root = JSHClass::FindRootHClass(oldPrototype->GetTaggedObject()->GetClass());
179    ProfileClassRootHClass(func.GetTaggedType(), JSTaggedType(phc0Root), ProfileType::Kind::PrototypeId);
180    ProfileClassRootHClass(func.GetTaggedType(), transPhc.GetTaggedType(), ProfileType::Kind::TransitionPrototypeId);
181}
182
183void PGOProfiler::ProfileDefineGetterSetter(JSHClass* receiverHClass,
184                                            JSHClass* holderHClass,
185                                            const JSHandle<JSTaggedValue>& func,
186                                            int32_t pcOffset)
187{
188    if (!isEnable_) {
189        return;
190    }
191    JSTaggedValue funcValue = JSTaggedValue(func.GetTaggedValue());
192    if (!funcValue.IsJSFunction()) {
193        return;
194    }
195    auto methodValue = JSFunction::Cast(funcValue)->GetMethod();
196    if (!methodValue.IsMethod()) {
197        return;
198    }
199
200    JSHandle<JSFunction> function(func);
201
202    WorkNode* workNode = reinterpret_cast<WorkNode*>(function->GetWorkNodePointer());
203    if (workNode != nullptr) {
204        workNode->SetValue(JSTaggedType(JSFunction::Cast(funcValue)));
205    }
206
207    JSHandle<JSTaggedValue> key(vm_->GetJSThread(), JSTaggedValue(pcOffset));
208    JSHandle<JSTaggedValue> receiverHClassHandle(vm_->GetJSThread(), receiverHClass);
209    JSHandle<JSTaggedValue> holderHClassHandle(vm_->GetJSThread(), holderHClass);
210    JSHandle<JSTaggedValue> profileTypeInfoValue(vm_->GetJSThread(), function->GetRawProfileTypeInfo());
211    JSHandle<ProfileTypeInfoCell> profileTypeInfoCell(profileTypeInfoValue);
212
213    if (function->HasProfileTypeInfo(vm_->GetJSThread())) {
214        JSHandle<ProfileTypeInfo> profileTypeInfo(vm_->GetJSThread(), profileTypeInfoCell->GetValue());
215        JSHandle<NumberDictionary> dictJShandle = ProfileTypeInfo::CreateOrGetExtraInfoMap(vm_->GetJSThread(),
216                                                                                           profileTypeInfo);
217        int entry = dictJShandle->FindEntry(key.GetTaggedValue());
218        if (entry == -1) {
219            ProfileTypeInfo::UpdateExtraInfoMap(vm_->GetJSThread(), dictJShandle, key, receiverHClassHandle,
220                                                holderHClassHandle, profileTypeInfo);
221            return;
222        }
223        ExtraProfileTypeInfo *mapInfoObj = ExtraProfileTypeInfo::Cast(dictJShandle->GetValue(entry).GetTaggedObject());
224        if (mapInfoObj->GetReceiver() == receiverHClassHandle.GetTaggedValue().CreateAndGetWeakRef() &&
225            mapInfoObj->GetHolder() == holderHClassHandle.GetTaggedValue()) {
226            return;
227        }
228
229        ExtraProfileTypeInfo::Cast(dictJShandle->GetValue(entry).GetTaggedObject())->Clear(vm_->GetJSThread());
230    }
231}
232
233void PGOProfiler::UpdateRootProfileTypeSafe(JSHClass* oldHClass, JSHClass* newHClass)
234{
235    if (!isEnable_) {
236        return;
237    }
238    ProfileType oldPt = GetProfileType(oldHClass);
239    if (oldPt.IsRootType()) {
240        newHClass->SetProfileType(oldPt.GetRaw());
241        oldHClass->SetProfileType(0);
242    }
243}
244
245void PGOProfiler::UpdateTrackElementsKind(JSTaggedValue trackInfoVal, ElementsKind newKind)
246{
247    if (trackInfoVal.IsHeapObject() && trackInfoVal.IsWeak()) {
248        auto trackInfo = TrackInfo::Cast(trackInfoVal.GetWeakReferentUnChecked());
249        auto oldKind = trackInfo->GetElementsKind();
250        if (Elements::IsGeneric(oldKind) || oldKind == newKind) {
251            return;
252        }
253        auto mixKind = Elements::MergeElementsKind(oldKind, newKind);
254        if (mixKind == oldKind) {
255            return;
256        }
257        trackInfo->SetElementsKind(mixKind);
258        auto thread = vm_->GetJSThread();
259        auto globalConst = thread->GlobalConstants();
260        // Since trackinfo is only used at define point,
261        // we update cachedHClass with initial array hclass which does not have IsPrototype set.
262        auto constantId = thread->GetArrayHClassIndexMap().at(mixKind).first;
263        auto hclass = globalConst->GetGlobalConstantObject(static_cast<size_t>(constantId));
264        trackInfo->SetCachedHClass(vm_->GetJSThread(), hclass);
265        UpdateTrackInfo(JSTaggedValue(trackInfo));
266    }
267}
268
269void PGOProfiler::UpdateTrackArrayLength(JSTaggedValue trackInfoVal, uint32_t newSize)
270{
271    if (trackInfoVal.IsHeapObject() && trackInfoVal.IsWeak()) {
272        auto trackInfo = TrackInfo::Cast(trackInfoVal.GetWeakReferentUnChecked());
273        uint32_t oldSize = trackInfo->GetArrayLength();
274        if (oldSize >= newSize) {
275            return;
276        }
277        trackInfo->SetArrayLength(newSize);
278        UpdateTrackInfo(JSTaggedValue(trackInfo));
279    }
280}
281
282void PGOProfiler::UpdateTrackSpaceFlag(TaggedObject *object, RegionSpaceFlag spaceFlag)
283{
284    if (!object->GetClass()->IsTrackInfoObject()) {
285        return;
286    }
287    auto trackInfo = TrackInfo::Cast(object);
288    RegionSpaceFlag oldFlag = trackInfo->GetSpaceFlag();
289    if (oldFlag == RegionSpaceFlag::IN_YOUNG_SPACE) {
290        trackInfo->SetSpaceFlag(spaceFlag);
291        UpdateTrackInfo(JSTaggedValue(trackInfo));
292    }
293}
294
295void PGOProfiler::UpdateTrackInfo(JSTaggedValue trackInfoVal)
296{
297    if (trackInfoVal.IsHeapObject()) {
298        auto trackInfo = TrackInfo::Cast(trackInfoVal.GetTaggedObject());
299        auto func = trackInfo->GetCachedFunc();
300        auto thread = vm_->GetJSThread();
301        if (!func.IsWeak()) {
302            return;
303        }
304        TaggedObject *object = func.GetWeakReferentUnChecked();
305        if (!object->GetClass()->IsJSFunction()) {
306            return;
307        }
308        JSFunction* function = JSFunction::Cast(object);
309        if (!function->HasProfileTypeInfo(thread)) {
310            return;
311        }
312        auto profileTypeInfoVal = function->GetProfileTypeInfo();
313        if (profileTypeInfoVal.IsUndefined() || !profileTypeInfoVal.IsTaggedArray()) {
314            return;
315        }
316        auto profileTypeInfo = ProfileTypeInfo::Cast(profileTypeInfoVal.GetTaggedObject());
317        if (profileTypeInfo->IsProfileTypeInfoWithBigMethod()) {
318            return;
319        }
320        if (!profileTypeInfo->IsProfileTypeInfoPreDumped()) {
321            profileTypeInfo->SetPreDumpPeriodIndex();
322            PGOPreDump(JSTaggedType(object));
323        }
324    }
325}
326
327void PGOProfiler::PGODump(JSTaggedType func)
328{
329    if (!isEnable_ || !vm_->GetJSOptions().IsEnableProfileDump()) {
330        return;
331    }
332
333    auto funcValue = JSTaggedValue(func);
334    if (!funcValue.IsJSFunction()) {
335        return;
336    }
337    auto methodValue = JSFunction::Cast(funcValue)->GetMethod();
338    if (!methodValue.IsMethod()) {
339        return;
340    }
341    auto function = JSFunction::Cast(funcValue);
342    auto workNode = reinterpret_cast<WorkNode *>(function->GetWorkNodePointer());
343    if (workNode == nullptr) {
344        workNode = nativeAreaAllocator_->New<WorkNode>(JSTaggedType(function));
345        function->SetWorkNodePointer(reinterpret_cast<uintptr_t>(workNode));
346        LockHolder lock(mutex_);
347        dumpWorkList_.PushBack(workNode);
348    } else {
349        workNode->SetValue(JSTaggedType(function));
350        auto workList = workNode->GetWorkList();
351        LockHolder lock(mutex_);
352        if (workList == &preDumpWorkList_) {
353            preDumpWorkList_.Remove(workNode);
354        }
355        if (workList != &dumpWorkList_) {
356            dumpWorkList_.PushBack(workNode);
357        }
358    }
359    StartPGODump();
360}
361
362void PGOProfiler::SuspendByGC()
363{
364    if (!isEnable_) {
365        return;
366    }
367    LockHolder lock(mutex_);
368    if (GetState() == State::START) {
369        SetState(State::PAUSE);
370        WaitingPGODump();
371    } else if (GetState() == State::FORCE_SAVE) {
372        SetState(State::FORCE_SAVE_PAUSE);
373        WaitingPGODump();
374    }
375}
376
377void PGOProfiler::ResumeByGC()
378{
379    if (!isEnable_) {
380        return;
381    }
382    LockHolder lock(mutex_);
383    if (GetState() == State::PAUSE) {
384        SetState(State::START);
385        DispatchPGODumpTask();
386    } else if (GetState() == State::FORCE_SAVE_PAUSE) {
387        SetState(State::FORCE_SAVE);
388        DispatchPGODumpTask();
389    }
390}
391
392void PGOProfiler::StopPGODump()
393{
394    LockHolder lock(mutex_);
395    if (IsGCWaiting()) {
396        NotifyGC("[StopPGODump::PAUSE]");
397        return;
398    }
399    SetState(State::STOP);
400    NotifyAll("[StopPGODump::STOP]");
401}
402
403void PGOProfiler::StartPGODump()
404{
405    if (GetState() == State::STOP) {
406        SetState(State::START);
407        DispatchPGODumpTask();
408    }
409}
410
411void PGOProfiler::DispatchPGODumpTask()
412{
413    Taskpool::GetCurrentTaskpool()->PostTask(
414        std::make_unique<PGOProfilerTask>(this, vm_->GetJSThread()->GetThreadId()));
415}
416
417PGOProfiler::State PGOProfiler::GetState()
418{
419    return state_.load(std::memory_order_acquire);
420}
421
422void PGOProfiler::SetState(State state)
423{
424    v_.AddLogWithDebugLog("[PGODumpStateChange] " + StateToString(GetState()) + " -> " + StateToString(state));
425    state_.store(state, std::memory_order_release);
426}
427
428void PGOProfiler::NotifyGC(std::string tag)
429{
430    v_.AddLogWithDebugLog(tag + " notify GC");
431    condition_.SignalAll();
432}
433
434void PGOProfiler::NotifyAll(std::string tag)
435{
436    v_.AddLogWithDebugLog(tag + " notify all");
437    condition_.SignalAll();
438}
439
440void PGOProfiler::WaitingPGODump()
441{
442    condition_.Wait(&mutex_);
443}
444
445void PGOProfiler::WaitPGODumpFinish()
446{
447    if (!isEnable_) {
448        return;
449    }
450    LockHolder lock(mutex_);
451    while (GetState() == State::START) {
452        WaitingPGODump();
453    }
454}
455
456void PGOProfiler::DumpByForce()
457{
458    isForce_ = true;
459    LockHolder lock(mutex_);
460    if (GetState() == State::START) {
461        SetState(State::FORCE_SAVE);
462        WaitingPGODump();
463    } else if (GetState() == State::STOP && !dumpWorkList_.IsEmpty()) {
464        SetState(State::FORCE_SAVE);
465        WaitingPGODump();
466        DispatchPGODumpTask();
467    } else if (GetState() == State::PAUSE) {
468        SetState(State::FORCE_SAVE_PAUSE);
469        WaitingPGODump();
470    }
471}
472
473bool PGOProfiler::IsGCWaitingWithLock()
474{
475    if (GetState() == State::PAUSE) {
476        LockHolder lock(mutex_);
477        if (GetState() == State::PAUSE) {
478            return true;
479        }
480    }
481    return false;
482}
483
484bool PGOProfiler::IsGCWaiting()
485{
486    if (GetState() == State::PAUSE) {
487        return true;
488    }
489    return false;
490}
491
492void PGOProfiler::PGOPreDump(JSTaggedType func)
493{
494    if (!isEnable_ || !vm_->GetJSOptions().IsEnableProfileDump()) {
495        return;
496    }
497
498    auto funcValue = JSTaggedValue(func);
499    if (!funcValue.IsJSFunction()) {
500        return;
501    }
502    auto methodValue = JSFunction::Cast(funcValue)->GetMethod();
503    if (!methodValue.IsMethod()) {
504        return;
505    }
506    auto function = JSFunction::Cast(funcValue);
507    auto workNode = reinterpret_cast<WorkNode *>(function->GetWorkNodePointer());
508    if (workNode == nullptr) {
509        workNode = nativeAreaAllocator_->New<WorkNode>(JSTaggedType(function));
510        function->SetWorkNodePointer(reinterpret_cast<uintptr_t>(workNode));
511        LockHolder lock(mutex_);
512        preDumpWorkList_.PushBack(workNode);
513    } else {
514        workNode->SetValue(JSTaggedType(function));
515        auto workList = workNode->GetWorkList();
516        LockHolder lock(mutex_);
517        if (workList == &dumpWorkList_) {
518            workList->Remove(workNode);
519        }
520        if (workList != &preDumpWorkList_) {
521            preDumpWorkList_.PushBack(workNode);
522        }
523    }
524}
525
526void PGOProfiler::UpdateExtraProfileTypeInfo(ApEntityId abcId,
527                                             const CString& recordName,
528                                             EntityId methodId,
529                                             WorkNode* current)
530{
531    JSTaggedValue funcValue = JSTaggedValue(current->GetValue());
532    if (!funcValue.IsJSFunction()) {
533        return;
534    }
535    auto func = JSFunction::Cast(funcValue);
536    if (!func->HasProfileTypeInfo(vm_->GetJSThread())) {
537        return;
538    }
539    ProfileTypeInfoCell *cell = ProfileTypeInfoCell::Cast(func->GetRawProfileTypeInfo());
540    ProfileTypeInfo *info = ProfileTypeInfo::Cast((cell->GetValue()).GetTaggedObject());
541    if ((info->GetExtraInfoMap()).IsHole() || (info->GetExtraInfoMap()).IsUndefined()) {
542        return;
543    }
544    NumberDictionary *dict = NumberDictionary::Cast(info->GetExtraInfoMap().GetTaggedObject());
545    int size = dict->Size();
546    for (int hashIndex = 0; hashIndex < size; hashIndex++) {
547        JSTaggedValue key(dict->GetKey(hashIndex));
548        if (!key.IsUndefined() && !key.IsHole()) {
549            JSTaggedValue val(dict->GetValue(hashIndex));
550            ExtraProfileTypeInfo *extraInfo = ExtraProfileTypeInfo::Cast(val.GetTaggedObject());
551            if (!extraInfo->IsValid()) {
552                continue;
553            }
554            AddObjectInfo(abcId,
555                          recordName,
556                          methodId,
557                          key.GetInt(),
558                          extraInfo->GetReceiverHClass(),
559                          extraInfo->GetReceiverHClass(),
560                          extraInfo->GetHolderHClass());
561        }
562    }
563}
564
565bool PGOProfiler::HasValidExtraProfileTypeInfo(JSFunction *func)
566{
567    if (!func->HasProfileTypeInfo(vm_->GetJSThread())) {
568        return false;
569    }
570    ProfileTypeInfoCell *profileCell = ProfileTypeInfoCell::Cast(func->GetRawProfileTypeInfo());
571    ProfileTypeInfo *profileInfo = ProfileTypeInfo::Cast((profileCell->GetValue()).GetTaggedObject());
572    JSTaggedValue map = profileInfo->GetExtraInfoMap();
573    if (map.IsHole() || map.IsUndefined()) {
574        return false;
575    }
576    NumberDictionary *numberDict = NumberDictionary::Cast(map.GetTaggedObject());
577    return numberDict->GetEntrySize() > 0;
578}
579
580void PGOProfiler::ProcessExtraProfileTypeInfo(JSFunction *func, ApEntityId abcId, const CString &recordName,
581                                              JSTaggedValue methodValue, WorkNode *current)
582{
583    if (!HasValidExtraProfileTypeInfo(func)) {
584        return;
585    }
586    Method* method = Method::Cast(methodValue.GetTaggedObject());
587    EntityId methodId = method->GetMethodId();
588    UpdateExtraProfileTypeInfo(abcId, recordName, methodId, current);
589}
590
591void PGOProfiler::HandlePGOPreDump()
592{
593    LockHolder lock(recordInfoMutex_);
594    if (!isEnable_ || !vm_->GetJSOptions().IsEnableProfileDump()) {
595        return;
596    }
597    DISALLOW_GARBAGE_COLLECTION;
598    preDumpWorkList_.Iterate([this](WorkNode* current) {
599        JSTaggedValue funcValue = JSTaggedValue(current->GetValue());
600        if (!funcValue.IsJSFunction()) {
601            return;
602        }
603        auto func = JSFunction::Cast(funcValue);
604        if (func->IsSendableOrConcurrentFunction()) {
605            return;
606        }
607        JSTaggedValue methodValue = func->GetMethod();
608        if (!methodValue.IsMethod()) {
609            return;
610        }
611        CString recordName = func->GetRecordName();
612        if (recordName.empty()) {
613            return;
614        }
615        auto abcId = GetMethodAbcId(func);
616
617        ProcessExtraProfileTypeInfo(func, abcId, recordName, methodValue, current);
618        ProfileType recordType = GetRecordProfileType(abcId, recordName);
619        recordInfos_->AddMethod(recordType, Method::Cast(methodValue), SampleMode::HOTNESS_MODE);
620        ProfileBytecode(abcId, recordName, funcValue);
621        if (PGOTrace::GetInstance()->IsEnable()) {
622            PGOTrace::GetInstance()->TryGetMethodData(methodValue, false);
623        }
624    });
625}
626
627void PGOProfiler::HandlePGODumpByDumpThread(bool force)
628{
629    ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "PGOProfiler::HandlePGODumpByDumpThread");
630    LockHolder lock(recordInfoMutex_);
631    if (!isEnable_ || !vm_->GetJSOptions().IsEnableProfileDump()) {
632        return;
633    }
634    DISALLOW_GARBAGE_COLLECTION;
635    auto current = PopFromProfileQueue();
636    while (current != nullptr) {
637        JSTaggedValue value = JSTaggedValue(current->GetValue());
638        if (value.IsUndefined()) {
639            current = PopFromProfileQueue();
640            continue;
641        }
642        if (!value.IsJSFunction()) {
643            current = PopFromProfileQueue();
644            continue;
645        }
646        auto func = JSFunction::Cast(value);
647        if (func->IsSendableOrConcurrentFunction()) {
648            current = PopFromProfileQueue();
649            continue;
650        }
651        JSTaggedValue methodValue = func->GetMethod();
652        if (!methodValue.IsMethod()) {
653            current = PopFromProfileQueue();
654            continue;
655        }
656        CString recordName = func->GetRecordName();
657        if (recordName.empty()) {
658            current = PopFromProfileQueue();
659            continue;
660        }
661        auto abcId = GetMethodAbcId(func);
662
663        ProcessExtraProfileTypeInfo(func, abcId, recordName, methodValue, current);
664
665        ProfileType recordType = GetRecordProfileType(abcId, recordName);
666        if (recordInfos_->AddMethod(recordType, Method::Cast(methodValue), SampleMode::HOTNESS_MODE)) {
667            methodCount_++;
668        }
669        ProfileBytecode(abcId, recordName, value);
670        current = PopFromProfileQueue();
671        if (PGOTrace::GetInstance()->IsEnable()) {
672            PGOTrace::GetInstance()->TryGetMethodData(methodValue, true);
673        }
674    }
675    ASSERT(GetState() != State::STOP);
676    if (IsGCWaitingWithLock()) {
677        return;
678    }
679    MergeProfilerAndDispatchAsyncSaveTask(force);
680}
681
682void PGOProfiler::MergeProfilerAndDispatchAsyncSaveTask(bool force)
683{
684    ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "PGOProfiler::MergeProfilerAndDispatchAsyncSaveTask");
685    // Merged every 50 methods and merge interval greater than minimal interval
686    auto interval = std::chrono::system_clock::now() - saveTimestamp_;
687    auto minIntervalOption = vm_->GetJSOptions().GetPGOSaveMinInterval();
688    auto mergeMinInterval = std::chrono::milliseconds(minIntervalOption * MS_PRE_SECOND);
689    if ((methodCount_ >= MERGED_EVERY_COUNT && interval > mergeMinInterval) || (force && methodCount_ > 0)) {
690        LOG_ECMA(DEBUG) << "Sample: post task to save profiler";
691        {
692            ClockScope start;
693            PGOProfilerManager::GetInstance()->Merge(this);
694            if (PGOTrace::GetInstance()->IsEnable()) {
695                PGOTrace::GetInstance()->SetMergeTime(start.TotalSpentTime());
696            }
697        }
698        if (!force) {
699            PGOProfilerManager::GetInstance()->AsyncSave();
700        }
701        SetSaveTimestamp(std::chrono::system_clock::now());
702        methodCount_ = 0;
703    }
704}
705
706PGOProfiler::WorkNode* PGOProfiler::PopFromProfileQueue()
707{
708    LockHolder lock(mutex_);
709    WorkNode* node = nullptr;
710    while (node == nullptr) {
711        if (IsGCWaiting()) {
712            break;
713        }
714        if (dumpWorkList_.IsEmpty()) {
715            break;
716        }
717        node = dumpWorkList_.PopFront();
718    }
719    return node;
720}
721
722void PGOProfiler::ProfileBytecode(ApEntityId abcId, const CString &recordName, JSTaggedValue funcValue)
723{
724    ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "PGOProfiler::ProfileBytecode");
725    ClockScope start;
726    JSFunction *function = JSFunction::Cast(funcValue);
727    if (function->IsSendableOrConcurrentFunction()) {
728        return;
729    }
730    Method *method = Method::Cast(function->GetMethod());
731    JSTaggedValue profileTypeInfoVal = function->GetProfileTypeInfo();
732    ASSERT(!profileTypeInfoVal.IsUndefined());
733    auto profileTypeInfo = ProfileTypeInfo::Cast(profileTypeInfoVal.GetTaggedObject());
734    auto methodId = method->GetMethodId();
735    auto pcStart = method->GetBytecodeArray();
736    auto codeSize = method->GetCodeSize();
737    BytecodeInstruction bcIns(pcStart);
738    auto bcInsLast = bcIns.JumpTo(codeSize);
739    bool isForceDump = vm_->GetJSOptions().IsPgoForceDump();
740
741    while (bcIns.GetAddress() != bcInsLast.GetAddress()) {
742        if (!isForceDump) {
743            if (IsGCWaitingWithLock()) {
744                break;
745            }
746        }
747        auto opcode = bcIns.GetOpcode();
748        auto bcOffset = bcIns.GetAddress() - pcStart;
749        auto pc = bcIns.GetAddress();
750        switch (opcode) {
751            case EcmaOpcode::LDTHISBYNAME_IMM8_ID16:
752            case EcmaOpcode::LDOBJBYNAME_IMM8_ID16:
753            case EcmaOpcode::LDPRIVATEPROPERTY_IMM8_IMM16_IMM16: {
754                uint8_t slotId = READ_INST_8_0();
755                CHECK_SLOTID_BREAK(slotId);
756                DumpICByName(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo, BCType::LOAD);
757                break;
758            }
759            case EcmaOpcode::LDTHISBYNAME_IMM16_ID16:
760            case EcmaOpcode::LDOBJBYNAME_IMM16_ID16: {
761                uint16_t slotId = READ_INST_16_0();
762                DumpICByName(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo, BCType::LOAD);
763                break;
764            }
765            case EcmaOpcode::LDOBJBYVALUE_IMM8_V8:
766            case EcmaOpcode::LDTHISBYVALUE_IMM8: {
767                uint8_t slotId = READ_INST_8_0();
768                CHECK_SLOTID_BREAK(slotId);
769                DumpICByValue(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo, BCType::LOAD);
770                break;
771            }
772            case EcmaOpcode::LDOBJBYVALUE_IMM16_V8:
773            case EcmaOpcode::LDTHISBYVALUE_IMM16: {
774                uint16_t slotId = READ_INST_16_0();
775                DumpICByValue(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo, BCType::LOAD);
776                break;
777            }
778            case EcmaOpcode::STOBJBYNAME_IMM8_ID16_V8:
779            case EcmaOpcode::STTHISBYNAME_IMM8_ID16:
780            case EcmaOpcode::DEFINEPROPERTYBYNAME_IMM8_ID16_V8:
781            case EcmaOpcode::STPRIVATEPROPERTY_IMM8_IMM16_IMM16_V8: {
782                uint8_t slotId = READ_INST_8_0();
783                CHECK_SLOTID_BREAK(slotId);
784                DumpICByName(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo, BCType::STORE);
785                break;
786            }
787            case EcmaOpcode::STOBJBYNAME_IMM16_ID16_V8:
788            case EcmaOpcode::STTHISBYNAME_IMM16_ID16: {
789                uint16_t slotId = READ_INST_16_0();
790                DumpICByName(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo, BCType::STORE);
791                break;
792            }
793            case EcmaOpcode::STOBJBYVALUE_IMM8_V8_V8:
794            case EcmaOpcode::STOWNBYINDEX_IMM8_V8_IMM16:
795            case EcmaOpcode::STTHISBYVALUE_IMM8_V8: {
796                uint8_t slotId = READ_INST_8_0();
797                CHECK_SLOTID_BREAK(slotId);
798                DumpICByValue(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo, BCType::STORE);
799                break;
800            }
801            case EcmaOpcode::STOBJBYVALUE_IMM16_V8_V8:
802            case EcmaOpcode::STOWNBYINDEX_IMM16_V8_IMM16:
803            case EcmaOpcode::STTHISBYVALUE_IMM16_V8: {
804                uint16_t slotId = READ_INST_16_0();
805                DumpICByValue(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo, BCType::STORE);
806                break;
807            }
808            // Op
809            case EcmaOpcode::ADD2_IMM8_V8:
810            case EcmaOpcode::SUB2_IMM8_V8:
811            case EcmaOpcode::MUL2_IMM8_V8:
812            case EcmaOpcode::DIV2_IMM8_V8:
813            case EcmaOpcode::MOD2_IMM8_V8:
814            case EcmaOpcode::SHL2_IMM8_V8:
815            case EcmaOpcode::SHR2_IMM8_V8:
816            case EcmaOpcode::AND2_IMM8_V8:
817            case EcmaOpcode::OR2_IMM8_V8:
818            case EcmaOpcode::XOR2_IMM8_V8:
819            case EcmaOpcode::ASHR2_IMM8_V8:
820            case EcmaOpcode::EXP_IMM8_V8:
821            case EcmaOpcode::NEG_IMM8:
822            case EcmaOpcode::NOT_IMM8:
823            case EcmaOpcode::INC_IMM8:
824            case EcmaOpcode::DEC_IMM8:
825            case EcmaOpcode::EQ_IMM8_V8:
826            case EcmaOpcode::NOTEQ_IMM8_V8:
827            case EcmaOpcode::LESS_IMM8_V8:
828            case EcmaOpcode::LESSEQ_IMM8_V8:
829            case EcmaOpcode::GREATER_IMM8_V8:
830            case EcmaOpcode::GREATEREQ_IMM8_V8:
831            case EcmaOpcode::STRICTNOTEQ_IMM8_V8:
832            case EcmaOpcode::STRICTEQ_IMM8_V8:
833            case EcmaOpcode::TONUMERIC_IMM8: {
834                uint8_t slotId = READ_INST_8_0();
835                CHECK_SLOTID_BREAK(slotId);
836                DumpOpType(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo);
837                break;
838            }
839            case EcmaOpcode::CALLRUNTIME_ISTRUE_PREF_IMM8:
840            case EcmaOpcode::CALLRUNTIME_ISFALSE_PREF_IMM8: {
841                uint8_t slotId = READ_INST_8_1();
842                CHECK_SLOTID_BREAK(slotId);
843                DumpOpType(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo);
844                break;
845            }
846            // Call
847            case EcmaOpcode::CALLARG0_IMM8:
848            case EcmaOpcode::CALLARG1_IMM8_V8:
849            case EcmaOpcode::CALLARGS2_IMM8_V8_V8:
850            case EcmaOpcode::CALLARGS3_IMM8_V8_V8_V8:
851            case EcmaOpcode::CALLRANGE_IMM8_IMM8_V8:
852            case EcmaOpcode::CALLTHIS0_IMM8_V8:
853            case EcmaOpcode::CALLTHIS1_IMM8_V8_V8:
854            case EcmaOpcode::CALLTHIS2_IMM8_V8_V8_V8:
855            case EcmaOpcode::CALLTHIS3_IMM8_V8_V8_V8_V8:
856            case EcmaOpcode::CALLTHISRANGE_IMM8_IMM8_V8: {
857                uint8_t slotId = READ_INST_8_0();
858                CHECK_SLOTID_BREAK(slotId);
859                DumpCall(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo);
860                break;
861            }
862            case EcmaOpcode::CALLRUNTIME_CALLINIT_PREF_IMM8_V8: {
863                uint8_t slotId = READ_INST_8_1();
864                CHECK_SLOTID_BREAK(slotId);
865                DumpCall(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo);
866                break;
867            }
868            case EcmaOpcode::WIDE_CALLRANGE_PREF_IMM16_V8:
869            case EcmaOpcode::WIDE_CALLTHISRANGE_PREF_IMM16_V8: {
870                // no ic slot
871                break;
872            }
873            case EcmaOpcode::NEWOBJRANGE_IMM8_IMM8_V8: {
874                uint8_t slotId = READ_INST_8_0();
875                CHECK_SLOTID_BREAK(slotId);
876                DumpNewObjRange(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo);
877                break;
878            }
879            case EcmaOpcode::NEWOBJRANGE_IMM16_IMM8_V8: {
880                uint16_t slotId = READ_INST_16_0();
881                DumpNewObjRange(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo);
882                break;
883            }
884            case EcmaOpcode::WIDE_NEWOBJRANGE_PREF_IMM16_V8: {
885                break;
886            }
887            // Create object
888            case EcmaOpcode::DEFINECLASSWITHBUFFER_IMM8_ID16_ID16_IMM16_V8: {
889                uint8_t slotId = READ_INST_8_0();
890                CHECK_SLOTID_BREAK(slotId);
891                DumpDefineClass(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo);
892                break;
893            }
894            case EcmaOpcode::DEFINECLASSWITHBUFFER_IMM16_ID16_ID16_IMM16_V8: {
895                uint16_t slotId = READ_INST_16_0();
896                DumpDefineClass(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo);
897                break;
898            }
899            case EcmaOpcode::DEFINEFUNC_IMM8_ID16_IMM8: {
900                uint8_t slotId = READ_INST_8_0();
901                CHECK_SLOTID_BREAK(slotId);
902                DumpDefineClass(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo);
903                break;
904            }
905            case EcmaOpcode::DEFINEFUNC_IMM16_ID16_IMM8: {
906                uint16_t slotId = READ_INST_16_0();
907                DumpDefineClass(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo);
908                break;
909            }
910            case EcmaOpcode::CREATEOBJECTWITHBUFFER_IMM8_ID16:
911            case EcmaOpcode::CREATEARRAYWITHBUFFER_IMM8_ID16:
912            case EcmaOpcode::CREATEEMPTYARRAY_IMM8: {
913                if (method->GetJSPandaFile() == nullptr) {
914                    break;
915                }
916                auto header = method->GetJSPandaFile()->GetPandaFile()->GetHeader();
917                auto traceId =
918                    static_cast<int32_t>(reinterpret_cast<uintptr_t>(pc) - reinterpret_cast<uintptr_t>(header));
919                uint8_t slotId = READ_INST_8_0();
920                CHECK_SLOTID_BREAK(slotId);
921                DumpCreateObject(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo, traceId);
922                break;
923            }
924            case EcmaOpcode::CREATEOBJECTWITHBUFFER_IMM16_ID16:
925            case EcmaOpcode::CREATEARRAYWITHBUFFER_IMM16_ID16:
926            case EcmaOpcode::CREATEEMPTYARRAY_IMM16: {
927                if (method->GetJSPandaFile() == nullptr) {
928                    break;
929                }
930                auto header = method->GetJSPandaFile()->GetPandaFile()->GetHeader();
931                auto traceId =
932                    static_cast<int32_t>(reinterpret_cast<uintptr_t>(pc) - reinterpret_cast<uintptr_t>(header));
933                uint16_t slotId = READ_INST_16_0();
934                DumpCreateObject(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo, traceId);
935                break;
936            }
937            case EcmaOpcode::GETITERATOR_IMM8: {
938                uint8_t slotId = READ_INST_8_0();
939                CHECK_SLOTID_BREAK(slotId);
940                DumpGetIterator(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo);
941                break;
942            }
943            case EcmaOpcode::GETITERATOR_IMM16: {
944                uint16_t slotId = READ_INST_16_0();
945                DumpGetIterator(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo);
946                break;
947            }
948            // Others
949            case EcmaOpcode::INSTANCEOF_IMM8_V8: {
950                uint8_t slotId = READ_INST_8_0();
951                CHECK_SLOTID_BREAK(slotId);
952                DumpInstanceof(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo);
953                break;
954            }
955            case EcmaOpcode::DEFINEGETTERSETTERBYVALUE_V8_V8_V8_V8:
956            default:
957                break;
958        }
959        bcIns = bcIns.GetNext();
960    }
961    if (PGOTrace::GetInstance()->IsEnable()) {
962        auto methodData = PGOTrace::GetInstance()->TryGetMethodData(function->GetMethod());
963        methodData->SetProfileBytecodeTime(start.TotalSpentTime());
964    }
965}
966
967void PGOProfiler::DumpICByName(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset,
968                               uint32_t slotId, ProfileTypeInfo *profileTypeInfo, BCType type)
969{
970    JSTaggedValue firstValue = profileTypeInfo->Get(slotId);
971    if (!firstValue.IsHeapObject()) {
972        if (firstValue.IsHole()) {
973            // Mega state
974            AddObjectInfoWithMega(abcId, recordName, methodId, bcOffset);
975        }
976        return;
977    }
978    if (firstValue.IsWeak()) {
979        TaggedObject *object = firstValue.GetWeakReferentUnChecked();
980        if (object->GetClass()->IsHClass()) {
981            JSTaggedValue secondValue = profileTypeInfo->Get(slotId + 1);
982            JSHClass *hclass = JSHClass::Cast(object);
983            DumpICByNameWithHandler(abcId, recordName, methodId, bcOffset, hclass, secondValue, type);
984        }
985        return;
986    }
987    DumpICByNameWithPoly(abcId, recordName, methodId, bcOffset, firstValue, type);
988}
989
990void PGOProfiler::DumpICByValue(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset,
991                                uint32_t slotId, ProfileTypeInfo *profileTypeInfo, BCType type)
992{
993    JSTaggedValue firstValue = profileTypeInfo->Get(slotId);
994    if (!firstValue.IsHeapObject()) {
995        if (firstValue.IsHole()) {
996            // Mega state
997            AddObjectInfoWithMega(abcId, recordName, methodId, bcOffset);
998        }
999        return;
1000    }
1001    if (firstValue.IsWeak()) {
1002        TaggedObject *object = firstValue.GetWeakReferentUnChecked();
1003        if (object->GetClass()->IsHClass()) {
1004            JSTaggedValue secondValue = profileTypeInfo->Get(slotId + 1);
1005            JSHClass *hclass = JSHClass::Cast(object);
1006            DumpICByValueWithHandler(abcId, recordName, methodId, bcOffset, hclass, secondValue, type);
1007        }
1008        return;
1009    }
1010    // Check key
1011    if ((firstValue.IsString() || firstValue.IsSymbol())) {
1012        return;
1013    }
1014    // Check without key
1015    DumpICByValueWithPoly(abcId, recordName, methodId, bcOffset, firstValue, type);
1016}
1017
1018void PGOProfiler::DumpICByNameWithPoly(ApEntityId abcId,
1019    const CString &recordName, EntityId methodId, int32_t bcOffset, JSTaggedValue cacheValue, BCType type)
1020{
1021    if (cacheValue.IsWeak()) {
1022        return;
1023    }
1024    ASSERT(cacheValue.IsTaggedArray());
1025    auto array = TaggedArray::Cast(cacheValue);
1026    uint32_t length = array->GetLength();
1027    for (uint32_t i = 0; i < length; i += 2) { // 2 means one ic, two slot
1028        auto result = array->Get(i);
1029        auto handler = array->Get(i + 1);
1030        if (!result.IsHeapObject() || !result.IsWeak()) {
1031            continue;
1032        }
1033        TaggedObject *object = result.GetWeakReferentUnChecked();
1034        if (!object->GetClass()->IsHClass()) {
1035            continue;
1036        }
1037        JSHClass *hclass = JSHClass::Cast(object);
1038        if (!DumpICByNameWithHandler(abcId, recordName, methodId, bcOffset, hclass, handler, type)) {
1039            AddObjectInfoWithMega(abcId, recordName, methodId, bcOffset);
1040            break;
1041        }
1042    }
1043}
1044
1045void PGOProfiler::DumpICByValueWithPoly(ApEntityId abcId,
1046    const CString &recordName, EntityId methodId, int32_t bcOffset, JSTaggedValue cacheValue, BCType type)
1047{
1048    if (cacheValue.IsWeak()) {
1049        return;
1050    }
1051    ASSERT(cacheValue.IsTaggedArray());
1052    auto array = TaggedArray::Cast(cacheValue);
1053    uint32_t length = array->GetLength();
1054    for (uint32_t i = 0; i < length; i += 2) { // 2 means one ic, two slot
1055        auto result = array->Get(i);
1056        auto handler = array->Get(i + 1);
1057        if (!result.IsHeapObject() || !result.IsWeak()) {
1058            continue;
1059        }
1060        TaggedObject *object = result.GetWeakReferentUnChecked();
1061        if (!object->GetClass()->IsHClass()) {
1062            continue;
1063        }
1064        JSHClass *hclass = JSHClass::Cast(object);
1065        DumpICByValueWithHandler(abcId, recordName, methodId, bcOffset, hclass, handler, type);
1066    }
1067}
1068
1069bool PGOProfiler::DumpICByNameWithHandler(ApEntityId abcId, const CString &recordName, EntityId methodId,
1070                                          int32_t bcOffset, JSHClass *hclass, JSTaggedValue secondValue, BCType type)
1071{
1072    TryDumpProtoTransitionType(hclass);
1073    if (type == BCType::LOAD) {
1074        return DumpICLoadByNameWithHandler(abcId, recordName, methodId, bcOffset, hclass, secondValue);
1075    }
1076
1077    if (secondValue.IsInt()) {
1078        return AddObjectInfo(abcId, recordName, methodId, bcOffset, hclass, hclass, hclass);
1079    } else if (secondValue.IsTransitionHandler()) {
1080        auto transitionHandler = TransitionHandler::Cast(secondValue.GetTaggedObject());
1081        auto transitionHClassVal = transitionHandler->GetTransitionHClass();
1082        if (transitionHClassVal.IsJSHClass()) {
1083            auto transitionHClass = JSHClass::Cast(transitionHClassVal.GetTaggedObject());
1084            return AddObjectInfo(abcId, recordName, methodId, bcOffset, hclass, hclass, transitionHClass);
1085        }
1086    } else if (secondValue.IsTransWithProtoHandler()) {
1087        auto transWithProtoHandler = TransWithProtoHandler::Cast(secondValue.GetTaggedObject());
1088        auto cellValue = transWithProtoHandler->GetProtoCell();
1089        if (CheckProtoChangeMarker(cellValue)) {
1090            return false;
1091        }
1092        auto transitionHClassVal = transWithProtoHandler->GetTransitionHClass();
1093        if (transitionHClassVal.IsJSHClass()) {
1094            auto transitionHClass = JSHClass::Cast(transitionHClassVal.GetTaggedObject());
1095            return AddObjectInfo(abcId, recordName, methodId, bcOffset, hclass, hclass, transitionHClass);
1096        }
1097    } else if (secondValue.IsPrototypeHandler()) {
1098        auto prototypeHandler = PrototypeHandler::Cast(secondValue.GetTaggedObject());
1099        auto cellValue = prototypeHandler->GetProtoCell();
1100        if (CheckProtoChangeMarker(cellValue)) {
1101            return false;
1102        }
1103        auto holder = prototypeHandler->GetHolder();
1104        auto holderHClass = holder.GetTaggedObject()->GetClass();
1105        auto accessorMethodId = prototypeHandler->GetAccessorMethodId();
1106        return AddObjectInfo(
1107            abcId, recordName, methodId, bcOffset, hclass, holderHClass, holderHClass, accessorMethodId);
1108    } else if (secondValue.IsStoreTSHandler()) {
1109        StoreTSHandler *storeTSHandler = StoreTSHandler::Cast(secondValue.GetTaggedObject());
1110        auto cellValue = storeTSHandler->GetProtoCell();
1111        if (CheckProtoChangeMarker(cellValue)) {
1112            return false;
1113        }
1114        auto holder = storeTSHandler->GetHolder();
1115        auto holderHClass = holder.GetTaggedObject()->GetClass();
1116        return AddObjectInfo(abcId, recordName, methodId, bcOffset, hclass, holderHClass, holderHClass);
1117    }
1118    // StoreGlobal
1119    return false;
1120}
1121
1122bool PGOProfiler::DumpICLoadByNameWithHandler(ApEntityId abcId, const CString &recordName, EntityId methodId,
1123                                              int32_t bcOffset, JSHClass *hclass, JSTaggedValue secondValue)
1124{
1125    bool ret = false;
1126    if (secondValue.IsInt()) {
1127        auto handlerInfo = static_cast<uint32_t>(secondValue.GetInt());
1128        if (HandlerBase::IsNonExist(handlerInfo)) {
1129            return ret;
1130        }
1131        if (HandlerBase::IsField(handlerInfo) || HandlerBase::IsAccessor(handlerInfo)) {
1132            if (AddObjectInfo(abcId, recordName, methodId, bcOffset, hclass, hclass, hclass)) {
1133                return true;
1134            }
1135        }
1136        return AddBuiltinsInfoByNameInInstance(abcId, recordName, methodId, bcOffset, hclass);
1137    } else if (secondValue.IsPrototypeHandler()) {
1138        auto prototypeHandler = PrototypeHandler::Cast(secondValue.GetTaggedObject());
1139        auto cellValue = prototypeHandler->GetProtoCell();
1140        if (CheckProtoChangeMarker(cellValue)) {
1141            return ret;
1142        }
1143        auto holder = prototypeHandler->GetHolder();
1144        auto holderHClass = holder.GetTaggedObject()->GetClass();
1145        JSTaggedValue handlerInfoVal = prototypeHandler->GetHandlerInfo();
1146        if (!handlerInfoVal.IsInt()) {
1147            return ret;
1148        }
1149        auto handlerInfo = static_cast<uint32_t>(handlerInfoVal.GetInt());
1150        if (HandlerBase::IsNonExist(handlerInfo)) {
1151            return ret;
1152        }
1153        auto accessorMethodId = prototypeHandler->GetAccessorMethodId();
1154        if (!AddObjectInfo(abcId, recordName, methodId, bcOffset, hclass, holderHClass,
1155                           holderHClass, accessorMethodId)) {
1156            return AddBuiltinsInfoByNameInProt(abcId, recordName, methodId, bcOffset, hclass, holderHClass);
1157        }
1158        return true;
1159    }
1160    // LoadGlobal
1161    return false;
1162}
1163
1164void PGOProfiler::DumpICByValueWithHandler(ApEntityId abcId, const CString &recordName, EntityId methodId,
1165                                           int32_t bcOffset, JSHClass *hclass, JSTaggedValue secondValue, BCType type)
1166{
1167    TryDumpProtoTransitionType(hclass);
1168    if (type == BCType::LOAD) {
1169        if (secondValue.IsInt()) {
1170            auto handlerInfo = static_cast<uint32_t>(secondValue.GetInt());
1171            if (HandlerBase::IsNormalElement(handlerInfo) || HandlerBase::IsStringElement(handlerInfo)) {
1172                if (HandlerBase::NeedSkipInPGODump(handlerInfo)) {
1173                    return;
1174                }
1175                AddBuiltinsInfo(abcId, recordName, methodId, bcOffset, hclass, hclass);
1176                return;
1177            }
1178
1179            if (HandlerBase::IsTypedArrayElement(handlerInfo)) {
1180                OnHeapMode onHeap =  HandlerBase::IsOnHeap(handlerInfo) ? OnHeapMode::ON_HEAP : OnHeapMode::NOT_ON_HEAP;
1181                AddBuiltinsInfo(abcId, recordName, methodId, bcOffset, hclass, hclass, onHeap);
1182                return;
1183            }
1184
1185            AddObjectInfo(abcId, recordName, methodId, bcOffset, hclass, hclass, hclass);
1186        }
1187        return;
1188    }
1189    if (secondValue.IsInt()) {
1190        auto handlerInfo = static_cast<uint32_t>(secondValue.GetInt());
1191        if (HandlerBase::IsNormalElement(handlerInfo) || HandlerBase::IsStringElement(handlerInfo)) {
1192            AddBuiltinsInfo(abcId, recordName, methodId, bcOffset, hclass, hclass,
1193                            OnHeapMode::NONE, HandlerBase::IsStoreOutOfBounds(handlerInfo));
1194            return;
1195        }
1196
1197        if (HandlerBase::IsTypedArrayElement(handlerInfo)) {
1198            OnHeapMode onHeap = HandlerBase::IsOnHeap(handlerInfo) ? OnHeapMode::ON_HEAP : OnHeapMode::NOT_ON_HEAP;
1199            AddBuiltinsInfo(abcId, recordName, methodId, bcOffset, hclass, hclass, onHeap,
1200                            HandlerBase::IsStoreOutOfBounds(handlerInfo));
1201            return;
1202        }
1203
1204        AddObjectInfo(abcId, recordName, methodId, bcOffset, hclass, hclass, hclass);
1205    } else if (secondValue.IsTransitionHandler()) {
1206        auto transitionHandler = TransitionHandler::Cast(secondValue.GetTaggedObject());
1207        auto transitionHClassVal = transitionHandler->GetTransitionHClass();
1208
1209        auto handlerInfoValue = transitionHandler->GetHandlerInfo();
1210        ASSERT(handlerInfoValue.IsInt());
1211        auto handlerInfo = static_cast<uint32_t>(handlerInfoValue.GetInt());
1212        if (transitionHClassVal.IsJSHClass()) {
1213            auto transitionHClass = JSHClass::Cast(transitionHClassVal.GetTaggedObject());
1214            if (HandlerBase::IsElement(handlerInfo)) {
1215                AddBuiltinsInfo(abcId, recordName, methodId, bcOffset, hclass, transitionHClass,
1216                                OnHeapMode::NONE, HandlerBase::IsStoreOutOfBounds(handlerInfo));
1217                return;
1218            }
1219            AddObjectInfo(abcId, recordName, methodId, bcOffset, hclass, hclass, transitionHClass);
1220        }
1221    } else if (secondValue.IsTransWithProtoHandler()) {
1222        auto transWithProtoHandler = TransWithProtoHandler::Cast(secondValue.GetTaggedObject());
1223        auto transitionHClassVal = transWithProtoHandler->GetTransitionHClass();
1224
1225        auto handlerInfoValue = transWithProtoHandler->GetHandlerInfo();
1226        ASSERT(handlerInfoValue.IsInt());
1227        auto handlerInfo = static_cast<uint32_t>(handlerInfoValue.GetInt());
1228        if (transitionHClassVal.IsJSHClass()) {
1229            auto transitionHClass = JSHClass::Cast(transitionHClassVal.GetTaggedObject());
1230            if (HandlerBase::IsElement(handlerInfo)) {
1231                AddBuiltinsInfo(abcId, recordName, methodId, bcOffset, hclass, transitionHClass,
1232                                OnHeapMode::NONE, HandlerBase::IsStoreOutOfBounds(handlerInfo));
1233                return;
1234            }
1235            AddObjectInfo(abcId, recordName, methodId, bcOffset, hclass, hclass, transitionHClass);
1236        }
1237    } else if (secondValue.IsPrototypeHandler()) {
1238        PrototypeHandler *prototypeHandler = PrototypeHandler::Cast(secondValue.GetTaggedObject());
1239        auto cellValue = prototypeHandler->GetProtoCell();
1240        if (!cellValue.IsProtoChangeMarker()) {
1241            return;
1242        }
1243        ASSERT(cellValue.IsProtoChangeMarker());
1244        ProtoChangeMarker *cell = ProtoChangeMarker::Cast(cellValue.GetTaggedObject());
1245        if (cell->GetHasChanged()) {
1246            return;
1247        }
1248        JSTaggedValue handlerInfoValue = prototypeHandler->GetHandlerInfo();
1249        ASSERT(handlerInfoValue.IsInt());
1250        auto handlerInfo = static_cast<uint32_t>(handlerInfoValue.GetInt());
1251        if (HandlerBase::IsElement(handlerInfo)) {
1252            AddBuiltinsInfo(abcId, recordName, methodId, bcOffset, hclass, hclass,
1253                            OnHeapMode::NONE, HandlerBase::IsStoreOutOfBounds(handlerInfo));
1254            return;
1255        }
1256        auto holder = prototypeHandler->GetHolder();
1257        auto holderHClass = holder.GetTaggedObject()->GetClass();
1258        AddObjectInfo(abcId, recordName, methodId, bcOffset, hclass, holderHClass, holderHClass);
1259    }
1260}
1261
1262void PGOProfiler::TryDumpProtoTransitionType(JSHClass *hclass)
1263{
1264    JSHClass *ihc1 = JSHClass::FindRootHClass(hclass);
1265    auto transitionType = GetProfileType(ihc1, true);
1266    if (!transitionType.IsRootType() || !transitionType.IsTransitionClassType()) {
1267        return;
1268    }
1269    JSTaggedValue phc1Root = JSHClass::FindProtoRootHClass(ihc1);
1270    auto transitionProtoType = GetProfileType(JSHClass::Cast(phc1Root.GetTaggedObject()), true);
1271    if (!transitionProtoType.IsRootType()) {
1272        LOG_ECMA(DEBUG) << "Set as the prototype of a function again after transition happened for this prototype!";
1273        return;
1274    }
1275
1276    auto thread = vm_->GetJSThread();
1277    auto *transitionTable = thread->GetCurrentEcmaContext()->GetFunctionProtoTransitionTable();
1278    JSTaggedType ihc0 = transitionTable->GetFakeParent(JSTaggedType(ihc1));
1279    JSTaggedType baseIhc = transitionTable->GetFakeParent(phc1Root.GetRawData());
1280    if ((ihc0 == 0) || (baseIhc == 0)) {
1281        return;
1282    }
1283
1284    auto ihc0Obj = JSHClass::Cast(JSTaggedValue(ihc0).GetTaggedObject());
1285    auto baseIhcObj = JSHClass::Cast(JSTaggedValue(baseIhc).GetTaggedObject());
1286    UpdateLayout(ihc0Obj);
1287    UpdateLayout(ihc1);
1288    UpdateLayout(baseIhcObj);
1289
1290    auto ihc0RootType = GetProfileType(ihc0Obj);
1291    ASSERT(ihc0RootType.IsRootType());
1292    auto baseRootHClass = JSHClass::FindRootHClass(baseIhcObj);
1293    auto baseRootType = GetProfileType(baseRootHClass, true);
1294    if (!baseRootType.IsRootType()) {
1295        LOG_ECMA(DEBUG) << "Unsupported prototypes which cannot be recorded!";
1296        return;
1297    }
1298    auto baseType = GetProfileType(baseIhcObj);
1299    ASSERT(!baseType.IsNone());
1300    PGOProtoTransitionType protoTransitionType(ihc0RootType);
1301    protoTransitionType.SetBaseType(baseRootType, baseType);
1302    protoTransitionType.SetTransitionType(transitionType);
1303    protoTransitionType.SetTransitionProtoPt(transitionProtoType);
1304
1305    recordInfos_->GetProtoTransitionPool()->Add(protoTransitionType);
1306}
1307
1308void PGOProfiler::DumpOpType(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset,
1309                             uint32_t slotId, ProfileTypeInfo *profileTypeInfo)
1310{
1311    JSTaggedValue slotValue = profileTypeInfo->Get(slotId);
1312    if (slotValue.IsInt()) {
1313        auto type = slotValue.GetInt();
1314        ProfileType recordType = GetRecordProfileType(abcId, recordName);
1315        recordInfos_->AddType(recordType, methodId, bcOffset, PGOSampleType(type));
1316    }
1317}
1318
1319bool PGOProfiler::FunctionKindVerify(const JSFunction *ctorFunction)
1320{
1321    FunctionKind kind = Method::Cast(ctorFunction->GetMethod())->GetFunctionKind();
1322    return kind == FunctionKind::BASE_CONSTRUCTOR ||
1323           kind == FunctionKind::CLASS_CONSTRUCTOR ||
1324           kind == FunctionKind::DERIVED_CONSTRUCTOR;
1325}
1326
1327void PGOProfiler::DumpDefineClass(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset,
1328                                  uint32_t slotId, ProfileTypeInfo *profileTypeInfo)
1329{
1330    JSTaggedValue slotValue = profileTypeInfo->Get(slotId);
1331    if (!slotValue.IsProfileTypeInfoCell0()) {
1332        return;
1333    }
1334    JSTaggedValue handle = ProfileTypeInfoCell::Cast(slotValue)->GetHandle();
1335    if (!handle.IsHeapObject() || !handle.IsWeak()) {
1336        return;
1337    }
1338    auto object = handle.GetWeakReferentUnChecked();
1339    if (object->GetClass()->IsJSFunction()) {
1340        JSFunction *ctorFunction = JSFunction::Cast(object);
1341        auto ctorMethod = ctorFunction->GetMethod();
1342        if (!ctorMethod.IsMethod() || !FunctionKindVerify(ctorFunction)) {
1343            return;
1344        }
1345        ApEntityId ctorAbcId = GetMethodAbcId(ctorFunction);
1346        auto ctorJSMethod = Method::Cast(ctorMethod);
1347        auto ctorMethodId = ctorJSMethod->GetMethodId().GetOffset();
1348
1349        auto localType = ProfileType(ctorAbcId, ctorMethodId, ProfileType::Kind::ClassId, true);
1350        if (IsSkippableObjectTypeSafe(localType)) {
1351            return;
1352        }
1353        PGODefineOpType objDefType(localType);
1354        auto protoOrHClass = ctorFunction->GetProtoOrHClass();
1355        if (protoOrHClass.IsJSHClass()) {
1356            auto ihc = JSHClass::Cast(protoOrHClass.GetTaggedObject());
1357            SetRootProfileType(ihc, ctorAbcId, ctorMethodId, ProfileType::Kind::ClassId);
1358            recordInfos_->AddRootLayout(JSTaggedType(ihc), localType);
1359            protoOrHClass = ihc->GetProto();
1360        }
1361
1362        auto ctorRootHClass = JSHClass::FindRootHClass(ctorFunction->GetJSHClass());
1363        auto ctorType = GetProfileType(ctorRootHClass);
1364        if (!ctorType.IsRootType()) {
1365            LOG_ECMA(DEBUG) << "The profileType of constructor root hclass was not found.";
1366        } else {
1367            objDefType.SetCtorPt(ctorType);
1368            recordInfos_->AddRootLayout(JSTaggedType(ctorRootHClass), ctorType);
1369        }
1370
1371        if (protoOrHClass.IsJSObject()) {
1372            auto prototypeHClass = JSObject::Cast(protoOrHClass)->GetClass();
1373            auto prototypeRootHClass = JSHClass::FindRootHClass(prototypeHClass);
1374            ProfileType prototypeType = GetProfileType(prototypeRootHClass);
1375            if (!prototypeType.IsRootType()) {
1376                LOG_ECMA(DEBUG) << "The profileType of prototype root hclass was not found.";
1377            } else {
1378                objDefType.SetProtoTypePt(prototypeType);
1379                recordInfos_->AddRootLayout(JSTaggedType(prototypeRootHClass), prototypeType);
1380            }
1381        }
1382
1383        ProfileType recordType = GetRecordProfileType(abcId, recordName);
1384        recordInfos_->AddDefine(recordType, methodId, bcOffset, objDefType);
1385    }
1386}
1387
1388void PGOProfiler::DumpCreateObject(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset,
1389                                   uint32_t slotId, ProfileTypeInfo *profileTypeInfo, int32_t traceId)
1390{
1391    JSTaggedValue slotValue = profileTypeInfo->Get(slotId);
1392    if (!slotValue.IsHeapObject()) {
1393        return;
1394    }
1395    ProfileType recordType = GetRecordProfileType(abcId, recordName);
1396    if (slotValue.IsWeak()) {
1397        auto object = slotValue.GetWeakReferentUnChecked();
1398        if (object->GetClass()->IsHClass()) {
1399            auto newHClass = JSHClass::Cast(object);
1400            auto rootHClass = JSHClass::FindRootHClass(newHClass);
1401            ProfileType profileType = GetProfileType(rootHClass);
1402            if (!profileType.IsRootType()) {
1403                return;
1404            }
1405            ASSERT(profileType.GetKind() == ProfileType::Kind::ObjectLiteralId);
1406            PGOSampleType currentType(profileType);
1407            PGODefineOpType objDefType(profileType);
1408            recordInfos_->AddDefine(recordType, methodId, bcOffset, objDefType);
1409            recordInfos_->AddRootLayout(JSTaggedType(rootHClass), profileType);
1410        }
1411    } else if (slotValue.IsTrackInfoObject()) {
1412        auto currentType = PGOSampleType::CreateProfileType(abcId, traceId, ProfileType::Kind::ArrayLiteralId, true);
1413        auto profileType = currentType.GetProfileType();
1414        PGODefineOpType objDefType(profileType);
1415        TrackInfo *trackInfo = TrackInfo::Cast(slotValue.GetTaggedObject());
1416        auto elementsKind = trackInfo->GetElementsKind();
1417        objDefType.SetElementsKind(elementsKind);
1418        objDefType.SetElementsLength(trackInfo->GetArrayLength());
1419        objDefType.SetSpaceFlag(trackInfo->GetSpaceFlag());
1420        recordInfos_->AddDefine(recordType, methodId, bcOffset, objDefType);
1421        auto cachedHClass = trackInfo->GetCachedHClass();
1422        if (cachedHClass.IsJSHClass()) {
1423            auto hclass = JSHClass::Cast(cachedHClass.GetTaggedObject());
1424            recordInfos_->AddRootLayout(JSTaggedType(hclass), profileType);
1425        }
1426    }
1427}
1428
1429void PGOProfiler::DumpCall(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset,
1430                           uint32_t slotId, ProfileTypeInfo *profileTypeInfo)
1431{
1432    JSTaggedValue slotValue = profileTypeInfo->Get(slotId);
1433    ProfileType::Kind kind;
1434    int calleeMethodId = 0;
1435    ApEntityId calleeAbcId = 0;
1436    if (slotValue.IsInt()) {
1437        calleeMethodId = slotValue.GetInt();
1438        calleeAbcId = abcId;
1439        ASSERT(calleeMethodId <= 0);
1440        if (calleeMethodId == 0) {
1441            kind = ProfileType::Kind::MethodId;
1442        } else {
1443            kind = ProfileType::Kind::BuiltinFunctionId;
1444        }
1445    } else if (slotValue.IsJSFunction()) {
1446        JSFunction *callee = JSFunction::Cast(slotValue);
1447        Method *calleeMethod = Method::Cast(callee->GetMethod());
1448        calleeMethodId = static_cast<int>(calleeMethod->GetMethodId().GetOffset());
1449        calleeAbcId = GetMethodAbcId(callee->GetMethod());
1450        kind = ProfileType::Kind::MethodId;
1451    } else {
1452        return;
1453    }
1454    PGOSampleType type = PGOSampleType::CreateProfileType(calleeAbcId, std::abs(calleeMethodId), kind);
1455    ProfileType recordType = GetRecordProfileType(abcId, recordName);
1456    recordInfos_->AddCallTargetType(recordType, methodId, bcOffset, type);
1457}
1458
1459void PGOProfiler::DumpGetIterator(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset,
1460                                  uint32_t slotId, ProfileTypeInfo *profileTypeInfo)
1461{
1462    if (vm_->GetJSThread()->GetEnableLazyBuiltins()) {
1463        return;
1464    }
1465    JSTaggedValue value = profileTypeInfo->Get(slotId);
1466    if (!value.IsInt()) {
1467        return;
1468    }
1469    int iterKind = value.GetInt();
1470    ASSERT(iterKind <= 0);
1471    ProfileType::Kind pgoKind = ProfileType::Kind::BuiltinFunctionId;
1472    PGOSampleType type = PGOSampleType::CreateProfileType(abcId, std::abs(iterKind), pgoKind);
1473    ProfileType recordType = GetRecordProfileType(abcId, recordName);
1474    recordInfos_->AddCallTargetType(recordType, methodId, bcOffset, type);
1475}
1476
1477void PGOProfiler::DumpNewObjRange(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset,
1478                                  uint32_t slotId, ProfileTypeInfo *profileTypeInfo)
1479{
1480    JSTaggedValue slotValue = profileTypeInfo->Get(slotId);
1481    int ctorMethodId = 0;
1482    if (slotValue.IsInt()) {
1483        ctorMethodId = slotValue.GetInt();
1484    } else if (slotValue.IsJSFunction()) {
1485        JSFunction *callee = JSFunction::Cast(slotValue);
1486        Method *calleeMethod = Method::Cast(callee->GetMethod());
1487        ctorMethodId = static_cast<int>(calleeMethod->GetMethodId().GetOffset());
1488    } else {
1489        return;
1490    }
1491    PGOSampleType type;
1492    if (ctorMethodId > 0) {
1493        type = PGOSampleType::CreateProfileType(abcId, ctorMethodId, ProfileType::Kind::ClassId, true);
1494    } else {
1495        auto kind = ProfileType::Kind::BuiltinFunctionId;
1496        type = PGOSampleType::CreateProfileType(abcId, std::abs(ctorMethodId), kind);
1497    }
1498    ProfileType recordType = GetRecordProfileType(abcId, recordName);
1499    recordInfos_->AddCallTargetType(recordType, methodId, bcOffset, type);
1500}
1501
1502void PGOProfiler::DumpInstanceof(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset,
1503                                 uint32_t slotId, ProfileTypeInfo *profileTypeInfo)
1504{
1505    JSTaggedValue firstValue = profileTypeInfo->Get(slotId);
1506    if (!firstValue.IsHeapObject()) {
1507        if (firstValue.IsHole()) {
1508            // Mega state
1509            AddObjectInfoWithMega(abcId, recordName, methodId, bcOffset);
1510        }
1511        return;
1512    }
1513    if (firstValue.IsWeak()) {
1514        TaggedObject *object = firstValue.GetWeakReferentUnChecked();
1515        if (object->GetClass()->IsHClass()) {
1516            JSHClass *hclass = JSHClass::Cast(object);
1517            // Since pgo does not support symbol, we choose to return if hclass having @@hasInstance
1518            JSHandle<GlobalEnv> env = vm_->GetGlobalEnv();
1519            JSTaggedValue key = env->GetHasInstanceSymbol().GetTaggedValue();
1520            JSHClass *functionPrototypeHC = JSObject::Cast(env->GetFunctionPrototype().GetTaggedValue())->GetClass();
1521            JSTaggedValue foundHClass = TryFindKeyInPrototypeChain(object, hclass, key);
1522            if (!foundHClass.IsUndefined() && JSHClass::Cast(foundHClass.GetTaggedObject()) != functionPrototypeHC) {
1523                return;
1524            }
1525            AddObjectInfo(abcId, recordName, methodId, bcOffset, hclass, hclass, hclass);
1526        }
1527        return;
1528    }
1529    // Poly Not Consider now
1530    return;
1531}
1532
1533void PGOProfiler::UpdateLayout(JSHClass *hclass)
1534{
1535    auto parentHClass = hclass->GetParent();
1536    if (!GetProfileType(hclass).IsRootType() && parentHClass.IsJSHClass()) {
1537        UpdateTransitionLayout(JSHClass::Cast(parentHClass.GetTaggedObject()), hclass);
1538    } else {
1539        auto rootHClass = JSHClass::FindRootHClass(hclass);
1540        ProfileType rootType = GetProfileType(rootHClass, true);
1541        if (!rootType.IsRootType()) {
1542            return;
1543        }
1544
1545        auto prototypeHClass = JSHClass::FindProtoRootHClass(rootHClass);
1546        if (prototypeHClass.IsJSHClass()) {
1547            auto prototypeObject = JSHClass::Cast(prototypeHClass.GetTaggedObject());
1548            ProfileType prototypeType = GetProfileType(prototypeObject, true);
1549            if (prototypeType.IsRootType()) {
1550                recordInfos_->AddRootPtType(rootType, prototypeType);
1551                UpdateLayout(JSHClass::Cast(prototypeHClass.GetTaggedObject()));
1552            }
1553        }
1554
1555        auto curType = GetOrInsertProfileType(hclass, rootType);
1556        recordInfos_->UpdateLayout(rootType, JSTaggedType(hclass), curType);
1557    }
1558}
1559
1560void PGOProfiler::UpdateTransitionLayout(JSHClass* parent, JSHClass* child)
1561{
1562    auto rootHClass = JSHClass::FindRootHClass(parent);
1563    auto rootType = GetProfileType(rootHClass, true);
1564    if (!rootType.IsRootType()) {
1565        return;
1566    }
1567    // If the child hclass is set as a prototype, it will become the root hclass. Need to give up.
1568    if (GetProfileType(child).IsRootType()) {
1569        return;
1570    }
1571    CStack<JSHClass *> hclassVec;
1572    hclassVec.emplace(child);
1573    hclassVec.emplace(parent);
1574
1575    while (!GetProfileType(parent).IsRootType()) {
1576        auto parentHCValue = parent->GetParent();
1577        if (!parentHCValue.IsJSHClass()) {
1578            break;
1579        }
1580        parent = JSHClass::Cast(parentHCValue.GetTaggedObject());
1581        hclassVec.emplace(parent);
1582    }
1583
1584    auto prototypeRootHClassVal = JSHClass::FindProtoRootHClass(rootHClass);
1585    if (prototypeRootHClassVal.IsJSHClass()) {
1586        auto prototypeRootHClass = JSHClass::Cast(prototypeRootHClassVal.GetTaggedObject());
1587        auto prototypeType = GetProfileType(prototypeRootHClass);
1588        if (prototypeType.IsRootType()) {
1589            recordInfos_->AddRootPtType(rootType, prototypeType);
1590            UpdateLayout(prototypeRootHClass);
1591        }
1592    }
1593
1594    parent = hclassVec.top();
1595    hclassVec.pop();
1596    auto parentType = GetProfileType(parent);
1597    while (!hclassVec.empty()) {
1598        child = hclassVec.top();
1599        hclassVec.pop();
1600        auto childType = GetOrInsertProfileType(child, rootType);
1601        recordInfos_->UpdateTransitionLayout(
1602            rootType, JSTaggedType(parent), parentType, JSTaggedType(child), childType);
1603        parentType = childType;
1604        parent = child;
1605    }
1606}
1607
1608bool PGOProfiler::AddTransitionObjectInfo(ProfileType recordType,
1609                                          EntityId methodId,
1610                                          int32_t bcOffset,
1611                                          JSHClass* receiver,
1612                                          JSHClass* hold,
1613                                          JSHClass* holdTra,
1614                                          PGOSampleType accessorMethod)
1615{
1616    auto receiverRootType = FindRootProfileType(receiver);
1617    if (!receiverRootType.IsRootType()) {
1618        return false;
1619    }
1620
1621    auto holdRootType = FindRootProfileType(hold);
1622    if (!holdRootType.IsRootType()) {
1623        return true;
1624    }
1625
1626    auto receiverType = GetOrInsertProfileType(receiver, receiverRootType);
1627    auto holdType = GetOrInsertProfileType(hold, holdRootType);
1628    auto holdTraType = GetOrInsertProfileType(holdTra, holdRootType);
1629
1630    if (receiver != hold) {
1631        UpdateLayout(receiver);
1632    }
1633
1634    if (holdType == holdTraType) {
1635        UpdateLayout(hold);
1636    } else {
1637        UpdateTransitionLayout(hold, holdTra);
1638    }
1639
1640    PGOObjectInfo info(receiverRootType, receiverType, holdRootType, holdType, holdRootType, holdTraType,
1641                       accessorMethod);
1642    UpdatePrototypeChainInfo(receiver, hold, info);
1643    recordInfos_->AddObjectInfo(recordType, methodId, bcOffset, info);
1644    return true;
1645}
1646
1647bool PGOProfiler::AddObjectInfo(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset,
1648                                JSHClass *receiver, JSHClass *hold, JSHClass *holdTra, uint32_t accessorMethodId)
1649{
1650    PGOSampleType accessor = PGOSampleType::CreateProfileType(abcId, accessorMethodId, ProfileType::Kind::MethodId);
1651    ProfileType recordType = GetRecordProfileType(abcId, recordName);
1652    return AddTransitionObjectInfo(recordType, methodId, bcOffset, receiver, hold, holdTra, accessor);
1653}
1654
1655void PGOProfiler::UpdatePrototypeChainInfo(JSHClass *receiver, JSHClass *holder, PGOObjectInfo &info)
1656{
1657    if (receiver == holder) {
1658        return;
1659    }
1660
1661    std::vector<std::pair<ProfileType, ProfileType>> protoChain;
1662    JSTaggedValue proto = JSHClass::FindProtoHClass(receiver);
1663    while (proto.IsJSHClass()) {
1664        auto protoHClass = JSHClass::Cast(proto.GetTaggedObject());
1665        if (protoHClass == holder) {
1666            break;
1667        }
1668        auto protoRootType = FindRootProfileType(protoHClass);
1669        if (!protoRootType.IsRootType()) {
1670            break;
1671        }
1672        auto protoType = GetOrInsertProfileType(protoHClass, protoRootType);
1673        protoChain.emplace_back(protoRootType, protoType);
1674        proto = JSHClass::FindProtoHClass(protoHClass);
1675    }
1676    if (!protoChain.empty()) {
1677        info.AddPrototypePt(protoChain);
1678    }
1679}
1680
1681void PGOProfiler::AddObjectInfoWithMega(
1682    ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset)
1683{
1684    auto megaType = ProfileType::CreateMegaType();
1685    PGOObjectInfo info(megaType, megaType, megaType, megaType, megaType, megaType, PGOSampleType());
1686    ProfileType recordType = GetRecordProfileType(abcId, recordName);
1687    recordInfos_->AddObjectInfo(recordType, methodId, bcOffset, info);
1688}
1689
1690bool PGOProfiler::AddBuiltinsInfoByNameInInstance(ApEntityId abcId, const CString &recordName, EntityId methodId,
1691    int32_t bcOffset, JSHClass *receiver)
1692{
1693    auto thread = vm_->GetJSThread();
1694    auto type = receiver->GetObjectType();
1695    const auto &ctorEntries = thread->GetCtorHclassEntries();
1696    auto entry = ctorEntries.find(receiver);
1697    if (entry != ctorEntries.end()) {
1698        AddBuiltinsGlobalInfo(abcId, recordName, methodId, bcOffset, entry->second);
1699        return true;
1700    }
1701
1702    auto builtinsId = ToBuiltinsTypeId(type);
1703    if (!builtinsId.has_value()) {
1704        return false;
1705    }
1706    JSHClass *exceptRecvHClass = nullptr;
1707    if (builtinsId == BuiltinTypeId::ARRAY) {
1708        bool receiverIsPrototype = receiver->IsPrototype();
1709        exceptRecvHClass = thread->GetArrayInstanceHClass(receiver->GetElementsKind(), receiverIsPrototype);
1710    } else if (builtinsId == BuiltinTypeId::STRING) {
1711        exceptRecvHClass = receiver;
1712    } else {
1713        exceptRecvHClass = thread->GetBuiltinInstanceHClass(builtinsId.value());
1714    }
1715
1716    if (exceptRecvHClass != receiver) {
1717        // When JSType cannot uniquely identify builtins object, it is necessary to
1718        // query the receiver on the global constants.
1719        if (builtinsId == BuiltinTypeId::OBJECT) {
1720            exceptRecvHClass = JSHClass::Cast(thread->GlobalConstants()->GetIteratorResultClass().GetTaggedObject());
1721            if (exceptRecvHClass == receiver) {
1722                GlobalIndex globalsId;
1723                globalsId.UpdateGlobalConstId(static_cast<size_t>(ConstantIndex::ITERATOR_RESULT_CLASS));
1724                AddBuiltinsGlobalInfo(abcId, recordName, methodId, bcOffset, globalsId);
1725                return true;
1726            }
1727        }
1728        return false;
1729    }
1730
1731    return AddBuiltinsInfo(abcId, recordName, methodId, bcOffset, receiver, receiver);
1732}
1733
1734bool PGOProfiler::AddBuiltinsInfoByNameInProt(ApEntityId abcId, const CString &recordName, EntityId methodId,
1735    int32_t bcOffset, JSHClass *receiver, JSHClass *hold)
1736{
1737    auto type = receiver->GetObjectType();
1738    auto builtinsId = ToBuiltinsTypeId(type);
1739    if (!builtinsId.has_value()) {
1740        return false;
1741    }
1742    auto thread = vm_->GetJSThread();
1743    JSHClass *exceptRecvHClass = nullptr;
1744    if (builtinsId == BuiltinTypeId::ARRAY) {
1745        bool receiverIsPrototype = receiver->IsPrototype();
1746        exceptRecvHClass = thread->GetArrayInstanceHClass(receiver->GetElementsKind(), receiverIsPrototype);
1747    } else if (builtinsId == BuiltinTypeId::STRING) {
1748        exceptRecvHClass = receiver;
1749    } else {
1750        exceptRecvHClass = thread->GetBuiltinInstanceHClass(builtinsId.value());
1751    }
1752
1753    auto exceptHoldHClass = thread->GetBuiltinPrototypeHClass(builtinsId.value());
1754    auto exceptPrototypeOfPrototypeHClass =
1755        thread->GetBuiltinPrototypeOfPrototypeHClass(builtinsId.value());
1756    // iterator needs to find two layers of prototype
1757    if (builtinsId == BuiltinTypeId::ARRAY_ITERATOR) {
1758        if ((exceptRecvHClass != receiver) ||
1759            (exceptHoldHClass != hold && exceptPrototypeOfPrototypeHClass != hold)) {
1760            return false;
1761        }
1762    } else if (IsTypedArrayType(builtinsId.value())) {
1763        auto exceptRecvHClassOnHeap = thread->GetBuiltinExtraHClass(builtinsId.value());
1764        ASSERT_PRINT(exceptRecvHClassOnHeap == nullptr || exceptRecvHClassOnHeap->IsOnHeapFromBitField(),
1765                     "must be on heap");
1766        if (IsJSHClassNotEqual(receiver, hold, exceptRecvHClass, exceptRecvHClassOnHeap,
1767                               exceptHoldHClass, exceptPrototypeOfPrototypeHClass)) {
1768            return false;
1769        }
1770    } else if (exceptRecvHClass != receiver || exceptHoldHClass != hold) {
1771        return false;
1772    }
1773
1774    return AddBuiltinsInfo(abcId, recordName, methodId, bcOffset, receiver, receiver);
1775}
1776
1777bool PGOProfiler::IsJSHClassNotEqual(JSHClass *receiver, JSHClass *hold, JSHClass *exceptRecvHClass,
1778                                     JSHClass *exceptRecvHClassOnHeap, JSHClass *exceptHoldHClass,
1779                                     JSHClass *exceptPrototypeOfPrototypeHClass)
1780{
1781    //exceptRecvHClass = IHC, exceptRecvHClassOnHeap = IHC OnHeap
1782    //exceptHoldHClass = PHC, exceptPrototypeOfPrototypeHClass = HClass of X.prototype.prototype
1783    return ((exceptRecvHClass != receiver && exceptRecvHClassOnHeap != receiver) ||
1784            (exceptHoldHClass != hold && exceptPrototypeOfPrototypeHClass != hold));
1785}
1786
1787bool PGOProfiler::CheckProtoChangeMarker(JSTaggedValue cellValue) const
1788{
1789    if (!cellValue.IsProtoChangeMarker()) {
1790        return true;
1791    }
1792    ProtoChangeMarker *cell = ProtoChangeMarker::Cast(cellValue.GetTaggedObject());
1793    return cell->GetHasChanged();
1794}
1795
1796void PGOProfiler::AddBuiltinsGlobalInfo(ApEntityId abcId, const CString &recordName, EntityId methodId,
1797                                        int32_t bcOffset, GlobalIndex globalsId)
1798{
1799    ProfileType recordType = GetRecordProfileType(abcId, recordName);
1800    PGOObjectInfo info(ProfileType::CreateGlobals(abcId, globalsId));
1801    recordInfos_->AddObjectInfo(recordType, methodId, bcOffset, info);
1802}
1803
1804bool PGOProfiler::AddBuiltinsInfo(
1805    ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset, JSHClass *receiver,
1806    JSHClass *transitionHClass, OnHeapMode onHeap, bool everOutOfBounds)
1807{
1808    ProfileType recordType = GetRecordProfileType(abcId, recordName);
1809    if (receiver->IsJSArray()) {
1810        auto type = receiver->GetObjectType();
1811        auto elementsKind = receiver->GetElementsKind();
1812        auto transitionElementsKind = transitionHClass->GetElementsKind();
1813        auto profileType = ProfileType::CreateBuiltinsArray(abcId, type, elementsKind, transitionElementsKind,
1814                                                            everOutOfBounds);
1815        PGOObjectInfo info(profileType);
1816        recordInfos_->AddObjectInfo(recordType, methodId, bcOffset, info);
1817    } else if (receiver->IsTypedArray()) {
1818        JSType jsType = receiver->GetObjectType();
1819        auto profileType = ProfileType::CreateBuiltinsTypedArray(abcId, jsType, onHeap, everOutOfBounds);
1820        PGOObjectInfo info(profileType);
1821        recordInfos_->AddObjectInfo(recordType, methodId, bcOffset, info);
1822    } else {
1823        auto type = receiver->GetObjectType();
1824        PGOObjectInfo info(ProfileType::CreateBuiltins(abcId, type));
1825        recordInfos_->AddObjectInfo(recordType, methodId, bcOffset, info);
1826    }
1827    return true;
1828}
1829
1830bool PGOProfiler::IsRecoredTransRootType(ProfileType type)
1831{
1832    if (!type.IsRootType() || !type.IsTransitionType()) {
1833        return false;
1834    }
1835    if (std::find(recordedTransRootType_.begin(), recordedTransRootType_.end(), type) != recordedTransRootType_.end()) {
1836        LOG_ECMA(DEBUG) << "forbide to add more than 1 hclass for a root type!";
1837        return true;
1838    }
1839    recordedTransRootType_.emplace_back(type);
1840    return false;
1841}
1842
1843void PGOProfiler::SetRootProfileType(JSHClass *root, ApEntityId abcId, uint32_t type, ProfileType::Kind kind)
1844{
1845    ProfileType traceType(root->GetProfileType());
1846    if (traceType.IsNone()) {
1847        traceType = ProfileType(abcId, type, kind, true);
1848        if (IsRecoredTransRootType(traceType)) {
1849            return;
1850        }
1851        root->SetProfileType(traceType.GetRaw());
1852    }
1853}
1854
1855ProfileType PGOProfiler::FindRootProfileType(JSHClass *hclass)
1856{
1857    auto rootHClass = JSHClass::FindRootHClass(hclass);
1858    return GetProfileType(rootHClass, true);
1859}
1860
1861ProfileType PGOProfiler::GetOrInsertProfileType(JSHClass *child, ProfileType rootType)
1862{
1863    ProfileType childType = GetProfileType(child);
1864    if (childType.IsNone()) {
1865        ASSERT(rootType.IsRootType());
1866        childType = PGOTypeGenerator::GenerateProfileType(JSTaggedType(child), rootType);
1867        child->SetProfileType(childType.GetRaw());
1868    }
1869    return childType;
1870}
1871
1872ProfileType PGOProfiler::GetProfileType(JSHClass *hclass, bool check)
1873{
1874    auto result = ProfileType(hclass->GetProfileType());
1875    if (check) {
1876        if (IsSkippableObjectTypeSafe(result)) {
1877            result = ProfileType::PROFILE_TYPE_NONE;
1878        }
1879    }
1880    return result;
1881}
1882
1883void PGOProfiler::ProcessReferences(const WeakRootVisitor &visitor)
1884{
1885    if (!isEnable_) {
1886        return;
1887    }
1888    preDumpWorkList_.Iterate([this, &visitor](WorkNode *node) {
1889        auto object = reinterpret_cast<TaggedObject *>(node->GetValue());
1890        auto fwd = visitor(object);
1891        if (fwd == nullptr) {
1892            preDumpWorkList_.Remove(node);
1893            nativeAreaAllocator_->Delete(node);
1894            return;
1895        }
1896        if (fwd != object) {
1897            node->SetValue(JSTaggedType(fwd));
1898        }
1899    });
1900}
1901
1902void PGOProfiler::Iterate(const RootVisitor &visitor)
1903{
1904    if (!isEnable_) {
1905        return;
1906    }
1907    // If the IC of the method is stable, the current design forces the dump data.
1908    // Must pause dump during GC.
1909    dumpWorkList_.Iterate([&visitor](WorkNode* node) {
1910        visitor(Root::ROOT_VM, ObjectSlot(node->GetValueAddr()));
1911    });
1912}
1913
1914PGOProfiler::PGOProfiler(EcmaVM* vm, bool isEnable)
1915    : nativeAreaAllocator_(std::make_unique<NativeAreaAllocator>()), vm_(vm), isEnable_(isEnable)
1916{
1917    if (isEnable_) {
1918        recordInfos_ = std::make_unique<PGORecordDetailInfos>(0);
1919    }
1920};
1921
1922PGOProfiler::~PGOProfiler()
1923{
1924    Reset(false);
1925}
1926
1927void PGOProfiler::Reset(bool isEnable)
1928{
1929    LockHolder lock(recordInfoMutex_);
1930    isEnable_ = isEnable;
1931    methodCount_ = 0;
1932    if (recordInfos_) {
1933        recordInfos_->Clear();
1934    } else {
1935        if (isEnable_) {
1936            recordInfos_ = std::make_unique<PGORecordDetailInfos>(0);
1937        }
1938    }
1939}
1940
1941ApEntityId PGOProfiler::GetMethodAbcId(JSTaggedValue jsMethod)
1942{
1943    ASSERT(jsMethod.IsMethod());
1944    CString pfName;
1945
1946    const auto *pf = Method::Cast(jsMethod)->GetJSPandaFile();
1947    if (pf != nullptr) {
1948        pfName = pf->GetJSPandaFileDesc();
1949    }
1950    ApEntityId abcId(0);
1951    if (!PGOProfilerManager::GetInstance()->GetPandaFileId(pfName, abcId) && !pfName.empty()) {
1952        LOG_ECMA(ERROR) << "Get method abc id failed. abcName: " << pfName;
1953    }
1954    return abcId;
1955}
1956ApEntityId PGOProfiler::GetMethodAbcId(JSFunction *jsFunction)
1957{
1958    CString pfName;
1959    auto jsMethod = jsFunction->GetMethod();
1960    if (jsMethod.IsMethod()) {
1961        return GetMethodAbcId(jsMethod);
1962    }
1963    LOG_ECMA(ERROR) << "Get method abc id failed. Not a method.";
1964    UNREACHABLE();
1965}
1966
1967ProfileType PGOProfiler::GetRecordProfileType(JSFunction *jsFunction, const CString &recordName)
1968{
1969    CString pfName;
1970    auto jsMethod = jsFunction->GetMethod();
1971    if (jsMethod.IsMethod()) {
1972        const auto *pf = Method::Cast(jsMethod)->GetJSPandaFile();
1973        if (pf != nullptr) {
1974            pfName = pf->GetJSPandaFileDesc();
1975        }
1976    }
1977    const auto &pf = JSPandaFileManager::GetInstance()->FindJSPandaFile(pfName);
1978    if (pf == nullptr) {
1979        LOG_ECMA(ERROR) << "Get record profile type failed. pf is null, pfName: " << pfName
1980                        << ", recordName: " << recordName;
1981        return ProfileType::PROFILE_TYPE_NONE;
1982    }
1983    return GetRecordProfileType(pf, GetMethodAbcId(jsFunction), recordName);
1984}
1985
1986ProfileType PGOProfiler::GetRecordProfileType(ApEntityId abcId, const CString &recordName)
1987{
1988    CString pfDesc;
1989    PGOProfilerManager::GetInstance()->GetPandaFileDesc(abcId, pfDesc);
1990    const auto &pf = JSPandaFileManager::GetInstance()->FindJSPandaFile(pfDesc);
1991    if (pf == nullptr) {
1992        LOG_ECMA(ERROR) << "Get record profile type failed. pf is null, pfDesc: " << pfDesc
1993                        << ", recordName: " << recordName;
1994        return ProfileType::PROFILE_TYPE_NONE;
1995    }
1996    return GetRecordProfileType(pf, abcId, recordName);
1997}
1998
1999ProfileType PGOProfiler::GetRecordProfileType(const std::shared_ptr<JSPandaFile> &pf, ApEntityId abcId,
2000                                              const CString &recordName)
2001{
2002    ASSERT(pf != nullptr);
2003    JSRecordInfo *recordInfo = nullptr;
2004    bool hasRecord = pf->CheckAndGetRecordInfo(recordName, &recordInfo);
2005    if (!hasRecord) {
2006        LOG_ECMA(ERROR) << "Get recordInfo failed. recordName: " << recordName;
2007        return ProfileType::PROFILE_TYPE_NONE;
2008    }
2009    ProfileType recordType {0};
2010    if (pf->IsBundlePack()) {
2011        recordType = CreateRecordProfileType(abcId, ProfileType::RECORD_ID_FOR_BUNDLE);
2012        recordInfos_->GetRecordPool()->Add(recordType, recordName);
2013        return recordType;
2014    }
2015    if (recordInfo->classId != JSPandaFile::CLASSID_OFFSET_NOT_FOUND) {
2016        recordType = CreateRecordProfileType(abcId, recordInfo->classId);
2017        recordInfos_->GetRecordPool()->Add(recordType, recordName);
2018        return recordType;
2019    }
2020    LOG_ECMA(ERROR) << "Invalid classId, skip it. recordName: " << recordName << ", isCjs: " << recordInfo->isCjs
2021                    << ", isJson: " << recordInfo->isJson;
2022    return ProfileType::PROFILE_TYPE_NONE;
2023}
2024
2025void PGOProfiler::WorkList::PushBack(WorkNode *node)
2026{
2027    if (node == nullptr) {
2028        LOG_ECMA(FATAL) << "PGOProfiler::WorkList::PushBack:node is nullptr";
2029        UNREACHABLE();
2030    }
2031    if (last_ == nullptr) {
2032        first_ = node;
2033        last_ = node;
2034    } else {
2035        last_->SetNext(node);
2036        node->SetPrev(last_);
2037        last_ = node;
2038    }
2039    node->SetWorkList(this);
2040}
2041
2042PGOProfiler::WorkNode *PGOProfiler::WorkList::PopFront()
2043{
2044    WorkNode *result = nullptr;
2045    if (first_ != nullptr) {
2046        result = first_;
2047        if (first_->GetNext() != nullptr) {
2048            first_ = first_->GetNext();
2049            first_->SetPrev(nullptr);
2050        } else {
2051            first_ = nullptr;
2052            last_ = nullptr;
2053        }
2054        result->SetNext(nullptr);
2055        result->SetWorkList(nullptr);
2056    }
2057    return result;
2058}
2059
2060void PGOProfiler::WorkList::Remove(WorkNode *node)
2061{
2062    if (node->GetPrev() != nullptr) {
2063        node->GetPrev()->SetNext(node->GetNext());
2064    }
2065    if (node->GetNext() != nullptr) {
2066        node->GetNext()->SetPrev(node->GetPrev());
2067    }
2068    if (node == first_) {
2069        first_ = node->GetNext();
2070    }
2071    if (node == last_) {
2072        last_ = node->GetPrev();
2073    }
2074    node->SetPrev(nullptr);
2075    node->SetNext(nullptr);
2076    node->SetWorkList(nullptr);
2077}
2078
2079void PGOProfiler::WorkList::Iterate(Callback callback) const
2080{
2081    auto current = first_;
2082    while (current != nullptr) {
2083        auto next = current->GetNext();
2084        callback(current);
2085        current = next;
2086    }
2087}
2088
2089ProfileType PGOProfiler::CreateRecordProfileType(ApEntityId abcId, ApEntityId classId)
2090{
2091    return {abcId, classId, ProfileType::Kind::RecordClassId};
2092}
2093
2094JSTaggedValue PGOProfiler::TryFindKeyInPrototypeChain(TaggedObject *currObj, JSHClass *currHC, JSTaggedValue key)
2095{
2096    // This is a temporary solution for Instanceof Only!
2097    // Do NOT use this function for other purpose.
2098    if (currHC->IsDictionaryMode()) {
2099        return JSTaggedValue(currHC);
2100    }
2101    while (!JSTaggedValue(currHC).IsUndefinedOrNull()) {
2102        if (LIKELY(!currHC->IsDictionaryMode())) {
2103            int entry = JSHClass::FindPropertyEntry(vm_->GetJSThread(), currHC, key);
2104            if (entry != -1) {
2105                return JSTaggedValue(currHC);
2106            }
2107        } else {
2108            TaggedArray *array = TaggedArray::Cast(JSObject::Cast(currObj)->GetProperties().GetTaggedObject());
2109            ASSERT(array->IsDictionaryMode());
2110            NameDictionary *dict = NameDictionary::Cast(array);
2111            int entry = dict->FindEntry(key);
2112            if (entry != -1) {
2113                return JSTaggedValue(currHC);
2114            }
2115        }
2116        currObj = currHC->GetProto().GetTaggedObject();
2117        if (JSTaggedValue(currObj).IsUndefinedOrNull()) {
2118            break;
2119        }
2120        currHC = currObj->GetClass();
2121    }
2122    return JSTaggedValue::Undefined();
2123}
2124void PGOProfiler::InitJITProfiler()
2125{
2126    jitProfiler_ = new JITProfiler(vm_);
2127    jitProfiler_->InitJITProfiler();
2128}
2129
2130} // namespace panda::ecmascript::pgo
2131