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