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