1/*
2 * Copyright (c) 2024 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#include "ecmascript/jit/jit_profiler.h"
16
17#include <chrono>
18#include <cstdint>
19#include <memory>
20
21#include "ecmascript/compiler/jit_compilation_env.h"
22#include "ecmascript/compiler/pgo_type/pgo_type_manager.h"
23#include "ecmascript/enum_conversion.h"
24#include "ecmascript/interpreter/interpreter-inl.h"
25
26namespace panda::ecmascript {
27using namespace pgo;
28JITProfiler::JITProfiler(EcmaVM *vm) : vm_(vm)
29{
30}
31
32void JITProfiler::ProfileBytecode(JSThread *thread, const JSHandle<ProfileTypeInfo> &profileTypeInfo,
33                                  ProfileTypeInfo *rawProfileTypeInfo,
34                                  EntityId methodId, ApEntityId abcId, const uint8_t *pcStart, uint32_t codeSize,
35                                  [[maybe_unused]]const panda_file::File::Header *header, bool useRawProfileTypeInfo)
36{
37    Clear();
38    if (useRawProfileTypeInfo) {
39        profileTypeInfo_ = rawProfileTypeInfo;
40    }
41    abcId_ = abcId;
42    methodId_ = methodId;
43    BytecodeInstruction bcIns(pcStart);
44    auto bcInsLast = bcIns.JumpTo(codeSize);
45
46    while (bcIns.GetAddress() != bcInsLast.GetAddress()) {
47        auto opcode = bcIns.GetOpcode();
48        auto bcOffset = bcIns.GetAddress() - pcStart;
49        auto pc = bcIns.GetAddress();
50        switch (opcode) {
51            case EcmaOpcode::LDTHISBYNAME_IMM8_ID16:
52            case EcmaOpcode::LDOBJBYNAME_IMM8_ID16: {
53                Jit::JitLockHolder lock(thread);
54                if (!useRawProfileTypeInfo) {
55                    profileTypeInfo_ = *profileTypeInfo;
56                }
57                uint8_t slotId = READ_INST_8_0();
58                CHECK_SLOTID_BREAK(slotId);
59                ConvertICByName(bcOffset, slotId, BCType::LOAD);
60                break;
61            }
62            case EcmaOpcode::LDTHISBYNAME_IMM16_ID16:
63            case EcmaOpcode::LDOBJBYNAME_IMM16_ID16: {
64                Jit::JitLockHolder lock(thread);
65                if (!useRawProfileTypeInfo) {
66                    profileTypeInfo_ = *profileTypeInfo;
67                }
68                uint16_t slotId = READ_INST_16_0();
69                ConvertICByName(bcOffset, slotId, BCType::LOAD);
70                break;
71            }
72            case EcmaOpcode::LDOBJBYVALUE_IMM8_V8:
73            case EcmaOpcode::LDTHISBYVALUE_IMM8: {
74                Jit::JitLockHolder lock(thread);
75                if (!useRawProfileTypeInfo) {
76                    profileTypeInfo_ = *profileTypeInfo;
77                }
78                uint8_t slotId = READ_INST_8_0();
79                CHECK_SLOTID_BREAK(slotId);
80                ConvertICByValue(bcOffset, slotId, BCType::LOAD);
81                break;
82            }
83            case EcmaOpcode::LDOBJBYVALUE_IMM16_V8:
84            case EcmaOpcode::LDTHISBYVALUE_IMM16: {
85                Jit::JitLockHolder lock(thread);
86                if (!useRawProfileTypeInfo) {
87                    profileTypeInfo_ = *profileTypeInfo;
88                }
89                uint16_t slotId = READ_INST_16_0();
90                ConvertICByValue(bcOffset, slotId, BCType::LOAD);
91                break;
92            }
93            case EcmaOpcode::STOBJBYNAME_IMM8_ID16_V8:
94            case EcmaOpcode::STTHISBYNAME_IMM8_ID16:
95            case EcmaOpcode::DEFINEPROPERTYBYNAME_IMM8_ID16_V8:
96            case EcmaOpcode::STPRIVATEPROPERTY_IMM8_IMM16_IMM16_V8: {
97                Jit::JitLockHolder lock(thread);
98                if (!useRawProfileTypeInfo) {
99                    profileTypeInfo_ = *profileTypeInfo;
100                }
101                uint8_t slotId = READ_INST_8_0();
102                CHECK_SLOTID_BREAK(slotId);
103                ConvertICByName(bcOffset, slotId, BCType::STORE);
104                break;
105            }
106            case EcmaOpcode::STOBJBYNAME_IMM16_ID16_V8:
107            case EcmaOpcode::STTHISBYNAME_IMM16_ID16: {
108                Jit::JitLockHolder lock(thread);
109                if (!useRawProfileTypeInfo) {
110                    profileTypeInfo_ = *profileTypeInfo;
111                }
112                uint16_t slotId = READ_INST_16_0();
113                ConvertICByName(bcOffset, slotId, BCType::STORE);
114                break;
115            }
116            case EcmaOpcode::STOBJBYVALUE_IMM8_V8_V8:
117            case EcmaOpcode::STOWNBYINDEX_IMM8_V8_IMM16:
118            case EcmaOpcode::STTHISBYVALUE_IMM8_V8: {
119                Jit::JitLockHolder lock(thread);
120                if (!useRawProfileTypeInfo) {
121                    profileTypeInfo_ = *profileTypeInfo;
122                }
123                uint8_t slotId = READ_INST_8_0();
124                CHECK_SLOTID_BREAK(slotId);
125                ConvertICByValue(bcOffset, slotId, BCType::STORE);
126                break;
127            }
128            case EcmaOpcode::STOBJBYVALUE_IMM16_V8_V8:
129            case EcmaOpcode::STOWNBYINDEX_IMM16_V8_IMM16:
130            case EcmaOpcode::STTHISBYVALUE_IMM16_V8: {
131                Jit::JitLockHolder lock(thread);
132                if (!useRawProfileTypeInfo) {
133                    profileTypeInfo_ = *profileTypeInfo;
134                }
135                uint16_t slotId = READ_INST_16_0();
136                ConvertICByValue(bcOffset, slotId, BCType::STORE);
137                break;
138            }
139            // Op
140            case EcmaOpcode::ADD2_IMM8_V8:
141            case EcmaOpcode::SUB2_IMM8_V8:
142            case EcmaOpcode::MUL2_IMM8_V8:
143            case EcmaOpcode::DIV2_IMM8_V8:
144            case EcmaOpcode::MOD2_IMM8_V8:
145            case EcmaOpcode::SHL2_IMM8_V8:
146            case EcmaOpcode::SHR2_IMM8_V8:
147            case EcmaOpcode::AND2_IMM8_V8:
148            case EcmaOpcode::OR2_IMM8_V8:
149            case EcmaOpcode::XOR2_IMM8_V8:
150            case EcmaOpcode::ASHR2_IMM8_V8:
151            case EcmaOpcode::EXP_IMM8_V8:
152            case EcmaOpcode::NEG_IMM8:
153            case EcmaOpcode::NOT_IMM8:
154            case EcmaOpcode::INC_IMM8:
155            case EcmaOpcode::DEC_IMM8:
156            case EcmaOpcode::EQ_IMM8_V8:
157            case EcmaOpcode::NOTEQ_IMM8_V8:
158            case EcmaOpcode::LESS_IMM8_V8:
159            case EcmaOpcode::LESSEQ_IMM8_V8:
160            case EcmaOpcode::GREATER_IMM8_V8:
161            case EcmaOpcode::GREATEREQ_IMM8_V8:
162            case EcmaOpcode::STRICTNOTEQ_IMM8_V8:
163            case EcmaOpcode::STRICTEQ_IMM8_V8:
164            case EcmaOpcode::TONUMERIC_IMM8: {
165                Jit::JitLockHolder lock(thread);
166                if (!useRawProfileTypeInfo) {
167                    profileTypeInfo_ = *profileTypeInfo;
168                }
169                uint8_t slotId = READ_INST_8_0();
170                CHECK_SLOTID_BREAK(slotId);
171                ConvertOpType(slotId, bcOffset);
172                break;
173            }
174            // Call
175            case EcmaOpcode::CALLARG0_IMM8:
176            case EcmaOpcode::CALLARG1_IMM8_V8:
177            case EcmaOpcode::CALLARGS2_IMM8_V8_V8:
178            case EcmaOpcode::CALLARGS3_IMM8_V8_V8_V8:
179            case EcmaOpcode::CALLRANGE_IMM8_IMM8_V8:
180            case EcmaOpcode::CALLTHIS0_IMM8_V8:
181            case EcmaOpcode::CALLTHIS1_IMM8_V8_V8:
182            case EcmaOpcode::CALLTHIS2_IMM8_V8_V8_V8:
183            case EcmaOpcode::CALLTHIS3_IMM8_V8_V8_V8_V8:
184            case EcmaOpcode::CALLTHISRANGE_IMM8_IMM8_V8: {
185                Jit::JitLockHolder lock(thread);
186                if (!useRawProfileTypeInfo) {
187                    profileTypeInfo_ = *profileTypeInfo;
188                }
189                uint8_t slotId = READ_INST_8_0();
190                CHECK_SLOTID_BREAK(slotId);
191                ConvertCall(slotId, bcOffset);
192                break;
193            }
194            case EcmaOpcode::CALLRUNTIME_CALLINIT_PREF_IMM8_V8: {
195                Jit::JitLockHolder lock(thread);
196                if (!useRawProfileTypeInfo) {
197                    profileTypeInfo_ = *profileTypeInfo;
198                }
199                uint8_t slotId = READ_INST_8_1();
200                CHECK_SLOTID_BREAK(slotId);
201                ConvertCall(slotId, bcOffset);
202                break;
203            }
204            case EcmaOpcode::WIDE_CALLRANGE_PREF_IMM16_V8:
205            case EcmaOpcode::WIDE_CALLTHISRANGE_PREF_IMM16_V8: {
206                // no ic slot
207                break;
208            }
209            case EcmaOpcode::NEWOBJRANGE_IMM8_IMM8_V8: {
210                Jit::JitLockHolder lock(thread);
211                if (!useRawProfileTypeInfo) {
212                    profileTypeInfo_ = *profileTypeInfo;
213                }
214                uint8_t slotId = READ_INST_8_0();
215                CHECK_SLOTID_BREAK(slotId);
216                ConvertNewObjRange(slotId, bcOffset);
217                break;
218            }
219            case EcmaOpcode::NEWOBJRANGE_IMM16_IMM8_V8: {
220                Jit::JitLockHolder lock(thread);
221                if (!useRawProfileTypeInfo) {
222                    profileTypeInfo_ = *profileTypeInfo;
223                }
224                uint16_t slotId = READ_INST_16_0();
225                ConvertNewObjRange(slotId, bcOffset);
226                break;
227            }
228            case EcmaOpcode::WIDE_NEWOBJRANGE_PREF_IMM16_V8: {
229                break;
230            }
231            // Create object
232            case EcmaOpcode::DEFINECLASSWITHBUFFER_IMM8_ID16_ID16_IMM16_V8: {
233                uint8_t slotId = READ_INST_8_0();
234                CHECK_SLOTID_BREAK(slotId);
235                (void) slotId;
236                break;
237            }
238            case EcmaOpcode::DEFINECLASSWITHBUFFER_IMM16_ID16_ID16_IMM16_V8: {
239                uint16_t slotId = READ_INST_16_0();
240                (void) slotId;
241                break;
242            }
243            case EcmaOpcode::DEFINEFUNC_IMM8_ID16_IMM8: {
244                uint8_t slotId = READ_INST_8_0();
245                CHECK_SLOTID_BREAK(slotId);
246                break;
247            }
248            case EcmaOpcode::DEFINEFUNC_IMM16_ID16_IMM8: {
249                uint16_t slotId = READ_INST_16_0();
250                (void) slotId;
251                break;
252            }
253            case EcmaOpcode::CREATEOBJECTWITHBUFFER_IMM8_ID16:
254            case EcmaOpcode::CREATEARRAYWITHBUFFER_IMM8_ID16:
255            case EcmaOpcode::CREATEEMPTYARRAY_IMM8: {
256                Jit::JitLockHolder lock(thread);
257                if (!useRawProfileTypeInfo) {
258                    profileTypeInfo_ = *profileTypeInfo;
259                }
260                auto traceId =
261                    static_cast<int32_t>(reinterpret_cast<uintptr_t>(pc) - reinterpret_cast<uintptr_t>(header));
262                uint8_t slotId = READ_INST_8_0();
263                CHECK_SLOTID_BREAK(slotId);
264                ConvertCreateObject(slotId, bcOffset, traceId);
265                break;
266            }
267            case EcmaOpcode::CREATEOBJECTWITHBUFFER_IMM16_ID16:
268            case EcmaOpcode::CREATEARRAYWITHBUFFER_IMM16_ID16:
269            case EcmaOpcode::CREATEEMPTYARRAY_IMM16: {
270                Jit::JitLockHolder lock(thread);
271                if (!useRawProfileTypeInfo) {
272                    profileTypeInfo_ = *profileTypeInfo;
273                }
274                auto traceId =
275                    static_cast<int32_t>(reinterpret_cast<uintptr_t>(pc) - reinterpret_cast<uintptr_t>(header));
276                uint16_t slotId = READ_INST_16_0();
277                ConvertCreateObject(slotId, bcOffset, traceId);
278                break;
279            }
280            case EcmaOpcode::GETITERATOR_IMM8: {
281                Jit::JitLockHolder lock(thread);
282                if (!useRawProfileTypeInfo) {
283                    profileTypeInfo_ = *profileTypeInfo;
284                }
285                uint8_t slotId = READ_INST_8_0();
286                CHECK_SLOTID_BREAK(slotId);
287                ConvertGetIterator(slotId, bcOffset);
288                break;
289            }
290            case EcmaOpcode::GETITERATOR_IMM16: {
291                Jit::JitLockHolder lock(thread);
292                if (!useRawProfileTypeInfo) {
293                    profileTypeInfo_ = *profileTypeInfo;
294                }
295                uint16_t slotId = READ_INST_16_0();
296                ConvertGetIterator(slotId, bcOffset);
297                break;
298            }
299            // Others
300            case EcmaOpcode::INSTANCEOF_IMM8_V8: {
301                Jit::JitLockHolder lock(thread);
302                if (!useRawProfileTypeInfo) {
303                    profileTypeInfo_ = *profileTypeInfo;
304                }
305                uint8_t slotId = READ_INST_8_0();
306                CHECK_SLOTID_BREAK(slotId);
307                ConvertInstanceof(bcOffset, slotId);
308                break;
309            }
310            case EcmaOpcode::DEFINEGETTERSETTERBYVALUE_V8_V8_V8_V8:
311            default:
312                break;
313        }
314        bcIns = bcIns.GetNext();
315    }
316}
317
318// PGOSampleType
319void JITProfiler::ConvertOpType(uint32_t slotId, long bcOffset)
320{
321    JSTaggedValue slotValue = profileTypeInfo_->Get(slotId);
322    if (slotValue.IsInt()) {
323        auto type = slotValue.GetInt();
324        UpdatePGOType(bcOffset, chunk_->New<PGOSampleType>(type));
325    }
326}
327
328void JITProfiler::ConvertCall(uint32_t slotId, long bcOffset)
329{
330    JSTaggedValue slotValue = profileTypeInfo_->Get(slotId);
331    ProfileType::Kind kind;
332    int calleeMethodId = 0;
333    ApEntityId calleeAbcId = 0;
334    if (slotValue.IsInt()) {
335        calleeMethodId = slotValue.GetInt();
336        if (calleeMethodId == 0) {
337            return;
338        }
339        calleeAbcId = abcId_;
340        ASSERT(calleeMethodId <= 0);
341        kind = ProfileType::Kind::BuiltinFunctionId;
342    }  else if (slotValue.IsJSFunction()) {
343        JSFunction *callee = JSFunction::Cast(slotValue);
344        Method *calleeMethod = Method::Cast(callee->GetMethod());
345        calleeMethodId = static_cast<int>(calleeMethod->GetMethodId().GetOffset());
346        calleeAbcId = PGOProfiler::GetMethodAbcId(callee);
347        static_cast<JitCompilationEnv *>(compilationEnv_)
348            ->UpdateFuncSlotIdMap(calleeMethodId, methodId_.GetOffset(), slotId);
349        kind = ProfileType::Kind::MethodId;
350    } else {
351        return;
352    }
353    PGOSampleType* type = chunk_->New<PGOSampleType>(ProfileType(abcId_, std::abs(calleeMethodId), kind));
354    UpdatePGOType(bcOffset, type);
355}
356
357void JITProfiler::ConvertNewObjRange(uint32_t slotId, long bcOffset)
358{
359    JSTaggedValue slotValue = profileTypeInfo_->Get(slotId);
360    int ctorMethodId = 0;
361    JSHClass* hclass = nullptr;
362    if (slotValue.IsInt()) {
363        ctorMethodId = slotValue.GetInt();
364        // JIT cannot optimize this scenario because it doesn't know the hclass
365        if (ctorMethodId > 0) {
366            return;
367        }
368    } else if (slotValue.IsJSFunction()) {
369        JSFunction *callee = JSFunction::Cast(slotValue);
370        Method *calleeMethod = Method::Cast(callee->GetMethod());
371        ctorMethodId = static_cast<int>(calleeMethod->GetMethodId().GetOffset());
372        JSTaggedValue protoOrHClass = callee->GetProtoOrHClass();
373        if (protoOrHClass.IsJSHClass()) {
374            hclass = JSHClass::Cast(protoOrHClass.GetTaggedObject());
375        } else {
376            return;
377        }
378    } else {
379        return;
380    }
381    if (ctorMethodId > 0) {
382        ptManager_->RecordAndGetHclassIndexForJIT(hclass);
383        auto pt = ProfileType(abcId_, std::abs(ctorMethodId), ProfileType::Kind::JITClassId, true);
384        PGODefineOpType* type = chunk_->New<PGODefineOpType>(pt, hclass);
385        UpdatePGOType(bcOffset, type);
386    } else {
387        auto kind = ProfileType::Kind::BuiltinFunctionId;
388        auto type = chunk_->New<PGOSampleType>(ProfileType(abcId_, std::abs(ctorMethodId), kind));
389        UpdatePGOType(bcOffset, type);
390    }
391}
392
393void JITProfiler::ConvertGetIterator(uint32_t slotId, long bcOffset)
394{
395    if (vm_->GetJSThread()->GetEnableLazyBuiltins()) {
396        return;
397    }
398    JSTaggedValue value = profileTypeInfo_->Get(slotId);
399    if (!value.IsInt()) {
400        return;
401    }
402    int iterKind = value.GetInt();
403    ASSERT(iterKind <= 0);
404    ProfileType::Kind pgoKind = ProfileType::Kind::BuiltinFunctionId;
405    auto type = chunk_->New<PGOSampleType>(ProfileType(abcId_, std::abs(iterKind), pgoKind));
406    UpdatePGOType(bcOffset, type);
407}
408
409void JITProfiler::ConvertCreateObject(uint32_t slotId, long bcOffset, [[maybe_unused]]int32_t traceId)
410{
411    JSTaggedValue slotValue = profileTypeInfo_->Get(slotId);
412    if (!slotValue.IsHeapObject()) {
413        return;
414    }
415    if (slotValue.IsWeak()) {
416        auto object = slotValue.GetWeakReferentUnChecked();
417        if (object->GetClass()->IsHClass()) {
418            auto newHClass = JSHClass::Cast(object);
419            PGODefineOpType* objDefType = chunk_->New<PGODefineOpType>(ProfileType::CreateJITType(), newHClass);
420            ptManager_->RecordAndGetHclassIndexForJIT(newHClass);
421            UpdatePGOType(bcOffset, objDefType);
422        }
423    } else if (slotValue.IsTrackInfoObject()) {
424        TrackInfo *trackInfo = TrackInfo::Cast(slotValue.GetTaggedObject());
425        auto hclass = JSHClass::Cast(trackInfo->GetCachedHClass().GetTaggedObject());
426        PGODefineOpType* objDefType = chunk_->New<PGODefineOpType>(ProfileType::CreateJITType(), hclass);
427        ptManager_->RecordAndGetHclassIndexForJIT(hclass);
428        auto elementsKind = trackInfo->GetElementsKind();
429        objDefType->SetElementsKind(elementsKind);
430        objDefType->SetElementsLength(trackInfo->GetArrayLength());
431        objDefType->SetSpaceFlag(trackInfo->GetSpaceFlag());
432        UpdatePGOType(bcOffset, objDefType);
433    }
434}
435
436void JITProfiler::ConvertICByName(int32_t bcOffset, uint32_t slotId, BCType type)
437{
438    ProfileTypeAccessorLockScope accessorLockScope(vm_->GetJSThreadNoCheck());
439    JSTaggedValue firstValue = profileTypeInfo_->Get(slotId);
440    if (!firstValue.IsHeapObject()) {
441        if (firstValue.IsHole()) {
442            // Mega state
443            AddObjectInfoWithMega(bcOffset);
444        }
445        return;
446    }
447    if (firstValue.IsWeak()) {
448        TaggedObject *object = firstValue.GetWeakReferentUnChecked();
449        if (object->GetClass()->IsHClass()) {
450            JSTaggedValue secondValue = profileTypeInfo_->Get(slotId + 1);
451            JSHClass *hclass = JSHClass::Cast(object);
452            ConvertICByNameWithHandler(abcId_, bcOffset, hclass, secondValue, type, slotId + 1);
453        }
454        return;
455    }
456    ConvertICByNameWithPoly(abcId_, bcOffset, firstValue, type, slotId);
457}
458
459void JITProfiler::ConvertICByNameWithHandler(ApEntityId abcId, int32_t bcOffset,
460                                             JSHClass *hclass,
461                                             JSTaggedValue secondValue, BCType type, uint32_t slotId)
462{
463    if (type == BCType::LOAD) {
464        HandleLoadType(abcId, bcOffset, hclass, secondValue, slotId);
465        // LoadGlobal
466        return;
467    }
468    HandleOtherTypes(abcId, bcOffset, hclass, secondValue, slotId);
469}
470
471void JITProfiler::HandleLoadType(ApEntityId &abcId, int32_t &bcOffset,
472                                 JSHClass *hclass, JSTaggedValue &secondValue, uint32_t slotId)
473{
474    if (secondValue.IsInt()) {
475        HandleLoadTypeInt(abcId, bcOffset, hclass, secondValue);
476    } else if (secondValue.IsPrototypeHandler()) {
477        HandleLoadTypePrototypeHandler(abcId, bcOffset, hclass, secondValue, slotId);
478    }
479}
480
481void JITProfiler::HandleLoadTypeInt(ApEntityId &abcId, int32_t &bcOffset,
482                                    JSHClass *hclass, JSTaggedValue &secondValue)
483{
484    auto handlerInfo = static_cast<uint32_t>(secondValue.GetInt());
485    if (HandlerBase::IsNonExist(handlerInfo)) {
486        return;
487    }
488    if (AddBuiltinsInfoByNameInInstance(abcId, bcOffset, hclass)) {
489        return;
490    }
491    if (HandlerBase::IsField(handlerInfo) || HandlerBase::IsAccessor(handlerInfo)) {
492        AddObjectInfo(abcId, bcOffset, hclass, hclass, hclass);
493    }
494}
495
496void JITProfiler::HandleLoadTypePrototypeHandler(ApEntityId &abcId, int32_t &bcOffset,
497                                                 JSHClass *hclass, JSTaggedValue &secondValue, uint32_t slotId)
498{
499    auto prototypeHandler = PrototypeHandler::Cast(secondValue.GetTaggedObject());
500    auto cellValue = prototypeHandler->GetProtoCell();
501    if (cellValue.IsUndefined()) {
502        return;
503    }
504    ProtoChangeMarker *cell = ProtoChangeMarker::Cast(cellValue.GetTaggedObject());
505    if (cell->GetHasChanged()) {
506        return;
507    }
508    auto holder = prototypeHandler->GetHolder();
509    auto holderHClass = holder.GetTaggedObject()->GetClass();
510    JSTaggedValue handlerInfoVal = prototypeHandler->GetHandlerInfo();
511    if (!handlerInfoVal.IsInt()) {
512        return;
513    }
514    auto handlerInfo = static_cast<uint32_t>(handlerInfoVal.GetInt());
515    if (HandlerBase::IsNonExist(handlerInfo)) {
516        return;
517    }
518    auto accessorMethodId = prototypeHandler->GetAccessorMethodId();
519    auto accessor = prototypeHandler->GetAccessorJSFunction();
520    if (accessor.IsJSFunction()) {
521        auto accessorFunction = JSFunction::Cast(accessor);
522        auto methodId = Method::Cast(accessorFunction->GetMethod())->GetMethodId().GetOffset();
523        ASSERT(accessorMethodId == methodId);
524        accessorMethodId = methodId;
525        static_cast<JitCompilationEnv *>(compilationEnv_)
526            ->UpdateFuncSlotIdMap(accessorMethodId, methodId_.GetOffset(), slotId);
527    }
528    if (AddBuiltinsInfoByNameInProt(abcId, bcOffset, hclass, holderHClass)) {
529        return ;
530    }
531    AddObjectInfo(abcId, bcOffset, hclass, holderHClass, holderHClass, accessorMethodId);
532}
533
534void JITProfiler::HandleOtherTypes(ApEntityId &abcId, int32_t &bcOffset,
535                                   JSHClass *hclass, JSTaggedValue &secondValue, uint32_t slotId)
536{
537    if (secondValue.IsInt()) {
538        AddObjectInfo(abcId, bcOffset, hclass, hclass, hclass);
539    } else if (secondValue.IsTransitionHandler()) {
540        HandleTransitionHandler(abcId, bcOffset, hclass, secondValue);
541    } else if (secondValue.IsTransWithProtoHandler()) {
542        HandleTransWithProtoHandler(abcId, bcOffset, hclass, secondValue);
543    } else if (secondValue.IsPrototypeHandler()) {
544        HandleOtherTypesPrototypeHandler(abcId, bcOffset, hclass, secondValue, slotId);
545    } else if (secondValue.IsPropertyBox()) {
546        // StoreGlobal
547    } else if (secondValue.IsStoreTSHandler()) {
548        HandleStoreTSHandler(abcId, bcOffset, hclass, secondValue);
549    }
550}
551
552void JITProfiler::HandleTransitionHandler(ApEntityId &abcId, int32_t &bcOffset,
553                                          JSHClass *hclass, JSTaggedValue &secondValue)
554{
555    auto transitionHandler = TransitionHandler::Cast(secondValue.GetTaggedObject());
556    auto transitionHClassVal = transitionHandler->GetTransitionHClass();
557    if (transitionHClassVal.IsJSHClass()) {
558        auto transitionHClass = JSHClass::Cast(transitionHClassVal.GetTaggedObject());
559        AddObjectInfo(abcId, bcOffset, hclass, hclass, transitionHClass);
560    }
561}
562
563void JITProfiler::HandleTransWithProtoHandler(ApEntityId &abcId, int32_t &bcOffset,
564                                              JSHClass *hclass, JSTaggedValue &secondValue)
565{
566    auto transWithProtoHandler = TransWithProtoHandler::Cast(secondValue.GetTaggedObject());
567    auto cellValue = transWithProtoHandler->GetProtoCell();
568    ASSERT(cellValue.IsProtoChangeMarker());
569    ProtoChangeMarker *cell = ProtoChangeMarker::Cast(cellValue.GetTaggedObject());
570    if (cell->GetHasChanged()) {
571        return;
572    }
573    auto transitionHClassVal = transWithProtoHandler->GetTransitionHClass();
574    if (transitionHClassVal.IsJSHClass()) {
575        auto transitionHClass = JSHClass::Cast(transitionHClassVal.GetTaggedObject());
576        AddObjectInfo(abcId, bcOffset, hclass, hclass, transitionHClass);
577    }
578}
579
580void JITProfiler::HandleOtherTypesPrototypeHandler(ApEntityId &abcId, int32_t &bcOffset,
581                                                   JSHClass *hclass, JSTaggedValue &secondValue, uint32_t slotId)
582{
583    auto prototypeHandler = PrototypeHandler::Cast(secondValue.GetTaggedObject());
584    auto cellValue = prototypeHandler->GetProtoCell();
585    if (cellValue.IsUndefined()) {
586        return;
587    }
588    ProtoChangeMarker *cell = ProtoChangeMarker::Cast(cellValue.GetTaggedObject());
589    if (cell->GetHasChanged()) {
590        return;
591    }
592    auto holder = prototypeHandler->GetHolder();
593    auto holderHClass = holder.GetTaggedObject()->GetClass();
594    auto accessorMethodId = prototypeHandler->GetAccessorMethodId();
595    auto accessor = prototypeHandler->GetAccessorJSFunction();
596    if (accessor.IsJSFunction()) {
597        auto accessorFunction = JSFunction::Cast(accessor);
598        auto methodId = Method::Cast(accessorFunction->GetMethod())->GetMethodId().GetOffset();
599        ASSERT(accessorMethodId == methodId);
600        accessorMethodId = methodId;
601        static_cast<JitCompilationEnv *>(compilationEnv_)
602            ->UpdateFuncSlotIdMap(accessorMethodId, methodId_.GetOffset(), slotId);
603    }
604    AddObjectInfo(abcId, bcOffset, hclass, holderHClass, holderHClass, accessorMethodId);
605}
606
607void JITProfiler::HandleStoreTSHandler(ApEntityId &abcId, int32_t &bcOffset,
608                                       JSHClass *hclass, JSTaggedValue &secondValue)
609{
610    StoreTSHandler *storeTSHandler = StoreTSHandler::Cast(secondValue.GetTaggedObject());
611    auto cellValue = storeTSHandler->GetProtoCell();
612    ASSERT(cellValue.IsProtoChangeMarker());
613    ProtoChangeMarker *cell = ProtoChangeMarker::Cast(cellValue.GetTaggedObject());
614    if (cell->GetHasChanged()) {
615        return;
616    }
617    auto holder = storeTSHandler->GetHolder();
618    auto holderHClass = holder.GetTaggedObject()->GetClass();
619    AddObjectInfo(abcId, bcOffset, hclass, holderHClass, holderHClass);
620}
621
622void JITProfiler::ConvertICByNameWithPoly(ApEntityId abcId, int32_t bcOffset, JSTaggedValue cacheValue, BCType type,
623                                          uint32_t slotId)
624{
625    if (cacheValue.IsWeak()) {
626        return;
627    }
628    ASSERT(cacheValue.IsTaggedArray());
629    auto array = TaggedArray::Cast(cacheValue);
630    uint32_t length = array->GetLength();
631    for (uint32_t i = 0; i < length; i += 2) { // 2 means one ic, two slot
632        auto result = array->Get(i);
633        auto handler = array->Get(i + 1);
634        if (!result.IsHeapObject() || !result.IsWeak()) {
635            continue;
636        }
637        TaggedObject *object = result.GetWeakReferentUnChecked();
638        if (!object->GetClass()->IsHClass()) {
639            continue;
640        }
641        JSHClass *hclass = JSHClass::Cast(object);
642        ConvertICByNameWithHandler(abcId, bcOffset, hclass, handler, type, slotId);
643    }
644}
645
646void JITProfiler::ConvertICByValue(int32_t bcOffset, uint32_t slotId, BCType type)
647{
648    ProfileTypeAccessorLockScope accessorLockScope(vm_->GetJSThreadNoCheck());
649    JSTaggedValue firstValue = profileTypeInfo_->Get(slotId);
650    if (!firstValue.IsHeapObject()) {
651        if (firstValue.IsHole()) {
652            // Mega state
653            AddObjectInfoWithMega(bcOffset);
654        }
655        return;
656    }
657    if (firstValue.IsWeak()) {
658        TaggedObject *object = firstValue.GetWeakReferentUnChecked();
659        if (object->GetClass()->IsHClass()) {
660            JSTaggedValue secondValue = profileTypeInfo_->Get(slotId + 1);
661            JSHClass *hclass = JSHClass::Cast(object);
662            ConvertICByValueWithHandler(abcId_, bcOffset, hclass, secondValue, type);
663        }
664        return;
665    }
666    // Check key
667    if ((firstValue.IsString() || firstValue.IsSymbol())) {
668        return;
669    }
670    // Check without key
671    ConvertICByValueWithPoly(abcId_, bcOffset, firstValue, type);
672}
673
674void JITProfiler::ConvertICByValueWithHandler(ApEntityId abcId, int32_t bcOffset,
675                                              JSHClass *hclass, JSTaggedValue secondValue,
676                                              BCType type)
677{
678    if (type == BCType::LOAD) {
679        if (secondValue.IsInt()) {
680            auto handlerInfo = static_cast<uint32_t>(secondValue.GetInt());
681            if (HandlerBase::IsNormalElement(handlerInfo) || HandlerBase::IsStringElement(handlerInfo)) {
682                if (HandlerBase::NeedSkipInPGODump(handlerInfo)) {
683                    return;
684                }
685                AddBuiltinsInfo(abcId, bcOffset, hclass, hclass);
686                return;
687            }
688            if (HandlerBase::IsTypedArrayElement(handlerInfo)) {
689                OnHeapMode onHeap =  HandlerBase::IsOnHeap(handlerInfo) ? OnHeapMode::ON_HEAP : OnHeapMode::NOT_ON_HEAP;
690                AddBuiltinsInfo(abcId, bcOffset, hclass, hclass, onHeap);
691                return;
692            }
693            AddObjectInfo(abcId, bcOffset, hclass, hclass, hclass);
694        }
695        return;
696    }
697    HandleStoreType(abcId, bcOffset, hclass, secondValue);
698}
699
700void JITProfiler::HandleStoreType(ApEntityId &abcId, int32_t &bcOffset,
701                                  JSHClass *hclass, JSTaggedValue &secondValue)
702{
703    if (secondValue.IsInt()) {
704        auto handlerInfo = static_cast<uint32_t>(secondValue.GetInt());
705        if (HandlerBase::IsNormalElement(handlerInfo) || HandlerBase::IsStringElement(handlerInfo)) {
706            AddBuiltinsInfo(abcId, bcOffset, hclass, hclass,
707                            OnHeapMode::NONE, HandlerBase::IsStoreOutOfBounds(handlerInfo));
708            return;
709        }
710        if (HandlerBase::IsTypedArrayElement(handlerInfo)) {
711            OnHeapMode onHeap = HandlerBase::IsOnHeap(handlerInfo) ? OnHeapMode::ON_HEAP : OnHeapMode::NOT_ON_HEAP;
712            AddBuiltinsInfo(abcId,  bcOffset, hclass, hclass, onHeap,
713                            HandlerBase::IsStoreOutOfBounds(handlerInfo));
714            return;
715        }
716        AddObjectInfo(abcId, bcOffset, hclass, hclass, hclass);
717    } else if (secondValue.IsTransitionHandler()) {
718        HandleTransition(abcId, bcOffset, hclass, secondValue);
719    } else if (secondValue.IsTransWithProtoHandler()) {
720        HandleTransWithProto(abcId, bcOffset, hclass, secondValue);
721    } else {
722        HandlePrototypeHandler(abcId, bcOffset, hclass, secondValue);
723    }
724}
725
726void JITProfiler::HandleTransition(ApEntityId &abcId, int32_t &bcOffset,
727                                   JSHClass *hclass, JSTaggedValue &secondValue)
728{
729    auto transitionHandler = TransitionHandler::Cast(secondValue.GetTaggedObject());
730    auto transitionHClassVal = transitionHandler->GetTransitionHClass();
731
732    auto handlerInfoValue = transitionHandler->GetHandlerInfo();
733    ASSERT(handlerInfoValue.IsInt());
734    auto handlerInfo = static_cast<uint32_t>(handlerInfoValue.GetInt());
735    if (transitionHClassVal.IsJSHClass()) {
736        auto transitionHClass = JSHClass::Cast(transitionHClassVal.GetTaggedObject());
737        if (HandlerBase::IsElement(handlerInfo)) {
738            AddBuiltinsInfo(abcId, bcOffset, hclass, transitionHClass,
739                            OnHeapMode::NONE, HandlerBase::IsStoreOutOfBounds(handlerInfo));
740        } else {
741            AddObjectInfo(abcId, bcOffset, hclass, hclass, transitionHClass);
742        }
743    }
744}
745
746void JITProfiler::HandleTransWithProto(ApEntityId &abcId, int32_t &bcOffset,
747                                       JSHClass *hclass, JSTaggedValue &secondValue)
748{
749    auto transWithProtoHandler = TransWithProtoHandler::Cast(secondValue.GetTaggedObject());
750    auto transitionHClassVal = transWithProtoHandler->GetTransitionHClass();
751    auto handlerInfoValue = transWithProtoHandler->GetHandlerInfo();
752    ASSERT(handlerInfoValue.IsInt());
753    auto handlerInfo = static_cast<uint32_t>(handlerInfoValue.GetInt());
754    if (transitionHClassVal.IsJSHClass()) {
755        auto transitionHClass = JSHClass::Cast(transitionHClassVal.GetTaggedObject());
756        if (HandlerBase::IsElement(handlerInfo)) {
757            AddBuiltinsInfo(abcId, bcOffset, hclass, transitionHClass,
758                            OnHeapMode::NONE, HandlerBase::IsStoreOutOfBounds(handlerInfo));
759        } else {
760            AddObjectInfo(abcId, bcOffset, hclass, hclass, transitionHClass);
761        }
762    }
763}
764
765void JITProfiler::HandlePrototypeHandler(ApEntityId &abcId, int32_t &bcOffset,
766                                         JSHClass *hclass, JSTaggedValue &secondValue)
767{
768    ASSERT(secondValue.IsPrototypeHandler());
769    PrototypeHandler *prototypeHandler = PrototypeHandler::Cast(secondValue.GetTaggedObject());
770    auto cellValue = prototypeHandler->GetProtoCell();
771    if (!cellValue.IsProtoChangeMarker()) {
772        return;
773    }
774    ASSERT(cellValue.IsProtoChangeMarker());
775    ProtoChangeMarker *cell = ProtoChangeMarker::Cast(cellValue.GetTaggedObject());
776    if (cell->GetHasChanged()) {
777        return;
778    }
779    JSTaggedValue handlerInfoValue = prototypeHandler->GetHandlerInfo();
780    ASSERT(handlerInfoValue.IsInt());
781    auto handlerInfo = static_cast<uint32_t>(handlerInfoValue.GetInt());
782    if (HandlerBase::IsElement(handlerInfo)) {
783        AddBuiltinsInfo(abcId, bcOffset, hclass, hclass,
784                        OnHeapMode::NONE, HandlerBase::IsStoreOutOfBounds(handlerInfo));
785        return;
786    }
787    auto holder = prototypeHandler->GetHolder();
788    auto holderHClass = holder.GetTaggedObject()->GetClass();
789    AddObjectInfo(abcId, bcOffset, hclass, holderHClass, holderHClass);
790}
791
792void JITProfiler::ConvertICByValueWithPoly(ApEntityId abcId, int32_t bcOffset, JSTaggedValue cacheValue, BCType type)
793{
794    if (cacheValue.IsWeak()) {
795        return;
796    }
797    ASSERT(cacheValue.IsTaggedArray());
798    auto array = TaggedArray::Cast(cacheValue);
799    uint32_t length = array->GetLength();
800    for (uint32_t i = 0; i < length; i += 2) { // 2 means one ic, two slot
801        auto result = array->Get(i);
802        auto handler = array->Get(i + 1);
803        if (!result.IsHeapObject() || !result.IsWeak()) {
804            continue;
805        }
806        TaggedObject *object = result.GetWeakReferentUnChecked();
807        if (!object->GetClass()->IsHClass()) {
808            continue;
809        }
810        JSHClass *hclass = JSHClass::Cast(object);
811        ConvertICByValueWithHandler(abcId, bcOffset, hclass, handler, type);
812    }
813}
814
815void JITProfiler::ConvertInstanceof(int32_t bcOffset, uint32_t slotId)
816{
817    JSTaggedValue firstValue = profileTypeInfo_->Get(slotId);
818    if (!firstValue.IsHeapObject()) {
819        if (firstValue.IsHole()) {
820            // Mega state
821            AddObjectInfoWithMega(bcOffset);
822        }
823        return;
824    }
825    if (firstValue.IsWeak()) {
826        TaggedObject *object = firstValue.GetWeakReferentUnChecked();
827        if (object->GetClass()->IsHClass()) {
828            JSHClass *hclass = JSHClass::Cast(object);
829            // Since pgo does not support symbol, we choose to return if hclass having @@hasInstance
830            JSHandle<GlobalEnv> env = vm_->GetGlobalEnv();
831            JSTaggedValue key = env->GetHasInstanceSymbol().GetTaggedValue();
832            JSHClass *functionPrototypeHC = JSObject::Cast(env->GetFunctionPrototype().GetTaggedValue())->GetClass();
833            JSTaggedValue foundHClass = TryFindKeyInPrototypeChain(object, hclass, key);
834            if (!foundHClass.IsUndefined() && JSHClass::Cast(foundHClass.GetTaggedObject()) != functionPrototypeHC) {
835                return;
836            }
837            AddObjectInfo(abcId_, bcOffset, hclass, hclass, hclass);
838        }
839        return;
840    }
841    // Poly Not Consider now
842    return;
843}
844
845JSTaggedValue JITProfiler::TryFindKeyInPrototypeChain(TaggedObject *currObj, JSHClass *currHC, JSTaggedValue key)
846{
847    // This is a temporary solution for Instanceof Only!
848    // Do NOT use this function for other purpose.
849    if (currHC->IsDictionaryMode()) {
850        return JSTaggedValue(currHC);
851    }
852    while (!JSTaggedValue(currHC).IsUndefinedOrNull()) {
853        if (LIKELY(!currHC->IsDictionaryMode())) {
854            int entry = JSHClass::FindPropertyEntry(vm_->GetJSThread(), currHC, key);
855            if (entry != -1) {
856                return JSTaggedValue(currHC);
857            }
858        } else {
859            TaggedArray *array = TaggedArray::Cast(JSObject::Cast(currObj)->GetProperties().GetTaggedObject());
860            ASSERT(array->IsDictionaryMode());
861            NameDictionary *dict = NameDictionary::Cast(array);
862            int entry = dict->FindEntry(key);
863            if (entry != -1) {
864                return JSTaggedValue(currHC);
865            }
866        }
867        currObj = currHC->GetProto().GetTaggedObject();
868        if (JSTaggedValue(currObj).IsUndefinedOrNull()) {
869            break;
870        }
871        currHC = currObj->GetClass();
872    }
873    return JSTaggedValue::Undefined();
874}
875
876void JITProfiler::AddObjectInfoWithMega(int32_t bcOffset)
877{
878    auto megaType = ProfileType::CreateMegaType();
879    PGOObjectInfo info(megaType, megaType, megaType, megaType, megaType, megaType, PGOSampleType());
880    AddObjectInfoImplement(bcOffset, info);
881}
882
883void JITProfiler::AddObjectInfoImplement(int32_t bcOffset, const PGOObjectInfo &info)
884{
885    PGORWOpType *cur = nullptr;
886    if (bcOffsetPGORwTypeMap_.find(bcOffset) == bcOffsetPGORwTypeMap_.end()) {
887        cur = chunk_->New<PGORWOpType>();
888        bcOffsetPGORwTypeMap_[bcOffset] = cur;
889    } else {
890        cur = const_cast<PGORWOpType*>(bcOffsetPGORwTypeMap_.at(bcOffset));
891    }
892    if (cur != nullptr) {
893        cur->AddObjectInfo(info);
894    }
895}
896
897bool JITProfiler::AddObjectInfo(ApEntityId abcId, int32_t bcOffset,
898                                JSHClass *receiver, JSHClass *hold, JSHClass *holdTra, uint32_t accessorMethodId)
899{
900    PGOSampleType accessor = PGOSampleType::CreateProfileType(abcId, accessorMethodId, ProfileType::Kind::MethodId);
901    // case: obj = Object.create(null) => LowerProtoChangeMarkerCheck Crash
902    if (receiver->GetPrototype().IsNull()) {
903        return false;
904    }
905    return AddTranstionObjectInfo(bcOffset, receiver, hold, holdTra, accessor);
906}
907
908bool JITProfiler::AddTranstionObjectInfo(
909    int32_t bcOffset, JSHClass *receiver, JSHClass *hold, JSHClass *holdTra, PGOSampleType accessorMethod)
910{
911    ptManager_->RecordAndGetHclassIndexForJIT(receiver);
912    ptManager_->RecordAndGetHclassIndexForJIT(hold);
913    ptManager_->RecordAndGetHclassIndexForJIT(holdTra);
914    PGOObjectInfo info(ProfileType::CreateJITType(), receiver, hold, holdTra, accessorMethod);
915    AddObjectInfoImplement(bcOffset, info);
916    return true;
917}
918
919void JITProfiler::AddBuiltinsInfo(ApEntityId abcId, int32_t bcOffset, JSHClass *receiver,
920    JSHClass *transitionHClass, OnHeapMode onHeap, bool everOutOfBounds)
921{
922    if (receiver->IsJSArray()) {
923        auto type = receiver->GetObjectType();
924        auto elementsKind = receiver->GetElementsKind();
925        auto transitionElementsKind = transitionHClass->GetElementsKind();
926        auto profileType = ProfileType::CreateBuiltinsArray(abcId, type, elementsKind, transitionElementsKind,
927                                                            everOutOfBounds);
928        PGOObjectInfo info(profileType);
929        AddObjectInfoImplement(bcOffset, info);
930    } else if (receiver->IsTypedArray()) {
931        JSType jsType = receiver->GetObjectType();
932        auto profileType = ProfileType::CreateBuiltinsTypedArray(abcId, jsType, onHeap, everOutOfBounds);
933        PGOObjectInfo info(profileType);
934        AddObjectInfoImplement(bcOffset, info);
935    } else {
936        auto type = receiver->GetObjectType();
937        PGOObjectInfo info(ProfileType::CreateBuiltins(abcId, type));
938        AddObjectInfoImplement(bcOffset, info);
939    }
940}
941
942void JITProfiler::AddBuiltinsGlobalInfo(ApEntityId abcId, int32_t bcOffset, GlobalIndex globalsId)
943{
944    PGOObjectInfo info(ProfileType::CreateGlobals(abcId, globalsId));
945    AddObjectInfoImplement(bcOffset, info);
946}
947
948bool JITProfiler::AddBuiltinsInfoByNameInInstance(ApEntityId abcId, int32_t bcOffset, JSHClass *receiver)
949{
950    auto thread = vm_->GetJSThread();
951    auto type = receiver->GetObjectType();
952    const auto &ctorEntries = thread->GetCtorHclassEntries();
953    auto entry = ctorEntries.find(receiver);
954    if (entry != ctorEntries.end()) {
955        AddBuiltinsGlobalInfo(abcId, bcOffset, entry->second);
956        return true;
957    }
958
959    auto builtinsId = ToBuiltinsTypeId(type);
960    if (!builtinsId.has_value()) {
961        return false;
962    }
963    JSHClass *exceptRecvHClass = nullptr;
964    if (builtinsId == BuiltinTypeId::ARRAY) {
965        bool receiverIsPrototype = receiver->IsPrototype();
966        exceptRecvHClass = thread->GetArrayInstanceHClass(receiver->GetElementsKind(), receiverIsPrototype);
967    } else if (builtinsId == BuiltinTypeId::STRING) {
968        exceptRecvHClass = receiver;
969    } else {
970        exceptRecvHClass = thread->GetBuiltinInstanceHClass(builtinsId.value());
971    }
972
973    if (exceptRecvHClass != receiver) {
974        // When JSType cannot uniquely identify builtins object, it is necessary to
975        // query the receiver on the global constants.
976        if (builtinsId == BuiltinTypeId::OBJECT) {
977            exceptRecvHClass = JSHClass::Cast(thread->GlobalConstants()->GetIteratorResultClass().GetTaggedObject());
978            if (exceptRecvHClass == receiver) {
979                GlobalIndex globalsId;
980                globalsId.UpdateGlobalConstId(static_cast<size_t>(ConstantIndex::ITERATOR_RESULT_CLASS));
981                AddBuiltinsGlobalInfo(abcId, bcOffset, globalsId);
982                return true;
983            }
984            return false;
985        }
986        return true;
987    }
988    AddBuiltinsInfo(abcId, bcOffset, receiver, receiver);
989    return true;
990}
991
992bool JITProfiler::AddBuiltinsInfoByNameInProt(ApEntityId abcId, int32_t bcOffset, JSHClass *receiver, JSHClass *hold)
993{
994    auto type = receiver->GetObjectType();
995    auto builtinsId = ToBuiltinsTypeId(type);
996    if (!builtinsId.has_value()) {
997        return false;
998    }
999    auto thread = vm_->GetJSThread();
1000    JSHClass *exceptRecvHClass = nullptr;
1001    if (builtinsId == BuiltinTypeId::ARRAY) {
1002        bool receiverIsPrototype = receiver->IsPrototype();
1003        exceptRecvHClass = thread->GetArrayInstanceHClass(receiver->GetElementsKind(), receiverIsPrototype);
1004    } else if (builtinsId == BuiltinTypeId::STRING) {
1005        exceptRecvHClass = receiver;
1006    } else {
1007        exceptRecvHClass = thread->GetBuiltinInstanceHClass(builtinsId.value());
1008    }
1009
1010    auto exceptHoldHClass = thread->GetBuiltinPrototypeHClass(builtinsId.value());
1011    auto exceptPrototypeOfPrototypeHClass =
1012        thread->GetBuiltinPrototypeOfPrototypeHClass(builtinsId.value());
1013    // iterator needs to find two layers of prototype
1014    if (builtinsId == BuiltinTypeId::ARRAY_ITERATOR) {
1015        if ((exceptRecvHClass != receiver) ||
1016            (exceptHoldHClass != hold && exceptPrototypeOfPrototypeHClass != hold)) {
1017            return true;
1018        }
1019    } else if (IsTypedArrayType(builtinsId.value())) {
1020        auto exceptRecvHClassOnHeap = thread->GetBuiltinExtraHClass(builtinsId.value());
1021        ASSERT_PRINT(exceptRecvHClassOnHeap == nullptr || exceptRecvHClassOnHeap->IsOnHeapFromBitField(),
1022                     "must be on heap");
1023        if (JITProfiler::IsJSHClassNotEqual(receiver, hold, exceptRecvHClass, exceptRecvHClassOnHeap, exceptHoldHClass,
1024                                            exceptPrototypeOfPrototypeHClass)) {
1025            return true;
1026        }
1027    } else if (exceptRecvHClass != receiver || exceptHoldHClass != hold) {
1028        if (builtinsId == BuiltinTypeId::OBJECT) {
1029            return false;
1030        } else {
1031            return true;
1032        }
1033    }
1034    AddBuiltinsInfo(abcId, bcOffset, receiver, receiver);
1035    return true;
1036}
1037
1038bool JITProfiler::IsJSHClassNotEqual(JSHClass *receiver, JSHClass *hold, JSHClass *exceptRecvHClass,
1039                                     JSHClass *exceptRecvHClassOnHeap, JSHClass *exceptHoldHClass,
1040                                     JSHClass *exceptPrototypeOfPrototypeHClass)
1041{
1042    //exceptRecvHClass = IHC, exceptRecvHClassOnHeap = IHC OnHeap
1043    //exceptHoldHClass = PHC, exceptPrototypeOfPrototypeHClass = HClass of X.prototype.prototype
1044    return ((exceptRecvHClass != receiver && exceptRecvHClassOnHeap != receiver) ||
1045            (exceptHoldHClass != hold && exceptPrototypeOfPrototypeHClass != hold));
1046}
1047
1048void JITProfiler::Clear()
1049{
1050    bcOffsetPGOOpTypeMap_.clear();
1051    bcOffsetPGODefOpTypeMap_.clear();
1052    bcOffsetPGORwTypeMap_.clear();
1053    abcId_ = 0;
1054    profileTypeInfo_ = nullptr;
1055    methodId_ = (EntityId)0;
1056}
1057
1058
1059JITProfiler::~JITProfiler()
1060{
1061}
1062}
1063