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 
26 namespace panda::ecmascript {
27 using namespace pgo;
JITProfiler(EcmaVM *vm)28 JITProfiler::JITProfiler(EcmaVM *vm) : vm_(vm)
29 {
30 }
31 
ProfileBytecode(JSThread *thread, const JSHandle<ProfileTypeInfo> &profileTypeInfo, ProfileTypeInfo *rawProfileTypeInfo, EntityId methodId, ApEntityId abcId, const uint8_t *pcStart, uint32_t codeSize, [[maybe_unused]]const panda_file::File::Header *header, bool useRawProfileTypeInfo)32 void 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
ConvertOpType(uint32_t slotId, long bcOffset)319 void 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 
ConvertCall(uint32_t slotId, long bcOffset)328 void 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 
ConvertNewObjRange(uint32_t slotId, long bcOffset)357 void 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 
ConvertGetIterator(uint32_t slotId, long bcOffset)393 void 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 
ConvertCreateObject(uint32_t slotId, long bcOffset, [[maybe_unused]]int32_t traceId)409 void 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 
ConvertICByName(int32_t bcOffset, uint32_t slotId, BCType type)436 void 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 
ConvertICByNameWithHandler(ApEntityId abcId, int32_t bcOffset, JSHClass *hclass, JSTaggedValue secondValue, BCType type, uint32_t slotId)459 void 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 
HandleLoadType(ApEntityId &abcId, int32_t &bcOffset, JSHClass *hclass, JSTaggedValue &secondValue, uint32_t slotId)471 void 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 
HandleLoadTypeInt(ApEntityId &abcId, int32_t &bcOffset, JSHClass *hclass, JSTaggedValue &secondValue)481 void 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 
HandleLoadTypePrototypeHandler(ApEntityId &abcId, int32_t &bcOffset, JSHClass *hclass, JSTaggedValue &secondValue, uint32_t slotId)496 void 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 
HandleOtherTypes(ApEntityId &abcId, int32_t &bcOffset, JSHClass *hclass, JSTaggedValue &secondValue, uint32_t slotId)534 void 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 
HandleTransitionHandler(ApEntityId &abcId, int32_t &bcOffset, JSHClass *hclass, JSTaggedValue &secondValue)552 void 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 
HandleTransWithProtoHandler(ApEntityId &abcId, int32_t &bcOffset, JSHClass *hclass, JSTaggedValue &secondValue)563 void 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 
HandleOtherTypesPrototypeHandler(ApEntityId &abcId, int32_t &bcOffset, JSHClass *hclass, JSTaggedValue &secondValue, uint32_t slotId)580 void 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 
HandleStoreTSHandler(ApEntityId &abcId, int32_t &bcOffset, JSHClass *hclass, JSTaggedValue &secondValue)607 void 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 
ConvertICByNameWithPoly(ApEntityId abcId, int32_t bcOffset, JSTaggedValue cacheValue, BCType type, uint32_t slotId)622 void 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 
ConvertICByValue(int32_t bcOffset, uint32_t slotId, BCType type)646 void 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 
ConvertICByValueWithHandler(ApEntityId abcId, int32_t bcOffset, JSHClass *hclass, JSTaggedValue secondValue, BCType type)674 void 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 
HandleStoreType(ApEntityId &abcId, int32_t &bcOffset, JSHClass *hclass, JSTaggedValue &secondValue)700 void 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 
HandleTransition(ApEntityId &abcId, int32_t &bcOffset, JSHClass *hclass, JSTaggedValue &secondValue)726 void 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 
HandleTransWithProto(ApEntityId &abcId, int32_t &bcOffset, JSHClass *hclass, JSTaggedValue &secondValue)746 void 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 
HandlePrototypeHandler(ApEntityId &abcId, int32_t &bcOffset, JSHClass *hclass, JSTaggedValue &secondValue)765 void 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 
ConvertICByValueWithPoly(ApEntityId abcId, int32_t bcOffset, JSTaggedValue cacheValue, BCType type)792 void 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 
ConvertInstanceof(int32_t bcOffset, uint32_t slotId)815 void 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 
TryFindKeyInPrototypeChain(TaggedObject *currObj, JSHClass *currHC, JSTaggedValue key)845 JSTaggedValue 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 
AddObjectInfoWithMega(int32_t bcOffset)876 void 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 
AddObjectInfoImplement(int32_t bcOffset, const PGOObjectInfo &info)883 void 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 
AddObjectInfo(ApEntityId abcId, int32_t bcOffset, JSHClass *receiver, JSHClass *hold, JSHClass *holdTra, uint32_t accessorMethodId)897 bool 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 
AddTranstionObjectInfo( int32_t bcOffset, JSHClass *receiver, JSHClass *hold, JSHClass *holdTra, PGOSampleType accessorMethod)908 bool 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 
AddBuiltinsInfo(ApEntityId abcId, int32_t bcOffset, JSHClass *receiver, JSHClass *transitionHClass, OnHeapMode onHeap, bool everOutOfBounds)919 void 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 
AddBuiltinsGlobalInfo(ApEntityId abcId, int32_t bcOffset, GlobalIndex globalsId)942 void JITProfiler::AddBuiltinsGlobalInfo(ApEntityId abcId, int32_t bcOffset, GlobalIndex globalsId)
943 {
944     PGOObjectInfo info(ProfileType::CreateGlobals(abcId, globalsId));
945     AddObjectInfoImplement(bcOffset, info);
946 }
947 
AddBuiltinsInfoByNameInInstance(ApEntityId abcId, int32_t bcOffset, JSHClass *receiver)948 bool 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 
AddBuiltinsInfoByNameInProt(ApEntityId abcId, int32_t bcOffset, JSHClass *receiver, JSHClass *hold)992 bool 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 
IsJSHClassNotEqual(JSHClass *receiver, JSHClass *hold, JSHClass *exceptRecvHClass, JSHClass *exceptRecvHClassOnHeap, JSHClass *exceptHoldHClass, JSHClass *exceptPrototypeOfPrototypeHClass)1038 bool 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 
Clear()1048 void 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 
~JITProfiler()1059 JITProfiler::~JITProfiler()
1060 {
1061 }
1062 }
1063