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